diff --git a/backend/globals.js b/backend/globals.js
index 17d69ec..2455ae5 100644
--- a/backend/globals.js
+++ b/backend/globals.js
@@ -1,5 +1,7 @@
// -- Excalidraw settings --
-// @TODO replace with "true" once Preact is integrated to ExcalidrawCanvas
+// @TODO replace with "true" once Preact is integrated into ExcalidrawCanvas
var process = { env: { IS_PREACT: "false" } };
+// @TODO probably remove or update once Preact is integrated into ExcalidrawCanvas
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = { isDisabled: true };
+window.EXCALIDRAW_ASSET_PATH = "/_api/public/excalidraw/";
// -- / --
diff --git a/frontend/typescript/excalidraw_canvas/README.md b/frontend/typescript/excalidraw_canvas/README.md
index 955d111..43b1d4c 100644
--- a/frontend/typescript/excalidraw_canvas/README.md
+++ b/frontend/typescript/excalidraw_canvas/README.md
@@ -13,3 +13,13 @@ Created with commands:
- `npm i -E roughjs @excalidraw/laser-pointer jotai browser-fs-access`
- `npm i -D esbuild typescript`
- `locales/en.json` downloaded from `https://raw.githubusercontent.com/excalidraw/excalidraw/refs/tags/v0.17.6/src/locales/en.json`
+- `excalidraw-assets-dev` and `excalidraw-assets` from `FastWave2.0\frontend\typescript\excalidraw_canvas\node_modules\@excalidraw\excalidraw\dist` copied into `FastWave2.0\public\excalidraw`
+- Lines added to `FastWave2.0\backend\globals.js`:
+ ```js
+ // -- Excalidraw settings --
+ // @TODO replace with "true" once Preact is integrated into ExcalidrawCanvas
+ var process = { env: { IS_PREACT: "false" } };
+ // @TODO probably remove or update once Preact is integrated into ExcalidrawCanvas
+ window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = { isDisabled: true };
+ window.EXCALIDRAW_ASSET_PATH = "/_api/public/excalidraw/";
+ ```
diff --git a/public/excalidraw/excalidraw-assets-dev/Assistant-Bold.woff2 b/public/excalidraw/excalidraw-assets-dev/Assistant-Bold.woff2
new file mode 100644
index 0000000..751ba1c
Binary files /dev/null and b/public/excalidraw/excalidraw-assets-dev/Assistant-Bold.woff2 differ
diff --git a/public/excalidraw/excalidraw-assets-dev/Assistant-Medium.woff2 b/public/excalidraw/excalidraw-assets-dev/Assistant-Medium.woff2
new file mode 100644
index 0000000..d5d809a
Binary files /dev/null and b/public/excalidraw/excalidraw-assets-dev/Assistant-Medium.woff2 differ
diff --git a/public/excalidraw/excalidraw-assets-dev/Assistant-Regular.woff2 b/public/excalidraw/excalidraw-assets-dev/Assistant-Regular.woff2
new file mode 100644
index 0000000..e17d6ec
Binary files /dev/null and b/public/excalidraw/excalidraw-assets-dev/Assistant-Regular.woff2 differ
diff --git a/public/excalidraw/excalidraw-assets-dev/Assistant-SemiBold.woff2 b/public/excalidraw/excalidraw-assets-dev/Assistant-SemiBold.woff2
new file mode 100644
index 0000000..d17aa74
Binary files /dev/null and b/public/excalidraw/excalidraw-assets-dev/Assistant-SemiBold.woff2 differ
diff --git a/public/excalidraw/excalidraw-assets-dev/Cascadia.woff2 b/public/excalidraw/excalidraw-assets-dev/Cascadia.woff2
new file mode 100644
index 0000000..b2eae9f
Binary files /dev/null and b/public/excalidraw/excalidraw-assets-dev/Cascadia.woff2 differ
diff --git a/public/excalidraw/excalidraw-assets-dev/Virgil.woff2 b/public/excalidraw/excalidraw-assets-dev/Virgil.woff2
new file mode 100644
index 0000000..cb22225
Binary files /dev/null and b/public/excalidraw/excalidraw-assets-dev/Virgil.woff2 differ
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/ar-SA-json-f35c4f87e6e2dcf7c20a.js b/public/excalidraw/excalidraw-assets-dev/locales/ar-SA-json-f35c4f87e6e2dcf7c20a.js
new file mode 100644
index 0000000..6f74a2e
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/ar-SA-json-f35c4f87e6e2dcf7c20a.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/ar-SA-json"],{
+
+/***/ "../../locales/ar-SA.json":
+/*!********************************!*\
+ !*** ../../locales/ar-SA.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"لصق","pasteAsPlaintext":"اللصق كنص عادي","pasteCharts":"لصق الرسوم البيانية","selectAll":"تحديد الكل","multiSelect":"إضافة عنصر للتحديد","moveCanvas":"نقل لوح الرسم","cut":"قص","copy":"نسخ","copyAsPng":"نسخ إلى الحافظة بصيغة PNG","copyAsSvg":"نسخ إلى الحافظة بصيغة SVG","copyText":"نسخ إلى الحافظة كنص","bringForward":"جلب للأمام","sendToBack":"أرسل للخلف","bringToFront":"أحضر للأمام","sendBackward":"أرسل للخلف","delete":"حذف","copyStyles":"نسخ الأنماط","pasteStyles":"لصق الأنماط","stroke":"الخط","background":"الخلفية","fill":"التعبئة","strokeWidth":"سُمك الخط","strokeStyle":"نمط الخط","strokeStyle_solid":"متصل","strokeStyle_dashed":"متقطع","strokeStyle_dotted":"منقط","sloppiness":"الإمالة","opacity":"الشفافية","textAlign":"محاذاة النص","edges":"الحواف","sharp":"حادة","round":"دائرية","arrowheads":"رؤوس الأسهم","arrowhead_none":"لا شيء","arrowhead_arrow":"سهم","arrowhead_bar":"شريط","arrowhead_dot":"نقطة","arrowhead_triangle":"مثلث","fontSize":"حجم الخط","fontFamily":"نوع الخط","addWatermark":"إضافة \\"مصنوعة بواسطة Excalidraw\\"","handDrawn":"رسم باليد","normal":"عادي","code":"رمز","small":"صغير","medium":"متوسط","large":"كبير","veryLarge":"كبير جدا","solid":"كامل","hachure":"خطوط","zigzag":"متعرج","crossHatch":"خطوط متقطعة","thin":"نحيف","bold":"داكن","left":"الـيسار","center":"وسط","right":"يمين","extraBold":"عريض","architect":"معماري","artist":"رسام","cartoonist":"كرتوني","fileTitle":"إسم الملف","colorPicker":"منتقي اللون","canvasColors":"تستخدم على القماش","canvasBackground":"خلفية اللوحة","drawingCanvas":"لوحة الرسم","layers":"الطبقات","actions":"الإجراءات","language":"اللغة","liveCollaboration":"التعاون المباشر...","duplicateSelection":"تكرار","untitled":"غير معنون","name":"الاسم","yourName":"اسمك","madeWithExcalidraw":"مصنوعة بواسطة Excalidraw","group":"تحديد مجموعة","ungroup":"إلغاء تحديد مجموعة","collaborators":"المتعاونون","showGrid":"إظهار الشبكة","addToLibrary":"أضف إلى المكتبة","removeFromLibrary":"حذف من المكتبة","libraryLoadingMessage":"جارٍ تحميل المكتبة…","libraries":"تصفح المكتبات","loadingScene":"جاري تحميل المشهد…","align":"محاذاة","alignTop":"محاذاة إلى اﻷعلى","alignBottom":"محاذاة إلى اﻷسفل","alignLeft":"محاذاة إلى اليسار","alignRight":"محاذاة إلى اليمين","centerVertically":"توسيط عمودي","centerHorizontally":"توسيط أفقي","distributeHorizontally":"التوزيع الأفقي","distributeVertically":"التوزيع عمودياً","flipHorizontal":"قلب عامودي","flipVertical":"قلب أفقي","viewMode":"نمط العرض","share":"مشاركة","showStroke":"إظهار منتقي لون الخط","showBackground":"إظهار منتقي لون الخلفية","toggleTheme":"غير النمط","personalLib":"المكتبة الشخصية","excalidrawLib":"مكتبتنا","decreaseFontSize":"تصغير حجم الخط","increaseFontSize":"تكبير حجم الخط","unbindText":"فك ربط النص","bindText":"ربط النص بالحاوية","createContainerFromText":"نص مغلف في حاوية","link":{"edit":"تعديل الرابط","editEmbed":"تحرير الرابط وإدراجه","create":"إنشاء رابط","createEmbed":"إنشاء رابط و إدراجه","label":"رابط","labelEmbed":"رابط و إدراج","empty":"لم يتم تعيين رابط"},"lineEditor":{"edit":"تحرير السطر","exit":"الخروج من المُحرر"},"elementLock":{"lock":"قفل","unlock":"فتح","lockAll":"قفل الكل","unlockAll":"فتح الكل"},"statusPublished":"نُشر","sidebarLock":"إبقاء الشريط الجانبي مفتوح","selectAllElementsInFrame":"تحديد جميع العناصر في الإطار","removeAllElementsFromFrame":"إزالة جميع العناصر من الإطار","eyeDropper":"اختيار اللون من القماش"},"library":{"noItems":"لا توجد عناصر أضيفت بعد...","hint_emptyLibrary":"حدد عنصر على القماش لإضافته هنا، أو تثبيت مكتبة من المستودع العام أدناه.","hint_emptyPrivateLibrary":"حدد عنصر على القماش لإضافته هنا."},"buttons":{"clearReset":"إعادة تعيين اللوحة","exportJSON":"صدر الملف","exportImage":"تصدير الصورة...","export":"حفظ إلى...","copyToClipboard":"نسخ إلى الحافظة","save":"احفظ للملف الحالي","saveAs":"حفظ كـ","load":"فتح","getShareableLink":"احصل على رابط المشاركة","close":"غلق","selectLanguage":"اختر اللغة","scrollBackToContent":"الرجوع إلى المحتوى","zoomIn":"تكبير","zoomOut":"تصغير","resetZoom":"إعادة تعيين الشاشة","menu":"القائمة","done":"تم","edit":"تعديل","undo":"تراجع","redo":"إعادة تنفيذ","resetLibrary":"إعادة ضبط المكتبة","createNewRoom":"إنشاء غرفة جديدة","fullScreen":"شاشة كاملة","darkMode":"الوضع المظلم","lightMode":"الوضع المضيء","zenMode":"وضع التأمل","objectsSnapMode":"التقط إلى العناصر","exitZenMode":"إلغاء الوضع الليلى","cancel":"إلغاء","clear":"مسح","remove":"إزالة","embed":"تبديل الإدراج","publishLibrary":"انشر","submit":"أرسل","confirm":"تأكيد","embeddableInteractionButton":"اضغط للتفاعل"},"alerts":{"clearReset":"هذا سيُزيل كامل اللوحة. هل أنت متأكد؟","couldNotCreateShareableLink":"تعذر إنشاء رابطة المشاركة.","couldNotCreateShareableLinkTooBig":"تعذر إنشاء رابط قابل للمشاركة: المشهد كبير جدًا","couldNotLoadInvalidFile":"تعذر التحميل، الملف غير صالح","importBackendFailed":"فشل الاستيراد من الخادوم.","cannotExportEmptyCanvas":"لا يمكن تصدير لوحة فارغة.","couldNotCopyToClipboard":"تعذر النسخ إلى الحافظة.","decryptFailed":"تعذر فك تشفير البيانات.","uploadedSecurly":"تم تأمين التحميل بتشفير النهاية إلى النهاية، مما يعني أن خادوم Excalidraw والأطراف الثالثة لا يمكنها قراءة المحتوى.","loadSceneOverridePrompt":"تحميل الرسم الخارجي سيحل محل المحتوى الموجود لديك. هل ترغب في المتابعة؟","collabStopOverridePrompt":"إيقاف الجلسة سيؤدي إلى الكتابة فوق رسومك السابقة المخزنة داخليا. هل أنت متأكد؟\\n\\n(إذا كنت ترغب في الاحتفاظ برسمك المخزن داخليا، ببساطة أغلق علامة تبويب المتصفح بدلاً من ذلك.)","errorAddingToLibrary":"تعذر إضافة العنصر للمكتبة","errorRemovingFromLibrary":"تعذر إزالة العنصر من المكتبة","confirmAddLibrary":"هذا سيضيف {{numShapes}} شكل إلى مكتبتك. هل أنت متأكد؟","imageDoesNotContainScene":"يبدو أن هذه الصورة لا تحتوي على أي بيانات مشهد. هل قمت بتمكين تضمين المشهد أثناء التصدير؟","cannotRestoreFromImage":"تعذر استعادة المشهد من ملف الصورة","invalidSceneUrl":"تعذر استيراد المشهد من عنوان URL المتوفر. إما أنها مشوهة، أو لا تحتوي على بيانات Excalidraw JSON صالحة.","resetLibrary":"هذا سوف يمسح مكتبتك. هل أنت متأكد؟","removeItemsFromsLibrary":"حذف {{count}} عنصر (عناصر) من المكتبة؟","invalidEncryptionKey":"مفتاح التشفير يجب أن يكون من 22 حرفاً. التعاون المباشر معطل.","collabOfflineWarning":"لا يوجد اتصال بالانترنت.\\nلن يتم حفظ التغييرات التي قمت بها!"},"errors":{"unsupportedFileType":"نوع الملف غير مدعوم.","imageInsertError":"تعذر إدراج الصورة. حاول مرة أخرى لاحقاً...","fileTooBig":"الملف كبير جداً. الحد الأقصى المسموح به للحجم هو {{maxSize}}.","svgImageInsertError":"تعذر إدراج صورة SVG. يبدو أن ترميز SVG غير صحيح.","failedToFetchImage":"","invalidSVGString":"SVG غير صالح.","cannotResolveCollabServer":"تعذر الاتصال بخادم التعاون. الرجاء إعادة تحميل الصفحة والمحاولة مرة أخرى.","importLibraryError":"تعذر تحميل المكتبة","collabSaveFailed":"تعذر الحفظ في قاعدة البيانات. إذا استمرت المشاكل، يفضل أن تحفظ ملفك محليا كي لا تفقد عملك.","collabSaveFailed_sizeExceeded":"تعذر الحفظ في قاعدة البيانات، يبدو أن القماش كبير للغاية، يفضّل حفظ الملف محليا كي لا تفقد عملك.","brave_measure_text_error":{"line1":"يبدو أنك تستخدم متصفح Brave مع إعداد حظر صارم لتتبع البصمة.","line2":"قد يؤدي هذا إلى كسر عناصر النص في الرسومات الخاصة بك.","line3":"من المستحسن إلغاء تفعيل هذا الإعداد. يمكنك اتباع هذه الخطوات لفعل ذلك.","line4":"إذا لم يصلح تعطيل هذا الإعداد طريقة عرض النصوص، الرجاء كتابة بلاغ على حسابنا في GitHub، أو راسلنا على Discord"},"libraryElementTypeError":{"embeddable":"لا يمكن إضافة العناصر القابلة للتضمين في المكتبة.","image":"سوف يتم دعم إضافة صور إلى المكتبة قريباً!"}},"toolBar":{"selection":"تحديد","image":"إدراج صورة","rectangle":"مستطيل","diamond":"مضلع","ellipse":"دائرة","arrow":"سهم","line":"خط","freedraw":"رسم","text":"نص","library":"مكتبة","lock":"الحفاظ على أداة التحديد نشطة بعد الرسم","penMode":"وضع القلم - امنع اللمس","link":"إضافة/تحديث الرابط للشكل المحدد","eraser":"ممحاة","frame":"أداة الإطار","embeddable":"تضمين ويب","laser":"مؤشر ليزر","hand":"يد (أداة الإزاحة)","extraTools":"المزيد من أﻷدوات"},"headings":{"canvasActions":"إجراءات اللوحة","selectedShapeActions":"إجراءات الشكل المحدد","shapes":"الأشكال"},"hints":{"canvasPanning":"لتحريك القماش، اضغط على عجلة الفأرة أو مفتاح المسافة أثناء السحب، أو استخدم أداة اليد","linearElement":"انقر لبدء نقاط متعددة، اسحب لخط واحد","freeDraw":"انقر واسحب، افرج عند الانتهاء","text":"نصيحة: يمكنك أيضًا إضافة نص بالنقر المزدوج في أي مكان بأداة الاختيار","embeddable":"اضغط مع السحب لإنشاء موقع ويب مضمّن","text_selected":"انقر نقراً مزدوجاً أو اضغط ادخال لتعديل النص","text_editing":"اضغط على Esc أو (Ctrl أو Cmd) + Enter لإنهاء التعديل","linearElementMulti":"انقر فوق النقطة الأخيرة أو اضغط على Esc أو Enter للإنهاء","lockAngle":"يمكنك تقييد الزاوية بالضغط على SHIFT","resize":"يمكنك تقييد النسب بالضغط على SHIFT أثناء تغيير الحجم،\\nاضغط على ALT لتغيير الحجم من المركز","resizeImage":"يمكنك تغيير الحجم بحرية بالضغط بأستمرار على SHIFT،\\nاضغط بأستمرار على ALT أيضا لتغيير الحجم من المركز","rotate":"يمكنك تقييد الزوايا من خلال الضغط على SHIFT أثناء الدوران","lineEditor_info":"اضغط على مفتاح (Ctrl أو Cmd) و انقر بشكل مزدوج، أو اضغط على مفتاحي (Ctrl أو Cmd) و (Enter) لتعديل النقاط","lineEditor_pointSelected":"اضغط على حذف لإزالة النقطة (النِّقَاط)، Ctrl/Cmd+D للتكرار، أو اسحب للانتقال","lineEditor_nothingSelected":"اختر نقطة لتعديلها (اضغط على SHIFT لتحديد عدة نِقَاط),\\nأو اضغط على ALT و انقر بالفأرة لإضافة نِقَاط جديدة","placeImage":"انقر لوضع الصورة، أو انقر واسحب لتعيين حجمها يدوياً","publishLibrary":"نشر مكتبتك","bindTextToElement":"اضغط على إدخال لإضافة نص","deepBoxSelect":"اضغط على Ctrl\\\\Cmd للاختيار العميق، ولمنع السحب","eraserRevert":"اضغط على Alt لاستعادة العناصر المعلَّمة للحذف","firefox_clipboard_write":"يمكن على الأرجح تمكين هذه الميزة عن طريق تعيين علم \\"dom.events.asyncClipboard.clipboardItem\\" إلى \\"true\\". لتغيير أعلام المتصفح في Firefox، قم بزيارة صفحة \\"about:config\\".","disableSnapping":"اضغط على Ctrl أو Cmd لتعطيل الالتقاط"},"canvasError":{"cannotShowPreview":"تعذر عرض المعاينة","canvasTooBig":"قد تكون اللوحة كبيرة جداً.","canvasTooBigTip":"نصيحة: حاول تحريك العناصر البعيدة بشكل أقرب قليلاً."},"errorSplash":{"headingMain":"حدث خطأ. حاول .","clearCanvasMessage":"إذا لم تعمل إعادة التحميل، حاول مرة أخرى ","clearCanvasCaveat":" هذا سيؤدي إلى فقدان العمل ","trackedToSentry":"تم تتبع الخطأ في المعرف {{eventId}} على نظامنا.","openIssueMessage":"حرصنا على عدم إضافة معلومات المشهد في بلاغ الخطأ. في حال كون مشهدك لا يحمل أي معلومات خاصة نرجو المتابعة على . نرجو إضافة المعلومات أدناه بنسخها ولصقها في محتوى البلاغ على GitHub.","sceneContent":"محتوى المشهد:"},"roomDialog":{"desc_intro":"يمكنك دعوة الآخرين لمشاركتك نفس الجلسة التي تعمل عليها.","desc_privacy":"لا تقلق، الجلسة تستخدم التشفير من النهاية إلى النهاية، لذلك فإن أي شيء ترسمه سيبقى خاصاً. لن يتمكن حتى الخادوم الخاص بنا من رؤية ما توصلت إليه.","button_startSession":"بدء الجلسة","button_stopSession":"إيقاف الجلسة","desc_inProgressIntro":"تجري الآن المشاركة الحية.","desc_shareLink":"شارك هذا الرابط مع أي شخص تريده أن يشاركك الجلسة:","desc_exitSession":"إيقاف الجلسة سيؤدي إلى قطع الاتصال الخاص بك من الغرفة، ولكن ستتمكن من مواصلة العمل مع المشهد، محليا. لاحظ أن هذا لن يؤثر على الأشخاص الآخرين، و سيظلون قادرين على التعاون في إصدارهم.","shareTitle":"الانضمام إلى جلسة تعاون حية على Excalidraw"},"errorDialog":{"title":"خطأ"},"exportDialog":{"disk_title":"حفظ الملف للجهاز","disk_details":"تصدير بيانات المشهد إلى ملف يمكنك الاستيراد منه لاحقاً.","disk_button":"إحفظ لملف","link_title":"رابط قابل للمشاركة","link_details":"صدر الملف للمشاهدة فقط.","link_button":"التصدير كرابط","excalidrawplus_description":"حفظ المشهد إلى مساحة العمل +Excalidraw الخاصة بك.","excalidrawplus_button":"تصدير","excalidrawplus_exportError":"تعذر التصدير إلى +Excalidraw في الوقت الحالي..."},"helpDialog":{"blog":"اقرأ مدونتنا","click":"انقر","deepSelect":"تحديد عميق","deepBoxSelect":"تحديد عميق داخل المربع، ومنع السحب","curvedArrow":"سهم مائل","curvedLine":"خط مائل","documentation":"دليل الاستخدام","doubleClick":"انقر مرتين","drag":"اسحب","editor":"المحرر","editLineArrowPoints":"تحرير سطر/نقاط سهم","editText":"تعديل النص / إضافة تسمية","github":"عثرت على مشكلة؟ إرسال","howto":"اتبع التعليمات","or":"أو","preventBinding":"منع ارتبط السهم","tools":"الأدوات","shortcuts":"اختصارات لوحة المفاتيح","textFinish":"إنهاء التعديل (محرر النص)","textNewLine":"أضف سطر جديد (محرر نص)","title":"المساعدة","view":"عرض","zoomToFit":"تكبير للملائمة","zoomToSelection":"تكبير للعنصر المحدد","toggleElementLock":"إغلاق/فتح المحدد","movePageUpDown":"نقل الصفحة أعلى/أسفل","movePageLeftRight":"نقل الصفحة يسار/يمين"},"clearCanvasDialog":{"title":"مسح اللوحة"},"publishDialog":{"title":"نشر المكتبة","itemName":"إسم العنصر","authorName":"إسم المؤلف","githubUsername":"اسم المستخدم في جيت هب","twitterUsername":"اسم المستخدم في تويتر","libraryName":"اسم المكتبة","libraryDesc":"وصف المكتبة","website":"الموقع","placeholder":{"authorName":"اسمك أو اسم المستخدم","libraryName":"اسم مكتبتك","libraryDesc":"وصف مكتبتك لمساعدة الناس على فهم استخدامها","githubHandle":"معالج GitHub (اختياري)، حتى تتمكن من تحرير المكتبة عند إرسالها للمراجعة","twitterHandle":"اسم مستخدم تويتر (اختياري)، حتى نعرف من الذي سيتم الإشارة إليه عند الترويج عبر تويتر","website":"رابط إلى موقعك الشخصي أو في مكان آخر (اختياري)"},"errors":{"required":"مطلوب","website":"أدخل عنوان URL صالح"},"noteDescription":"تقديم مكتبتك لتضمينها في مستودع المكتبة العامة لأشخاص آخرين لاستخدامها في رسومهم.","noteGuidelines":"تحتاج المكتبة إلى الموافقة أولا. يرجى قراءة المعايير قبل تقديمها. سوف تحتاج إلى حساب GitHub للتواصل وإجراء التغييرات عند الطلب، ولكن ليس مطلوبا بشكل صارم.","noteLicense":"تقديمك يعني موافقتك على نشر المكتبة المقدمة تحت MIT ترخيص، ما يعني أن لأي أحد الحق في استخدامها دون قيود.","noteItems":"يجب أن يكون لكل عنصر مكتبة اسمه الخاص حتى يكون قابلاً للتصفية. سيتم تضمين عناصر المكتبة التالية:","atleastOneLibItem":"يرجى تحديد عنصر مكتبة واحد على الأقل للبدء","republishWarning":"ملاحظة: بعض العناصر المحددة معينة على أنه نشرها أو تقديمها من قبل. يجب عليك فقط إعادة إرسال العناصر عند تحديث مكتبة موجودة أو إرسالها."},"publishSuccessDialog":{"title":"تم إرسال المكتبة","content":"شكرا لك {{authorName}}. لقد تم إرسال مكتبتك للمراجعة. يمكنك تتبع الحالة"},"confirmDialog":{"resetLibrary":"إعادة ضبط المكتبة","removeItemsFromLib":"إزالة العناصر المحددة من المكتبة"},"imageExportDialog":{"header":"تصدير الصورة","label":{"withBackground":"الخلفية","onlySelected":"المحدد فقط","darkMode":"الوضع الداكن","embedScene":"تضمين المشهد","scale":"الحجم","padding":"الهوامش"},"tooltip":{"embedScene":"سيتم حفظ بيانات المشهد في ملف PNG/SVG المصدّر بحيث يمكن استعادة المشهد منه.\\nسيزيد حجم الملف المصدر."},"title":{"exportToPng":"تصدير بصيغة PNG","exportToSvg":"تصدير بصيغة SVG","copyPngToClipboard":"نسخ الـ PNG إلى الحافظة"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"نسخ إلى الحافظة"}},"encrypted":{"tooltip":"رسوماتك مشفرة من النهاية إلى النهاية حتى أن خوادم Excalidraw لن تراها أبدا.","link":"مشاركة المدونة في التشفير من النهاية إلى النهاية في Excalidraw"},"stats":{"angle":"الزاوية","element":"عنصر","elements":"العناصر","height":"الارتفاع","scene":"المشهد","selected":"المحدد","storage":"التخزين","title":"إحصائيات للمهووسين","total":"المجموع","version":"الإصدار","versionCopy":"انقر للنسخ","versionNotAvailable":"الإصدار غير متوفر","width":"العرض"},"toast":{"addedToLibrary":"تمت الاضافة الى المكتبة!","copyStyles":"نسخت الانماط.","copyToClipboard":"نسخ إلى الحافظة.","copyToClipboardAsPng":"تم نسخ {{exportSelection}} إلى الحافظة بصيغة PNG\\n({{exportColorScheme}})","fileSaved":"تم حفظ الملف.","fileSavedToFilename":"حفظ باسم {filename}","canvas":"لوحة الرسم","selection":"العنصر المحدد","pasteAsSingleElement":"استخدم {{shortcut}} للصق كعنصر واحد،\\nأو لصق في محرر نص موجود","unableToEmbed":"تضمين هذا الرابط غير مسموح حاليًا. افتح بلاغاً على GitHub لطلب عنوان Url القائمة البيضاء","unrecognizedLinkFormat":"الرابط الذي ضمنته لا يتطابق مع التنسيق المتوقع. الرجاء محاولة لصق النص \'المضمن\' المُزوَد من موقع المصدر"},"colors":{"transparent":"شفاف","black":"أسود","white":"أبيض","red":"أحمر","pink":"وردي","grape":"عنبي","violet":"بنفسجي","gray":"رمادي","blue":"أزرق","cyan":"سماوي","teal":"أزرق مخضر","green":"أخضر","yellow":"أصفر","orange":"برتقالي","bronze":"برونزي"},"welcomeScreen":{"app":{"center_heading":"جميع بياناتك محفوظة محليا في المتصفح الخاص بك.","center_heading_plus":"هل تريد الذهاب إلى Excalidraw+ بدلاً من ذلك؟","menuHint":"التصدير والتفضيلات واللغات ..."},"defaults":{"menuHint":"التصدير والتفضيلات وغيرها...","center_heading":"الرسم البياني التصويري. بشكل مبسط.","toolbarHint":"اختر أداة و ابدأ الرسم!","helpHint":"الاختصارات و المساعدة"}},"colorPicker":{"mostUsedCustomColors":"الألوان المخصصة الأكثر استخداما","colors":"الألوان","shades":"الدرجات","hexCode":"رمز Hex","noShades":"لا تتوفر درجات لهذا اللون"},"overwriteConfirm":{"action":{"exportToImage":{"title":"تصدير كصورة","button":"تصدير كصورة","description":"تصدير بيانات المشهد إلى ملف يمكنك الاستيراد منه لاحقاً."},"saveToDisk":{"title":"حفظ الملف للجهاز","button":"حفظ الملف للجهاز","description":"تصدير بيانات المشهد إلى ملف يمكنك الاستيراد منه لاحقاً."},"excalidrawPlus":{"title":"Excalidraw+","button":"تصدير إلى Excalidraw+","description":"حفظ المشهد إلى مساحة العمل +Excalidraw الخاصة بك."}},"modal":{"loadFromFile":{"title":"تحميل من ملف","button":"تحميل من ملف","description":"سيتم التحميل من الملف استبدال المحتوى الموجود. يمكنك النسخ الاحتياطي لرسمك أولاً باستخدام أحد الخيارات أدناه."},"shareableLink":{"title":"تحميل من رابط","button":"استبدال محتواي","description":"سيتسبب تحميل رسمة خارجية باستبدال محتواك الموجود حالياً. بإمكانك إجراء النسخ الاحتياطي لرسمتك الحالية باستخدام أحد الخيارات أدناه."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/az-AZ-json-5d70eb8bf3f20abc3bac.js b/public/excalidraw/excalidraw-assets-dev/locales/az-AZ-json-5d70eb8bf3f20abc3bac.js
new file mode 100644
index 0000000..02237df
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/az-AZ-json-5d70eb8bf3f20abc3bac.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/az-AZ-json"],{
+
+/***/ "../../locales/az-AZ.json":
+/*!********************************!*\
+ !*** ../../locales/az-AZ.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Yapışdır","pasteAsPlaintext":"Düz mətn kimi yapışdırın","pasteCharts":"Diaqramları yapışdırın","selectAll":"Hamısını seç","multiSelect":"Seçimə element əlavə edin","moveCanvas":"Kanvası köçürün","cut":"Kəs","copy":"Kopyala","copyAsPng":"PNG olaraq panoya kopyala","copyAsSvg":"SVG olaraq panoya kopyala","copyText":"Mətn olaraq panoya kopyala","bringForward":"Önə daşı","sendToBack":"Geriyə göndərin","bringToFront":"Önə gətirin","sendBackward":"Geriyə göndərin","delete":"Sil","copyStyles":"Stilləri kopyalayın","pasteStyles":"Stilləri yapışdırın","stroke":"Strok rəngi","background":"Arxa fon","fill":"Doldur","strokeWidth":"Strok eni","strokeStyle":"Strok stili","strokeStyle_solid":"Solid","strokeStyle_dashed":"Kəsik","strokeStyle_dotted":"Nöqtəli","sloppiness":"Səliqəsizlik","opacity":"Şəffaflıq","textAlign":"Mətni uyğunlaşdır","edges":"Kənarlar","sharp":"Kəskin","round":"Dəyirmi","arrowheads":"Ox ucları","arrowhead_none":"Heç biri","arrowhead_arrow":"Ox","arrowhead_bar":"Çubuq","arrowhead_dot":"Nöqtə","arrowhead_triangle":"Üçbucaq","fontSize":"Şrift ölçüsü","fontFamily":"Şrift qrupu","addWatermark":"\\"Made with Excalidraw\\" əlavə et","handDrawn":"Əllə çəkilmiş","normal":"Normal","code":"Kod","small":"Kiçik","medium":"Orta","large":"Böyük","veryLarge":"Çox böyük","solid":"Solid","hachure":"Ştrix","zigzag":"Ziqzaq","crossHatch":"Çarpaz dəlik","thin":"İncə","bold":"Qalın","left":"Sol","center":"Mərkəz","right":"Sağ","extraBold":"Ekstra qalın","architect":"Memar","artist":"Rəssam","cartoonist":"Karikaturaçı","fileTitle":"Fayl adı","colorPicker":"Rəng seçən","canvasColors":"Kanvas üzərində istifadə olunur","canvasBackground":"Kanvas arxa fonu","drawingCanvas":"Kanvas çəkmək","layers":"Qatlar","actions":"Hərəkətlər","language":"Dil","liveCollaboration":"Canlı əməkdaşlıq...","duplicateSelection":"Dublikat","untitled":"Başlıqsız","name":"Ad","yourName":"Adınız","madeWithExcalidraw":"Excalidraw ilə hazırlanmışdır","group":"Qrup şəklində seçim","ungroup":"Qrupsuz seçim","collaborators":"","showGrid":"","addToLibrary":"","removeFromLibrary":"","libraryLoadingMessage":"","libraries":"","loadingScene":"","align":"","alignTop":"","alignBottom":"","alignLeft":"","alignRight":"","centerVertically":"","centerHorizontally":"","distributeHorizontally":"","distributeVertically":"","flipHorizontal":"","flipVertical":"","viewMode":"","share":"","showStroke":"","showBackground":"","toggleTheme":"","personalLib":"","excalidrawLib":"","decreaseFontSize":"","increaseFontSize":"","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"","editEmbed":"","create":"","createEmbed":"","label":"","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"","unlock":"","lockAll":"","unlockAll":""},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"","exportJSON":"","exportImage":"","export":"","copyToClipboard":"","save":"","saveAs":"","load":"","getShareableLink":"","close":"","selectLanguage":"","scrollBackToContent":"","zoomIn":"","zoomOut":"","resetZoom":"","menu":"","done":"","edit":"","undo":"","redo":"","resetLibrary":"","createNewRoom":"","fullScreen":"","darkMode":"","lightMode":"","zenMode":"","objectsSnapMode":"","exitZenMode":"","cancel":"","clear":"","remove":"","embed":"","publishLibrary":"","submit":"","confirm":"","embeddableInteractionButton":""},"alerts":{"clearReset":"","couldNotCreateShareableLink":"","couldNotCreateShareableLinkTooBig":"","couldNotLoadInvalidFile":"","importBackendFailed":"","cannotExportEmptyCanvas":"","couldNotCopyToClipboard":"","decryptFailed":"","uploadedSecurly":"","loadSceneOverridePrompt":"","collabStopOverridePrompt":"","errorAddingToLibrary":"","errorRemovingFromLibrary":"","confirmAddLibrary":"","imageDoesNotContainScene":"","cannotRestoreFromImage":"","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"","invalidEncryptionKey":"","collabOfflineWarning":""},"errors":{"unsupportedFileType":"","imageInsertError":"","fileTooBig":"","svgImageInsertError":"","failedToFetchImage":"","invalidSVGString":"","cannotResolveCollabServer":"","importLibraryError":"","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"","image":"","rectangle":"","diamond":"","ellipse":"","arrow":"","line":"","freedraw":"","text":"","library":"","lock":"","penMode":"","link":"","eraser":"","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"","selectedShapeActions":"","shapes":""},"hints":{"canvasPanning":"","linearElement":"","freeDraw":"","text":"","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"","lockAngle":"","resize":"","resizeImage":"","rotate":"","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"","canvasTooBig":"","canvasTooBigTip":""},"errorSplash":{"headingMain":"","clearCanvasMessage":"","clearCanvasCaveat":"","trackedToSentry":"","openIssueMessage":"","sceneContent":""},"roomDialog":{"desc_intro":"","desc_privacy":"","button_startSession":"","button_stopSession":"","desc_inProgressIntro":"","desc_shareLink":"","desc_exitSession":"","shareTitle":""},"errorDialog":{"title":""},"exportDialog":{"disk_title":"","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"","excalidrawplus_exportError":""},"helpDialog":{"blog":"","click":"","deepSelect":"","deepBoxSelect":"","curvedArrow":"","curvedLine":"","documentation":"","doubleClick":"","drag":"","editor":"","editLineArrowPoints":"","editText":"","github":"","howto":"","or":"","preventBinding":"","tools":"","shortcuts":"","textFinish":"","textNewLine":"","title":"","view":"","zoomToFit":"","zoomToSelection":"","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"","githubUsername":"","twitterUsername":"","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"","link":""},"stats":{"angle":"","element":"","elements":"","height":"","scene":"","selected":"","storage":"","title":"","total":"","version":"","versionCopy":"","versionNotAvailable":"","width":""},"toast":{"addedToLibrary":"","copyStyles":"","copyToClipboard":"","copyToClipboardAsPng":"","fileSaved":"","fileSavedToFilename":"","canvas":"","selection":"","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/bg-BG-json-88cced5fd8a6d8298501.js b/public/excalidraw/excalidraw-assets-dev/locales/bg-BG-json-88cced5fd8a6d8298501.js
new file mode 100644
index 0000000..3a05b4e
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/bg-BG-json-88cced5fd8a6d8298501.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/bg-BG-json"],{
+
+/***/ "../../locales/bg-BG.json":
+/*!********************************!*\
+ !*** ../../locales/bg-BG.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Постави","pasteAsPlaintext":"Постави като обикновен текст","pasteCharts":"Постави графики","selectAll":"Маркирай всичко","multiSelect":"Добави елемент към селекция","moveCanvas":"Премести платно","cut":"Изрежи","copy":"Копирай","copyAsPng":"Копиране в клипборда","copyAsSvg":"Копирано в клипборда като SVG","copyText":"","bringForward":"Преместване напред","sendToBack":"Изнасяне назад","bringToFront":"Изнасяне отпред","sendBackward":"Изпрати отзад","delete":"Изтрий","copyStyles":"Копирайте стилове","pasteStyles":"Постави стилове","stroke":"Щрих","background":"Фон","fill":"Наситеност","strokeWidth":"Ширина на щриха","strokeStyle":"Стил на линия","strokeStyle_solid":"Плътен","strokeStyle_dashed":"Пунктир","strokeStyle_dotted":"Пунктирано","sloppiness":"Небрежност","opacity":"Прозрачност","textAlign":"Подравняване на текста","edges":"Крайща","sharp":"Остър","round":"Закръглено","arrowheads":"Стрелки","arrowhead_none":"Без","arrowhead_arrow":"Стрелка","arrowhead_bar":"Връх на стрелката","arrowhead_dot":"Точка","arrowhead_triangle":"Триъгълник","fontSize":"Размер на шрифта","fontFamily":"Семейство шрифтове","addWatermark":"Добави \\"Направено с Excalidraw\\"","handDrawn":"Нарисувано на ръка","normal":"Нормален","code":"Код","small":"Малък","medium":"Среден","large":"Голям","veryLarge":"Много голям","solid":"Солиден","hachure":"Хералдика","zigzag":"Зигзаг","crossHatch":"Двойно-пресечено","thin":"Тънък","bold":"Ясно очертан","left":"Ляво","center":"Център","right":"Дясно","extraBold":"Много ясно очертан","architect":"Архитект","artist":"Художник","cartoonist":"Карикатурист","fileTitle":"Име на файл","colorPicker":"Избор на цвят","canvasColors":"Използван на платно","canvasBackground":"Фон на платно","drawingCanvas":"Платно за рисуване","layers":"Слоеве","actions":"Действия","language":"Език","liveCollaboration":"","duplicateSelection":"Дублирай","untitled":"Неозаглавено","name":"Име","yourName":"Вашето име","madeWithExcalidraw":"Направено с Excalidraw","group":"Групирай селекцията","ungroup":"Спри групирането на селекцията","collaborators":"Сътрудници","showGrid":"Показване на мрежа","addToLibrary":"Добавяне към библиотеката","removeFromLibrary":"Премахване от библиотеката","libraryLoadingMessage":"Зареждане на библиотеката…","libraries":"Разглеждане на библиотеките","loadingScene":"Зареждане на сцена…","align":"Подравняване","alignTop":"Подравняване отгоре","alignBottom":"Подравняване отдолу","alignLeft":"Подравняване отляво","alignRight":"Подравняване отдясно","centerVertically":"Центрирай вертикално","centerHorizontally":"Центрирай хоризонтално","distributeHorizontally":"Разпредели хоризонтално","distributeVertically":"Разпредели вертикално","flipHorizontal":"Хоризонтално обръщане","flipVertical":"Вертикално обръщане","viewMode":"Изглед","share":"Сподели","showStroke":"","showBackground":"","toggleTheme":"Включи тема","personalLib":"Лична Библиотека","excalidrawLib":"Excalidraw Библиотека","decreaseFontSize":"Намали размера на шрифта","increaseFontSize":"Увеличи размера на шрифта","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"Редактирай линк","editEmbed":"","create":"","createEmbed":"","label":"Линк","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"Заключи","unlock":"Отключи","lockAll":"Заключи всички","unlockAll":"Отключи всички"},"statusPublished":"Публикувани","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":"Избери цвят от платното"},"library":{"noItems":"Няма добавени неща все още...","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"Нулиране на платно","exportJSON":"","exportImage":"","export":"Запази на...","copyToClipboard":"Копиране в клипборда","save":"Запази към текущ файл","saveAs":"Запиши като","load":"Отвори","getShareableLink":"Получаване на връзка за споделяне","close":"Затвори","selectLanguage":"Избор на език","scrollBackToContent":"Превъртете обратно към съдържанието","zoomIn":"Приближаване","zoomOut":"Отдалечаване","resetZoom":"Стандартен мащаб","menu":"Меню","done":"Завършено","edit":"Редактиране","undo":"Отмяна","redo":"Повтори","resetLibrary":"Нулиране на библиотеката","createNewRoom":"Създай нова стая","fullScreen":"На цял екран","darkMode":"Тъмен режим","lightMode":"Светъл режим","zenMode":"Режим Zen","objectsSnapMode":"","exitZenMode":"Спиране на Zen режим","cancel":"Отмени","clear":"Изчисти","remove":"Премахване","embed":"","publishLibrary":"Публикувай","submit":"Изпрати","confirm":"Потвърждаване","embeddableInteractionButton":""},"alerts":{"clearReset":"Това ще изчисти цялото платно. Сигурни ли сте?","couldNotCreateShareableLink":"Връзката не може да бъде създадена.","couldNotCreateShareableLinkTooBig":"Не може да се създаде връзка за споделяне: сцената е твърде голяма","couldNotLoadInvalidFile":"Невалиден файл не може да се зареди","importBackendFailed":"Импортирането от бекенд не беше успешно.","cannotExportEmptyCanvas":"Не може да се експортира празно платно.","couldNotCopyToClipboard":"Не можем да копираме в клипбоарда.","decryptFailed":"Данните не можаха да се дешифрират.","uploadedSecurly":"Качването е защитено с криптиране от край до край, което означава, че сървърът Excalidraw и трети страни не могат да четат съдържанието.","loadSceneOverridePrompt":"Зареждането на външна рисунка ще презапише настоящото ви съдържание. Желаете ли да продължите?","collabStopOverridePrompt":"Прекратяването на сесията ще презапише предишната, локално запазена, рисунка. Сигурни ли сте?\\n\\n(Ако искате да продължите с локалната рисунка, просто затворете таба на браузъра.)","errorAddingToLibrary":"Не можем да заредим от библиотеката","errorRemovingFromLibrary":"Не можем да премахнем елемент от библиотеката","confirmAddLibrary":"Ще се добавят {{numShapes}} фигура(и) във вашата библиотека. Сигурни ли сте?","imageDoesNotContainScene":"","cannotRestoreFromImage":"Не може да бъде възстановена сцена от този файл","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"Изтрий {{count}} елемент(а) от библиотеката?","invalidEncryptionKey":"","collabOfflineWarning":""},"errors":{"unsupportedFileType":"Този файлов формат не се поддържа.","imageInsertError":"","fileTooBig":"Файлът е твърде голям. Максималния допустим размер е {{maxSize}}.","svgImageInsertError":"","failedToFetchImage":"","invalidSVGString":"Невалиден SVG.","cannotResolveCollabServer":"","importLibraryError":"Не можем да заредим библиотеката","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"Силно препоръчваме да изключите тази настройка. Можете да следвате тези стъпки за това как да го направите.","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Селекция","image":"Вмъкване на изображение","rectangle":"Правоъгълник","diamond":"Диамант","ellipse":"Елипс","arrow":"Стрелка","line":"Линия","freedraw":"Рисуване","text":"Текст","library":"Библиотека","lock":"Поддържайте избрания инструмент активен след рисуване","penMode":"","link":"","eraser":"Гума","frame":"","embeddable":"","laser":"","hand":"","extraTools":"Още инструменти"},"headings":{"canvasActions":"Действия по платното","selectedShapeActions":"Избрани действия","shapes":"Фигури"},"hints":{"canvasPanning":"","linearElement":"Кликнете, за да стартирате няколко точки, плъзнете за една линия","freeDraw":"Натиснете и влачете, пуснете като сте готови","text":"Подсказка: Можете също да добавите текст като натиснете някъде два път с инструмента за селекция","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"Кликнете върху последната точка или натиснете Escape или Enter, за да завършите","lockAngle":"Можете да ограничите ъгъла, като задържите SHIFT","resize":"Може да ограничите при преоразмеряване като задържите SHIFT,\\nзадръжте ALT за преоразмерите през центъра","resizeImage":"","rotate":"Можете да ограничите ъглите, като държите SHIFT, докато се въртите","lineEditor_info":"","lineEditor_pointSelected":"Натиснете Delete за да изтриете точка(и), CtrlOrCmd+D за дуплициране, или извлачете за да преместите","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"Натиснете Enter, за да добавите","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"Невъзможност за показване на preview","canvasTooBig":"Платното е твърде голямо.","canvasTooBigTip":"Подсказка: пробвайте да приближите далечните елементи по-близко."},"errorSplash":{"headingMain":"Среща грешка. Опитайте ","clearCanvasMessage":"Ако презареждането не работи, опитайте ","clearCanvasCaveat":" Това ще доведе до загуба на работа ","trackedToSentry":"Грешката с идентификатор {{eventId}} беше проследен в нашата система.","openIssueMessage":"Бяхме много предпазливи да не включите информацията за вашата сцена при грешката. Ако сцената ви не е частна, моля, помислете за последващи действия на нашата Моля, включете информация по-долу, като я копирате и добавите в GitHub.","sceneContent":"Съдържание на сцената:"},"roomDialog":{"desc_intro":"Можете да поканите хора на текущата си сцена да си сътрудничат с вас.","desc_privacy":"Не се притеснявайте, сесията използва криптиране от край до край, така че каквото нарисувате ще остане частно. Дори нашият сървър няма да може да види какво предлагате.","button_startSession":"Стартирайте сесията","button_stopSession":"Стоп на сесията","desc_inProgressIntro":"Сесията за сътрудничество на живо е в ход.","desc_shareLink":"Споделете тази връзка с всеки, с когото искате да си сътрудничите:","desc_exitSession":"Спирането на сесията ще ви изключи от стаята, но ще можете да продължите да работите със сцената, локално. Имайте предвид, че това няма да засегне други хора и те все още ще могат да си сътрудничат с тяхната версия.","shareTitle":""},"errorDialog":{"title":"Грешка"},"exportDialog":{"disk_title":"","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"Експорт","excalidrawplus_exportError":""},"helpDialog":{"blog":"Прочетете нашия блог","click":"клик","deepSelect":"","deepBoxSelect":"","curvedArrow":"Извита стрелка","curvedLine":"Извита линия","documentation":"Документация","doubleClick":"двойно-щракване","drag":"плъзнете","editor":"Редактор","editLineArrowPoints":"","editText":"","github":"Намерихте проблем? Изпратете","howto":"Следвайте нашите ръководства","or":"или","preventBinding":"Спри прилепяне на стрелките","tools":"Инструменти","shortcuts":"Клавиши за бърз достъп","textFinish":"Завърши редактиране (текстов редактор)","textNewLine":"Добави нова линия (текстов редактор)","title":"Помощ","view":"Преглед","zoomToFit":"Приближи докато се виждат всички елементи","zoomToSelection":"Приближи селекцията","toggleElementLock":"Заключи/Отключи селекция","movePageUpDown":"Премести страница нагоре/надолу","movePageLeftRight":"Премести страница наляво/надясно"},"clearCanvasDialog":{"title":"Изчисти платното"},"publishDialog":{"title":"Публикувай библиотека","itemName":"Име","authorName":"Авторско име","githubUsername":"GitHub потребителско име","twitterUsername":"Twitter потребителско име","libraryName":"Име на библиотеката","libraryDesc":"Описание на библиотеката","website":"Уебсайт","placeholder":{"authorName":"Името или потребителското Ви име","libraryName":"Име на библиотеката Ви","libraryDesc":"Описание на библиотеката ви, за да помогнете на хората да разберат приложенията ѝ","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"Задължително","website":"Въведете валиден URL адрес"},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"Нулирай библиотека","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"Фон","onlySelected":"Само избраното","darkMode":"Тъмен режим","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"Изнасяне в PNG","exportToSvg":"Изнасяне в SVG","copyPngToClipboard":"Копирай PNG в клипборда"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Копиране в клипборда"}},"encrypted":{"tooltip":"Вашите рисунки са криптирани от край до край, така че сървърите на Excalidraw няма да могат да ги виждат.","link":""},"stats":{"angle":"Ъгъл","element":"Елемент","elements":"Елементи","height":"Височина","scene":"Сцена","selected":"Селектирано","storage":"Съхранение на данни","title":"Статистика за хакери","total":"Общо","version":"Версия","versionCopy":"Настисни за да копираш","versionNotAvailable":"Версията не е налична","width":"Широчина"},"toast":{"addedToLibrary":"Добавена към библиотеката","copyStyles":"Копирани стилове.","copyToClipboard":"Копирано в клипборда.","copyToClipboardAsPng":"Копира {{exportSelection}} в клипборда като PNG\\n({{exportColorScheme}})","fileSaved":"Файлът е запазен.","fileSavedToFilename":"Запазен към {filename}","canvas":"платно","selection":"селекция","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Прозрачен","black":"Черен","white":"Бял","red":"Червен","pink":"Розов","grape":"Грозде","violet":"Виолетово","gray":"Сив","blue":"Син","cyan":"Синьозелено","teal":"Тъмно синьо-зелено","green":"Зелено","yellow":"Жълто","orange":"Оранжево","bronze":"Бронзово"},"welcomeScreen":{"app":{"center_heading":"Всичките Ви данни са запазени локално в браузъра Ви.","center_heading_plus":"","menuHint":"Експорт, предпочитания, езици, ..."},"defaults":{"menuHint":"Експорт, предпочитания, и още...","center_heading":"Диаграми. Направени. Просто.","toolbarHint":"Изберете инструмент & Започнете да рисувате!","helpHint":"Преки пътища & помощ"}},"colorPicker":{"mostUsedCustomColors":"Най-често използвани цветове","colors":"Цветове","shades":"Нюанси","hexCode":"Шестнадесетичен код","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"Изнеси като изображение","button":"Изнеси като изображение","description":""},"saveToDisk":{"title":"Запази към диск","button":"Запази към диск","description":""},"excalidrawPlus":{"title":"Excalidraw+","button":"Експортирай към Excalidraw+","description":"Запази сцената към Excalidraw+ работното място."}},"modal":{"loadFromFile":{"title":"Зареди от файл","button":"Зареди от файл","description":""},"shareableLink":{"title":"Зареди от линк","button":"Замени моето съдържание","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/bn-BD-json-a06588c61947851c8579.js b/public/excalidraw/excalidraw-assets-dev/locales/bn-BD-json-a06588c61947851c8579.js
new file mode 100644
index 0000000..b7769ac
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/bn-BD-json-a06588c61947851c8579.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/bn-BD-json"],{
+
+/***/ "../../locales/bn-BD.json":
+/*!********************************!*\
+ !*** ../../locales/bn-BD.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"পেস্ট করুন","pasteAsPlaintext":"প্লেইনটেক্সট হিসাবে পেস্ট করুন","pasteCharts":"চার্ট পেস্ট করুন","selectAll":"সবটা সিলেক্ট করুন","multiSelect":"একাধিক সিলেক্ট করুন","moveCanvas":"ক্যানভাস সরান","cut":"কাট করুন","copy":"কপি করুন","copyAsPng":"পীএনজী ছবির মতন কপি করুন","copyAsSvg":"এসভীজী ছবির মতন কপি করুন","copyText":"লিখিত তথ্যের মতন কপি করুন","bringForward":"অধিকতর সামনে আনুন","sendToBack":"অধিকতর পিছনে নিয়ে যান","bringToFront":"সবার সামনে আনুন","sendBackward":"সবার পিছনে নিয়ে যান","delete":"মুছা","copyStyles":"ডিজাইন কপি করুন","pasteStyles":"ডিজাইন পেস্ট করুন","stroke":"রেখাংশ","background":"পটভূমি","fill":"রং","strokeWidth":"রেখাংশের বেধ","strokeStyle":"রেখাংশের ডিজাইন","strokeStyle_solid":"পুরু","strokeStyle_dashed":"পাতলা","strokeStyle_dotted":"বিন্দুবিন্দু","sloppiness":"ভ্রান্তি","opacity":"দৃশ্যমানতা","textAlign":"লেখ অনুভূমি","edges":"কোণ","sharp":"তীক্ষ্ণ","round":"গোল","arrowheads":"তীরের শীর্ষভাগ","arrowhead_none":"কিছু না","arrowhead_arrow":"তীর","arrowhead_bar":"রেখাংশ","arrowhead_dot":"বিন্দু","arrowhead_triangle":"ত্রিভূজ","fontSize":"লেখনীর মাত্রা","fontFamily":"লেখনীর হরফ","addWatermark":"এক্সক্যালিড্র দ্বারা প্রস্তুত","handDrawn":"হাতে আঁকা","normal":"স্বাভাবিক","code":"কোড","small":"ছোট","medium":"মাঝারি","large":"বড়","veryLarge":"অনেক বড়","solid":"দৃঢ়","hachure":"ভ্রুলেখা","zigzag":"আঁকাবাঁকা","crossHatch":"ক্রস হ্যাচ","thin":"পাতলা","bold":"পুরু","left":"বাম","center":"কেন্দ্র","right":"ডান","extraBold":"অতি পুরু","architect":"স্থপতি","artist":"শিল্পী","cartoonist":"চিত্রকার","fileTitle":"ফাইলের নাম","colorPicker":"রং পছন্দ করুন","canvasColors":"ক্যানভাসের রং","canvasBackground":"ক্যানভাসের পটভূমি","drawingCanvas":"ব্যবহৃত ক্যানভাস","layers":"মাত্রা","actions":"ক্রিয়া","language":"ভাষা","liveCollaboration":"সরাসরি পারস্পরিক সহযোগিতা...","duplicateSelection":"সদৃশ সিলেক্ট","untitled":"অনামী","name":"নাম","yourName":"আপনার নাম","madeWithExcalidraw":"এক্সক্যালিড্র দ্বারা তৈরি","group":"দল গঠন করুন","ungroup":"দল বিভেদ করুন","collaborators":"সহযোগী","showGrid":"গ্রিড দেখান","addToLibrary":"সংগ্রহে যোগ করুন","removeFromLibrary":"সংগ্রহ থেকে বের করুন","libraryLoadingMessage":"সংগ্রহ তৈরি হচ্ছে","libraries":"সংগ্রহ দেখুন","loadingScene":"দৃশ্য তৈরি হচ্ছে","align":"পংক্তিবিন্যাস","alignTop":"উপর পংক্তি","alignBottom":"নিম্ন পংক্তি","alignLeft":"বাম পংক্তি","alignRight":"ডান পংক্তি","centerVertically":"উলম্ব কেন্দ্রিত","centerHorizontally":"অনুভূমিক কেন্দ্রিত","distributeHorizontally":"অনুভূমিকভাবে বিতরণ করুন","distributeVertically":"উল্লম্বভাবে বিতরণ করুন","flipHorizontal":"অনুভূমিক আবর্তন","flipVertical":"উলম্ব আবর্তন","viewMode":"দৃশ্য","share":"ভাগ করুন","showStroke":"","showBackground":"","toggleTheme":"","personalLib":"","excalidrawLib":"","decreaseFontSize":"লেখনীর মাত্রা কমান","increaseFontSize":"লেখনীর মাত্রা বাড়ান","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"লিঙ্ক সংশোধন","editEmbed":"","create":"লিঙ্ক তৈরী","createEmbed":"","label":"লিঙ্ক নামকরণ","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"আবদ্ধ করুন","unlock":"বিচ্ছিন্ন করুন","lockAll":"সব আবদ্ধ করুন","unlockAll":"সব বিচ্ছিন্ন করুন"},"statusPublished":"প্রকাশিত","sidebarLock":"লক","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"সংগ্রহে কিছু যোগ করা হয়নি","hint_emptyLibrary":"এখানে যোগ করার জন্য ক্যানভাসে একটি বস্তু নির্বাচন করুন, অথবা নীচে, প্রকাশ্য সংগ্রহশালা থেকে একটি সংগ্রহ ইনস্টল করুন৷","hint_emptyPrivateLibrary":"এখানে যোগ করার জন্য ক্যানভাসে একটি বস্তু নির্বাচন করুন"},"buttons":{"clearReset":"ক্যানভাস সাফ করুন","exportJSON":"জেসন নিবদ্ধ করুন","exportImage":"","export":"","copyToClipboard":"ক্লিপবোর্ডে কপি করুন","save":"জমা করুন","saveAs":"অন্যভাবে জমা করুন","load":"","getShareableLink":"ভাগযোগ্য লিঙ্ক পান","close":"বন্ধ করুন","selectLanguage":"ভাষা চিহ্নিত করুন","scrollBackToContent":"বিষয়বস্তুতে ফেরত যান","zoomIn":"বড় করুন","zoomOut":"ছোট করুন","resetZoom":"স্বাভাবিক করুন","menu":"তালিকা","done":"সম্পন্ন","edit":"সংশোধন করুন","undo":"ফেরত যান","redo":"পুনরায় করুন","resetLibrary":"সংগ্রহ সাফ করুন","createNewRoom":"নতুন রুম বানান","fullScreen":"পূর্ণস্ক্রীন","darkMode":"ডার্ক মোড","lightMode":"লাইট মোড","zenMode":"জেন মোড","objectsSnapMode":"","exitZenMode":"জেন মোড বন্ধ করুন","cancel":"বাতিল","clear":"সাফ","remove":"বিয়োগ","embed":"","publishLibrary":"সংগ্রহ প্রকাশ করুন","submit":"জমা করুন","confirm":"নিশ্চিত করুন","embeddableInteractionButton":""},"alerts":{"clearReset":"এটি পুরো ক্যানভাস সাফ করবে। আপনি কি নিশ্চিত?","couldNotCreateShareableLink":"ভাগ করা যায় এমন লিঙ্ক তৈরি করা যায়নি।","couldNotCreateShareableLinkTooBig":"ভাগ করা যায় এমন লিঙ্ক তৈরি করা যায়নি: দৃশ্যটি খুব বড়","couldNotLoadInvalidFile":"অবৈধ ফাইল লোড করা যায়নি","importBackendFailed":"ব্যাকেন্ড থেকে আপলোড ব্যর্থ হয়েছে।","cannotExportEmptyCanvas":"খালি ক্যানভাস নিবদ্ধ করা যাবে না।","couldNotCopyToClipboard":"ক্লিপবোর্ডে কপি করা যায়নি।","decryptFailed":"তথ্য ডিক্রিপ্ট করা যায়নি।","uploadedSecurly":"আপলোডটি এন্ড-টু-এন্ড এনক্রিপশনের মাধ্যমে সুরক্ষিত করা হয়েছে, যার অর্থ হল এক্সক্যালিড্র সার্ভার এবং তৃতীয় পক্ষের দ্বারা পড়তে পারা সম্ভব নয়।","loadSceneOverridePrompt":"বাহ্যিক অঙ্কন লোড করা আপনার বিদ্যমান দৃশ্য প্রতিস্থাপন করবে। আপনি কি অবিরত করতে চান?","collabStopOverridePrompt":"অধিবেশন বন্ধ করা আপনার পূর্ববর্তী, স্থানীয়ভাবে সঞ্চিত অঙ্কন ওভাররাইট করবে। আপনি কি নিশ্চিত?\\n\\n(যদি আপনি আপনার স্থানীয় অঙ্কন রাখতে চান, তাহলে শুধু ব্রাউজার ট্যাবটি বন্ধ করুন।)","errorAddingToLibrary":"বস্তুটি সংগ্রহে যোগ করা যায়নি","errorRemovingFromLibrary":"বস্তুটি সংগ্রহ থেকে বিয়োগ করা যায়নি","confirmAddLibrary":"এটি আপনার সংগ্রহে {{numShapes}} আকার(গুলি) যোগ করবে। আপনি কি নিশ্চিত?","imageDoesNotContainScene":"এই ছবিতে কোনো দৃশ্যের তথ্য আছে বলে মনে হয় না৷ আপনি কি নিবদ্ধ করার সময় দৃশ্য এমবেডিং করতে সক্ষম?","cannotRestoreFromImage":"এই ফাইল থেকে দৃশ্য পুনরুদ্ধার করা যায়নি","invalidSceneUrl":"সরবরাহ করা লিঙ্ক থেকে দৃশ্য লোড করা যায়নি৷ এটি হয় বিকৃত, অথবা বৈধ এক্সক্যালিড্র জেসন তথ্য নেই৷","resetLibrary":"এটি আপনার সংগ্রহ পরিষ্কার করবে। আপনি কি নিশ্চিত?","removeItemsFromsLibrary":"সংগ্রহ থেকে {{count}} বস্তু বিয়োগ করা হবে। আপনি কি নিশ্চিত?","invalidEncryptionKey":"অবৈধ এনক্রীপশন কী।","collabOfflineWarning":""},"errors":{"unsupportedFileType":"অসমর্থিত ফাইল।","imageInsertError":"ছবি সন্নিবেশ করা যায়নি। পরে আবার চেষ্টা করুন...","fileTooBig":"ফাইলটি খুব বড়। সর্বাধিক অনুমোদিত আকার হল {{maxSize}}৷","svgImageInsertError":"এসভীজী ছবি সন্নিবেশ করা যায়নি। এসভীজী মার্কআপটি অবৈধ মনে হচ্ছে৷","failedToFetchImage":"","invalidSVGString":"এসভীজী মার্কআপটি অবৈধ মনে হচ্ছে৷","cannotResolveCollabServer":"কোল্যাব সার্ভারের সাথে সংযোগ করা যায়নি। পৃষ্ঠাটি পুনরায় লোড করে আবার চেষ্টা করুন।","importLibraryError":"সংগ্রহ লোড করা যায়নি","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"বাছাই","image":"চিত্র সন্নিবেশ","rectangle":"আয়তক্ষেত্র","diamond":"রুহিতন","ellipse":"উপবৃত্ত","arrow":"তীর","line":"রেখা","freedraw":"কলম","text":"লেখা","library":"সংগ্রহ","lock":"আঁকার পরে নির্বাচিত টুল সক্রিয় রাখুন","penMode":"","link":"একটি নির্বাচিত আকৃতির জন্য লিঙ্ক যোগ বা আপডেট করুন","eraser":"ঝাড়ন","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"ক্যানভাস কার্যকলাপ","selectedShapeActions":"বাছাই করা আকার(গুলি)র কার্যকলাপ","shapes":"আকার(গুলি)"},"hints":{"canvasPanning":"","linearElement":"একাধিক বিন্দু শুরু করতে ক্লিক করুন, একক লাইনের জন্য টেনে আনুন","freeDraw":"ক্লিক করুন এবং টেনে আনুন, আপনার কাজ শেষ হলে ছেড়ে দিন","text":"বিশেষ্য: আপনি নির্বাচন টুলের সাথে যে কোনো জায়গায় ডাবল-ক্লিক করে পাঠ্য যোগ করতে পারেন","embeddable":"","text_selected":"লেখা সম্পাদনা করতে ডাবল-ক্লিক করুন বা এন্টার টিপুন","text_editing":"লেখা সম্পাদনা শেষ করতে এসকেপ বা কন্ট্রোল/কম্যান্ড যোগে এন্টার টিপুন","linearElementMulti":"শেষ বিন্দুতে ক্লিক করুন অথবা শেষ করতে এসকেপ বা এন্টার টিপুন","lockAngle":"ঘোরানোর সময় আপনি শিফ্ট ধরে রেখে কোণ সীমাবদ্ধ করতে পারেন","resize":"আপনি আকার পরিবর্তন করার সময় শিফ্ট ধরে রেখে অনুপাতকে সীমাবদ্ধ করতে পারেন,\\nকেন্দ্র থেকে আকার পরিবর্তন করতে অল্ট ধরে রাখুন","resizeImage":"আপনি শিফ্ট ধরে রেখে অবাধে আকার পরিবর্তন করতে পারেন, কেন্দ্র থেকে আকার পরিবর্তন করতে অল্ট ধরুন","rotate":"আপনি ঘোরানোর সময় শিফ্ট ধরে রেখে কোণগুলিকে সীমাবদ্ধ করতে পারেন","lineEditor_info":"","lineEditor_pointSelected":"বিন্দু(গুলি) মুছতে ডিলিট টিপুন, কন্ট্রোল/কম্যান্ড যোগে ডি টিপুন নকল করতে অথবা সরানোর জন্য টানুন","lineEditor_nothingSelected":"সম্পাদনা করার জন্য একটি বিন্দু নির্বাচন করুন (একাধিক নির্বাচন করতে শিফ্ট ধরে রাখুন),\\nঅথবা অল্ট ধরে রাখুন এবং নতুন বিন্দু যোগ করতে ক্লিক করুন","placeImage":"ছবিটি স্থাপন করতে ক্লিক করুন, অথবা নিজে আকার সেট করতে ক্লিক করুন এবং টেনে আনুন","publishLibrary":"আপনার নিজস্ব সংগ্রহ প্রকাশ করুন","bindTextToElement":"লেখা যোগ করতে এন্টার টিপুন","deepBoxSelect":"","eraserRevert":"মুছে ফেলার জন্য চিহ্নিত উপাদানগুলিকে ফিরিয়ে আনতে অল্ট ধরে রাখুন","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"প্রিভিউ দেখাতে অপারগ","canvasTooBig":"ক্যানভাস অনেক বড়।","canvasTooBigTip":"বিশেষ্য: দূরতম উপাদানগুলোকে একটু কাছাকাছি নিয়ে যাওয়ার চেষ্টা করুন।"},"errorSplash":{"headingMain":"একটি ত্রুটির সম্মুখীন হয়েছে৷ চেষ্টা করুন ","clearCanvasMessage":"যদি পুনরায় লোড করা কাজ না করে, চেষ্টা করুন ","clearCanvasCaveat":" এর ফলে কাজের ক্ষতি হবে ","trackedToSentry":"ত্রুটি {{eventId}} আমাদের সিস্টেমে ট্র্যাক করা হয়েছিল।","openIssueMessage":"আমরা ত্রুটিতে আপনার দৃশ্যের তথ্য অন্তর্ভুক্ত না করার জন্য খুব সতর্ক ছিলাম। আপনার দৃশ্য ব্যক্তিগত না হলে, আমাদের অনুসরণ করার কথা বিবেচনা করুন অনুগ্রহ করে GitHub ইস্যুতে অনুলিপি এবং পেস্ট করে নীচের তথ্য অন্তর্ভুক্ত করুন।","sceneContent":"দৃশ্য বিষয়বস্তু:"},"roomDialog":{"desc_intro":"আপনি আপনার সাথে সহযোগিতা করার জন্য আপনার বর্তমান দৃশ্যে লোকেদের আমন্ত্রণ জানাতে পারেন৷","desc_privacy":"চিন্তা করবেন না, সেশনটি এন্ড-টু-এন্ড এনক্রিপশন ব্যবহার করে, তাই আপনি যা আঁকবেন তা গোপন থাকবে। এমনকি আমাদের সার্ভার আপনি যা নিয়ে এসেছেন তা দেখতে সক্ষম হবে না।","button_startSession":"সেশন শুরু করুন","button_stopSession":"সেশন বন্ধ করুন","desc_inProgressIntro":"লাইভ-সহযোগীতার সেশন এখন চলছে।","desc_shareLink":"আপনি যার সাথে সহযোগিতা করতে চান তাদের সাথে এই লিঙ্কটি ভাগ করুন: ","desc_exitSession":"অধিবেশন বন্ধ করা আপনাকে রুম থেকে সংযোগ বিচ্ছিন্ন করবে, কিন্তু আপনি স্থানীয়ভাবে দৃশ্যের সাথে কাজ চালিয়ে যেতে সক্ষম হবেন। মনে রাখবেন যে এটি অন্য লোকেদের প্রভাবিত করবে না এবং তারা এখনও তাদের সংস্করণে সহযোগিতা করতে সক্ষম হবে।","shareTitle":"এক্সক্যালিড্র লাইভ সহযোগিতা সেশনে যোগ দিন"},"errorDialog":{"title":"ত্রুটি"},"exportDialog":{"disk_title":"","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"নিবদ্ধ","excalidrawplus_exportError":""},"helpDialog":{"blog":"","click":"ক্লিক","deepSelect":"","deepBoxSelect":"","curvedArrow":"","curvedLine":"","documentation":"","doubleClick":"","drag":"","editor":"","editLineArrowPoints":"","editText":"","github":"","howto":"","or":"অথবা","preventBinding":"","tools":"","shortcuts":"","textFinish":"","textNewLine":"","title":"","view":"","zoomToFit":"","zoomToSelection":"","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"","githubUsername":"","twitterUsername":"","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"","link":""},"stats":{"angle":"কোণ","element":"","elements":"","height":"","scene":"","selected":"","storage":"","title":"","total":"","version":"","versionCopy":"","versionNotAvailable":"","width":"প্রস্থ"},"toast":{"addedToLibrary":"সংগ্রহশালায় যুক্ত হয়েছে","copyStyles":"","copyToClipboard":"ক্লিপবোর্ডে কপি করা হয়েছে।","copyToClipboardAsPng":"","fileSaved":"","fileSavedToFilename":"","canvas":"","selection":"বাছাই","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/ca-ES-json-9b25933a25836cc0be23.js b/public/excalidraw/excalidraw-assets-dev/locales/ca-ES-json-9b25933a25836cc0be23.js
new file mode 100644
index 0000000..b10489d
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/ca-ES-json-9b25933a25836cc0be23.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/ca-ES-json"],{
+
+/***/ "../../locales/ca-ES.json":
+/*!********************************!*\
+ !*** ../../locales/ca-ES.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Enganxa","pasteAsPlaintext":"Enganxar com a text pla","pasteCharts":"Enganxa els diagrames","selectAll":"Selecciona-ho tot","multiSelect":"Afegeix un element a la selecció","moveCanvas":"Mou el llenç","cut":"Retalla","copy":"Copia","copyAsPng":"Copia al porta-retalls com a PNG","copyAsSvg":"Copia al porta-retalls com a SVG","copyText":"Copia al porta-retalls com a text","bringForward":"Porta endavant","sendToBack":"Envia enrere","bringToFront":"Porta al davant","sendBackward":"Envia al fons","delete":"Elimina","copyStyles":"Copia els estils","pasteStyles":"Enganxa els estils","stroke":"Color del traç","background":"Color del fons","fill":"Estil del fons","strokeWidth":"Amplada del traç","strokeStyle":"Estil del traç","strokeStyle_solid":"Sòlid","strokeStyle_dashed":"Guions","strokeStyle_dotted":"Punts","sloppiness":"Estil del traç","opacity":"Opacitat","textAlign":"Alineació del text","edges":"Vores","sharp":"Agut","round":"Arrodonit","arrowheads":"Puntes de fletxa","arrowhead_none":"Cap","arrowhead_arrow":"Fletxa","arrowhead_bar":"Barra","arrowhead_dot":"Punt","arrowhead_triangle":"Triangle","fontSize":"Mida de lletra","fontFamily":"Tipus de lletra","addWatermark":"Afegeix-hi «Fet amb Excalidraw»","handDrawn":"Dibuixat a mà","normal":"Normal","code":"Codi","small":"Petit","medium":"Mitjà","large":"Gran","veryLarge":"Molt gran","solid":"Sòlid","hachure":"Ratlletes","zigzag":"","crossHatch":"Ratlletes creuades","thin":"Fi","bold":"Negreta","left":"Esquerra","center":"Centre","right":"Dreta","extraBold":"Extra negreta","architect":"Arquitecte","artist":"Artista","cartoonist":"Dibuixant","fileTitle":"Nom del fitxer","colorPicker":"Selector de colors","canvasColors":"Usat al llenç","canvasBackground":"Fons del llenç","drawingCanvas":"Llenç de dibuix","layers":"Capes","actions":"Accions","language":"Llengua","liveCollaboration":"Col·laboració en directe...","duplicateSelection":"Duplica","untitled":"Sense títol","name":"Nom","yourName":"El vostre nom","madeWithExcalidraw":"Fet amb Excalidraw","group":"Agrupa la selecció","ungroup":"Desagrupa la selecció","collaborators":"Col·laboradors","showGrid":"Mostra la graella","addToLibrary":"Afegir a la biblioteca","removeFromLibrary":"Eliminar de la biblioteca","libraryLoadingMessage":"S\'està carregant la biblioteca…","libraries":"Explora les biblioteques","loadingScene":"S\'està carregant l\'escena…","align":"Alinea","alignTop":"Alinea a la part superior","alignBottom":"Alinea a la part inferior","alignLeft":"Alinea a l’esquerra","alignRight":"Alinea a la dreta","centerVertically":"Centra verticalment","centerHorizontally":"Centra horitzontalment","distributeHorizontally":"Distribueix horitzontalment","distributeVertically":"Distribueix verticalment","flipHorizontal":"Capgira horitzontalment","flipVertical":"Capgira verticalment","viewMode":"Mode de visualització","share":"Comparteix","showStroke":"Mostra el selector de color del traç","showBackground":"Mostra el selector de color de fons","toggleTheme":"Activa o desactiva el tema","personalLib":"Biblioteca personal","excalidrawLib":"Biblioteca d\'Excalidraw","decreaseFontSize":"Redueix la mida de la lletra","increaseFontSize":"Augmenta la mida de la lletra","unbindText":"Desvincular el text","bindText":"Ajusta el text al contenidor","createContainerFromText":"","link":{"edit":"Edita l\'enllaç","editEmbed":"","create":"Crea un enllaç","createEmbed":"","label":"Enllaç","labelEmbed":"","empty":""},"lineEditor":{"edit":"Editar línia","exit":"Sortir de l\'editor de línia"},"elementLock":{"lock":"Bloca","unlock":"Desbloca","lockAll":"Bloca-ho tot","unlockAll":"Desbloca-ho tot"},"statusPublished":"Publicat","sidebarLock":"Manté la barra lateral oberta","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Encara no s\'hi han afegit elements...","hint_emptyLibrary":"Trieu un element o un llenç per a afegir-lo aquí, o instal·leu una biblioteca del repositori públic, més avall.","hint_emptyPrivateLibrary":"Trieu un element o un llenç per a afegir-lo aquí."},"buttons":{"clearReset":"Neteja el llenç","exportJSON":"Exporta a un fitxer","exportImage":"Exporta la imatge...","export":"Guardar a...","copyToClipboard":"Copia al porta-retalls","save":"Desa al fitxer actual","saveAs":"Anomena i desa","load":"Obrir","getShareableLink":"Obté l\'enllaç per a compartir","close":"Tanca","selectLanguage":"Trieu la llengua","scrollBackToContent":"Torna al contingut","zoomIn":"Apropa\'t","zoomOut":"Allunya\'t","resetZoom":"Restableix el zoom","menu":"Menú","done":"Fet","edit":"Edita","undo":"Desfés","redo":"Refés","resetLibrary":"Restableix la biblioteca","createNewRoom":"Crea una sala nova","fullScreen":"Pantalla completa","darkMode":"Mode fosc","lightMode":"Mode clar","zenMode":"Mode zen","objectsSnapMode":"","exitZenMode":"Surt de mode zen","cancel":"Cancel·la","clear":"Neteja","remove":"Suprimeix","embed":"","publishLibrary":"Publica","submit":"Envia","confirm":"Confirma","embeddableInteractionButton":""},"alerts":{"clearReset":"S\'esborrarà tot el llenç. N\'esteu segur?","couldNotCreateShareableLink":"No s\'ha pogut crear un enllaç per a compartir.","couldNotCreateShareableLinkTooBig":"No s’ha pogut crear un enllaç per a compartir: l’escena és massa gran","couldNotLoadInvalidFile":"No s\'ha pogut carregar un fitxer no vàlid","importBackendFailed":"Importació fallida.","cannotExportEmptyCanvas":"No es pot exportar un llenç buit.","couldNotCopyToClipboard":"No s\'ha pogut copiar al porta-retalls.","decryptFailed":"No s\'ha pogut desencriptar.","uploadedSecurly":"La càrrega s\'ha assegurat amb xifratge punta a punta, cosa que significa que el servidor Excalidraw i tercers no poden llegir el contingut.","loadSceneOverridePrompt":"Si carregas aquest dibuix extern, substituirá el que tens. Vols continuar?","collabStopOverridePrompt":"Aturar la sessió provocarà la sobreescriptura del dibuix previ, que hi ha desat en l\'emmagatzematge local. N\'esteu segur?\\n\\n(Si voleu conservar el dibuix local, tanqueu la pentanya del navegador en comptes d\'aturar la sessió).","errorAddingToLibrary":"No s\'ha pogut afegir l\'element a la biblioteca","errorRemovingFromLibrary":"No s\'ha pogut eliminar l\'element de la biblioteca","confirmAddLibrary":"Això afegirà {{numShapes}} forma(es) a la vostra biblioteca. Estàs segur?","imageDoesNotContainScene":"Aquesta imatge no sembla contenir cap dada d\'escena. Heu activat l\'incrustació de l\'escena durant l\'exportació?","cannotRestoreFromImage":"L’escena no s’ha pogut restaurar des d’aquest fitxer d’imatge","invalidSceneUrl":"No s\'ha pogut importar l\'escena des de l\'adreça URL proporcionada. Està malformada o no conté dades Excalidraw JSON vàlides.","resetLibrary":"Això buidarà la biblioteca. N\'esteu segur?","removeItemsFromsLibrary":"Suprimir {{count}} element(s) de la biblioteca?","invalidEncryptionKey":"La clau d\'encriptació ha de tenir 22 caràcters. La col·laboració en directe està desactivada.","collabOfflineWarning":"Sense connexió a internet disponible.\\nEls vostres canvis no seran guardats!"},"errors":{"unsupportedFileType":"Tipus de fitxer no suportat.","imageInsertError":"No s\'ha pogut insertar la imatge, torneu-ho a provar més tard...","fileTooBig":"El fitxer és massa gros. La mida màxima permesa és {{maxSize}}.","svgImageInsertError":"No ha estat possible inserir la imatge SVG. Les marques SVG semblen invàlides.","failedToFetchImage":"","invalidSVGString":"SVG no vàlid.","cannotResolveCollabServer":"No ha estat possible connectar amb el servidor collab. Si us plau recarregueu la pàgina i torneu a provar.","importLibraryError":"No s\'ha pogut carregar la biblioteca","collabSaveFailed":"No s\'ha pogut desar a la base de dades de fons. Si els problemes persisteixen, hauríeu de desar el fitxer localment per assegurar-vos que no perdeu el vostre treball.","collabSaveFailed_sizeExceeded":"No s\'ha pogut desar a la base de dades de fons, sembla que el llenç és massa gran. Hauríeu de desar el fitxer localment per assegurar-vos que no perdeu el vostre treball.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Selecció","image":"Insereix imatge","rectangle":"Rectangle","diamond":"Rombe","ellipse":"El·lipse","arrow":"Fletxa","line":"Línia","freedraw":"Dibuix","text":"Text","library":"Biblioteca","lock":"Mantenir activa l\'eina seleccionada desprès de dibuixar","penMode":"Mode de llapis - evita tocar","link":"Afegeix / actualitza l\'enllaç per a la forma seleccionada","eraser":"Esborrador","frame":"","embeddable":"","laser":"","hand":"Mà (eina de desplaçament)","extraTools":""},"headings":{"canvasActions":"Accions del llenç","selectedShapeActions":"Accions per a les formes seleccionades","shapes":"Formes"},"hints":{"canvasPanning":"Per moure el llenç, manteniu premuda la roda del ratolí o la barra espaiadora mentre arrossegueu o utilitzeu l\'eina manual","linearElement":"Feu clic per a dibuixar múltiples punts; arrossegueu per a una sola línia","freeDraw":"Feu clic i arrossegueu, deixeu anar per a finalitzar","text":"Consell: també podeu afegir text fent doble clic en qualsevol lloc amb l\'eina de selecció","embeddable":"","text_selected":"Feu doble clic o premeu Retorn per a editar el text","text_editing":"Premeu Escapada o Ctrl+Retorn (o Ordre+Retorn) per a finalitzar l\'edició","linearElementMulti":"Feu clic a l\'ultim punt, o pitgeu Esc o Retorn per a finalitzar","lockAngle":"Per restringir els angles, mantenir premut el majúscul (SHIFT)","resize":"Per restringir les proporcions mentres es canvia la mida, mantenir premut el majúscul (SHIFT); per canviar la mida des del centre, mantenir premut ALT","resizeImage":"Podeu redimensionar lliurement prement MAJÚSCULA;\\nper a redimensionar des del centre, premeu ALT","rotate":"Per restringir els angles mentre gira, mantenir premut el majúscul (SHIFT)","lineEditor_info":"Mantingueu premut Ctrl o Cmd i feu doble clic o premeu Ctrl o Cmd + Retorn per editar els punts","lineEditor_pointSelected":"Premeu Suprimir per a eliminar el(s) punt(s), CtrlOrCmd+D per a duplicar-lo, o arrossegueu-lo per a moure\'l","lineEditor_nothingSelected":"Seleccioneu un punt per a editar-lo (premeu SHIFT si voleu\\nselecció múltiple), o manteniu Alt i feu clic per a afegir més punts","placeImage":"Feu clic per a col·locar la imatge o clic i arrossegar per a establir-ne la mida manualment","publishLibrary":"Publiqueu la vostra pròpia llibreria","bindTextToElement":"Premeu enter per a afegir-hi text","deepBoxSelect":"Manteniu CtrlOrCmd per a selecció profunda, i per a evitar l\'arrossegament","eraserRevert":"Mantingueu premuda Alt per a revertir els elements seleccionats per a esborrar","firefox_clipboard_write":"És probable que aquesta funció es pugui activar posant la marca \\"dom.events.asyncClipboard.clipboardItem\\" a \\"true\\". Per canviar les marques del navegador al Firefox, visiteu la pàgina \\"about:config\\".","disableSnapping":""},"canvasError":{"cannotShowPreview":"No es pot mostrar la previsualització","canvasTooBig":"Pot ser que el llenç sigui massa gran.","canvasTooBigTip":"Consell: proveu d’acostar una mica els elements més allunyats."},"errorSplash":{"headingMain":"S\'ha produït un error. Proveu ","clearCanvasMessage":"Si la recàrrega no funciona, proveu ","clearCanvasCaveat":" Això resultarà en la pèrdua de feina ","trackedToSentry":"L\'error amb l\'identificador {{eventId}} s\'ha rastrejat en el nostre sistema.","openIssueMessage":"Anàvem amb molta cura de no incloure la informació de la vostra escena en l\'error. Si l\'escena no és privada, podeu fer-ne el seguiment al nostre Incloeu la informació a continuació copiant i enganxant a GitHub Issues.","sceneContent":"Contingut de l\'escena:"},"roomDialog":{"desc_intro":"Podeu convidar persones a la vostra escena actual a col·laborar amb vós.","desc_privacy":"No us preocupeu, la sessió utilitza el xifratge de punta a punta, de manera que qualsevol cosa que dibuixeu romandrà privada. Ni tan sols el nostre servidor podrà veure què feu.","button_startSession":"Inicia la sessió","button_stopSession":"Atura la sessió","desc_inProgressIntro":"La sessió de col·laboració en directe està en marxa.","desc_shareLink":"Comparteix aquest enllaç amb qualsevol persona amb qui vulgueu col·laborar:","desc_exitSession":"Si atureu la sessió, us desconectareu de la sala, però podreu continuar treballant amb el dibuix localment. Tingues en compte que això no afectarà a altres persones, i encara podran col·laborar en la seva versió.","shareTitle":"Uniu-vos a una sessió de col·laboració en directe a Excalidraw"},"errorDialog":{"title":"Error"},"exportDialog":{"disk_title":"Desa al disc","disk_details":"Exporta les dades de l\'escena a un fitxer que després podreu importar.","disk_button":"Desa en un fitxer","link_title":"Enllaç per a compartir","link_details":"Exporta com a un enllaç de només lectura.","link_button":"Exporta a un enllaç","excalidrawplus_description":"Desa l\'escena en el vostre espai de treball Excalidraw+.","excalidrawplus_button":"Exporta","excalidrawplus_exportError":"No és possible exportar a Excalidraw+ ara mateix..."},"helpDialog":{"blog":"Llegiu el nostre blog","click":"clic","deepSelect":"Selecció profunda","deepBoxSelect":"Seleccioneu profundament dins del quadre i eviteu arrossegar","curvedArrow":"Fletxa corba","curvedLine":"Línia corba","documentation":"Documentació","doubleClick":"doble clic","drag":"arrossega","editor":"Editor","editLineArrowPoints":"","editText":"","github":"Hi heu trobat un problema? Informeu-ne","howto":"Seguiu les nostres guies","or":"o","preventBinding":"Prevenir vinculació de la fletxa","tools":"Eines","shortcuts":"Dreceres de teclat","textFinish":"Finalitza l\'edició (editor de text)","textNewLine":"Afegeix una línia nova (editor de text)","title":"Ajuda","view":"Visualització","zoomToFit":"Zoom per veure tots els elements","zoomToSelection":"Zoom per veure la selecció","toggleElementLock":"Blocar/desblocar la selecció","movePageUpDown":"Mou la pàgina cap amunt/a baix","movePageLeftRight":"Mou la pàgina cap a l\'esquerra/dreta"},"clearCanvasDialog":{"title":"Neteja el llenç"},"publishDialog":{"title":"Publica la biblioteca","itemName":"Nom de l\'element","authorName":"Nom de l\'autor/a","githubUsername":"Nom d\'usuari de GitHub","twitterUsername":"Nom d\'usuari de Twitter","libraryName":"Nom de la biblioteca","libraryDesc":"Descripció de la biblioteca","website":"Lloc web","placeholder":{"authorName":"Nom o usuari","libraryName":"Nom de la vostra biblioteca","libraryDesc":"Descripció de la biblioteca per a ajudar a la gent a entendre\'n el funcionament","githubHandle":"Identificador de GitHub (opcional), per tal que pugueu editar la biblioteca una vegada enviada per a ser revisada","twitterHandle":"Usuari de twitter (opcional), per tal que puguem donar-vos crèdit quan fem la promoció a Twitter","website":"Enllaç al vostre lloc web personal o a qualsevol altre (opcional)"},"errors":{"required":"Requerit","website":"Introduïu una URL vàlida"},"noteDescription":"Envieu la vostra biblioteca perquè sigui inclosa al repositori públicper tal que altres persones puguin fer-ne ús en els seus dibuixos.","noteGuidelines":"La biblioteca ha de ser aprovada manualment. Si us plau, llegiu les directrius abans d\'enviar-hi res. Necessitareu un compte de GitHub per a comunicar i fer-hi canvis si cal, però no és requisit imprescindible.","noteLicense":"Quan l\'envieu, accepteu que la biblioteca sigui publicada sota la llicència MIT, que, en resum, vol dir que qualsevol persona pot fer-ne ús sense restriccions.","noteItems":"Cada element de la biblioteca ha de tenir el seu propi nom per tal que sigui filtrable. S\'hi inclouran els elements següents:","atleastOneLibItem":"Si us plau, seleccioneu si més no un element de la biblioteca per a començar","republishWarning":"Nota: alguns dels elements seleccionats s\'han marcat com a publicats/enviats. Només hauríeu de reenviar elements quan actualitzeu una biblioteca existent."},"publishSuccessDialog":{"title":"Biblioteca enviada","content":"Gràcies, {{authorName}}. La vostra biblioteca ha estat enviada per a ser revisada. Podeu comprovar-ne l\'estataquí"},"confirmDialog":{"resetLibrary":"Restableix la biblioteca","removeItemsFromLib":"Suprimeix els elements seleccionats de la llibreria"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"Els vostres dibuixos estan xifrats de punta a punta de manera que els servidors d’Excalidraw no els veuran mai.","link":"Article del blog sobre encriptació d\'extrem a extrem a Excalidraw"},"stats":{"angle":"Angle","element":"Element","elements":"Elements","height":"Altura","scene":"Escena","selected":"Seleccionat","storage":"Emmagatzematge","title":"Estadístiques per nerds","total":"Total","version":"Versió","versionCopy":"Feu clic per a copiar","versionNotAvailable":"Versió no disponible","width":"Amplada"},"toast":{"addedToLibrary":"Afegit a la biblioteca","copyStyles":"S\'han copiat els estils.","copyToClipboard":"S\'ha copiat al porta-retalls.","copyToClipboardAsPng":"S\'ha copiat {{exportSelection}} al porta-retalls en format PNG\\n({{exportColorScheme}})","fileSaved":"S\'ha desat el fitxer.","fileSavedToFilename":"S\'ha desat a {filename}","canvas":"el llenç","selection":"la selecció","pasteAsSingleElement":"Fer servir {{shortcut}} per enganxar com un sol element,\\no enganxeu-lo en un editor de text existent","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Transparent","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"Totes les vostres dades es guarden localment al vostre navegador.","center_heading_plus":"Vols anar a Excalidraw+ en comptes?","menuHint":"Exportar, preferències, llenguatges..."},"defaults":{"menuHint":"Exportar, preferències i més...","center_heading":"Diagrames. Fer. Simple.","toolbarHint":"Selecciona una eina i comença a dibuixar!","helpHint":"Dreceres i ajuda"}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/cs-CZ-json-1d6c97ea271d017058c9.js b/public/excalidraw/excalidraw-assets-dev/locales/cs-CZ-json-1d6c97ea271d017058c9.js
new file mode 100644
index 0000000..871d4b1
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/cs-CZ-json-1d6c97ea271d017058c9.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/cs-CZ-json"],{
+
+/***/ "../../locales/cs-CZ.json":
+/*!********************************!*\
+ !*** ../../locales/cs-CZ.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Vložit","pasteAsPlaintext":"Vložit jako prostý text","pasteCharts":"Vložit grafy","selectAll":"Vybrat vše","multiSelect":"Přidat prvek do výběru","moveCanvas":"Posunout plátno","cut":"Vyjmout","copy":"Kopírovat","copyAsPng":"Zkopírovat do schránky jako PNG","copyAsSvg":"Zkopírovat do schránky jako SVG","copyText":"Zkopírovat do schránky jako text","bringForward":"Přenést blíž","sendToBack":"Přenést do pozadí","bringToFront":"Přenést do popředí","sendBackward":"Přenést dál","delete":"Smazat","copyStyles":"Kopírovat styly","pasteStyles":"Vložit styly","stroke":"Obrys","background":"Pozadí","fill":"Výplň","strokeWidth":"Tloušťka tahu","strokeStyle":"Styl tahu","strokeStyle_solid":"Plný","strokeStyle_dashed":"Čárkovaný","strokeStyle_dotted":"Tečkovaný","sloppiness":"Stylizace","opacity":"Průhlednost","textAlign":"Zarovnání textu","edges":"Hrany","sharp":"Ostré","round":"Zaoblené","arrowheads":"Styl šipky","arrowhead_none":"Žádný","arrowhead_arrow":"Šipka","arrowhead_bar":"Kóta","arrowhead_dot":"Tečka","arrowhead_triangle":"Trojúhelník","fontSize":"Velikost písma","fontFamily":"Písmo","addWatermark":"Přidat \\"Vyrobeno s Excalidraw\\"","handDrawn":"Od ruky","normal":"Normální","code":"Kód","small":"Malé","medium":"Střední","large":"Velké","veryLarge":"Velmi velké","solid":"Plný","hachure":"Hachure","zigzag":"Klikatě","crossHatch":"Křížový šrafování","thin":"Tenký","bold":"Tlustý","left":"Vlevo","center":"Na střed","right":"Vpravo","extraBold":"Extra tlustý","architect":"Architekt","artist":"Umělec","cartoonist":"Kartoonista","fileTitle":"Název souboru","colorPicker":"Výběr barvy","canvasColors":"Použito na plátně","canvasBackground":"Pozadí plátna","drawingCanvas":"Kreslicí plátno","layers":"Vrstvy","actions":"Akce","language":"Jazyk","liveCollaboration":"Živá spolupráce...","duplicateSelection":"Duplikovat","untitled":"Bez názvu","name":"Název","yourName":"Vaše jméno","madeWithExcalidraw":"Vytvořeno v Excalidraw","group":"Sloučit výběr do skupiny","ungroup":"Zrušit sloučení skupiny","collaborators":"Spolupracovníci","showGrid":"Zobrazit mřížku","addToLibrary":"Přidat do knihovny","removeFromLibrary":"Odebrat z knihovny","libraryLoadingMessage":"Načítání knihovny…","libraries":"Procházet knihovny","loadingScene":"Načítání scény…","align":"Zarovnání","alignTop":"Zarovnat nahoru","alignBottom":"Zarovnat dolů","alignLeft":"Zarovnat vlevo","alignRight":"Zarovnejte vpravo","centerVertically":"Vycentrovat svisle","centerHorizontally":"Vycentrovat vodorovně","distributeHorizontally":"Rozložit horizontálně","distributeVertically":"Rozložit svisle","flipHorizontal":"Převrátit vodorovně","flipVertical":"Převrátit svisle","viewMode":"Náhled","share":"Sdílet","showStroke":"Zobrazit výběr barvy","showBackground":"Zobrazit výběr barev pozadí","toggleTheme":"Přepnout tmavý řežim","personalLib":"Osobní knihovna","excalidrawLib":"Exkalidraw knihovna","decreaseFontSize":"Zmenšit písmo","increaseFontSize":"Zvětšit písmo","unbindText":"Zrušit vazbu textu","bindText":"Vázat text s kontejnerem","createContainerFromText":"Zabalit text do kontejneru","link":{"edit":"Upravit odkaz","editEmbed":"","create":"Vytvořit odkaz","createEmbed":"","label":"Odkaz","labelEmbed":"","empty":""},"lineEditor":{"edit":"Upravit čáru","exit":"Ukončit editor řádků"},"elementLock":{"lock":"Uzamknout","unlock":"Odemknout","lockAll":"Uzamknout vše","unlockAll":"Odemknout vše"},"statusPublished":"Zveřejněno","sidebarLock":"Ponechat postranní panel otevřený","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":"Vyberte barvu z plátna"},"library":{"noItems":"Dosud neexistují žádné položky...","hint_emptyLibrary":"Vyberte položku na plátně a přidejte ji sem nebo nainstalujte knihovnu z veřejného úložiště níže.","hint_emptyPrivateLibrary":"Vyberte položku na plátně a přidejte ji sem."},"buttons":{"clearReset":"Resetovat plátno","exportJSON":"Exportovat do souboru","exportImage":"Exportovat obrázek...","export":"Uložit jako...","copyToClipboard":"Kopírovat do schránky","save":"Uložit do aktuálního souboru","saveAs":"Uložit jako","load":"Otevřít","getShareableLink":"Získat odkaz pro sdílení","close":"Zavřít","selectLanguage":"Zvolit jazyk","scrollBackToContent":"Přejít zpět na obsah","zoomIn":"Přiblížit","zoomOut":"Oddálit","resetZoom":"Resetovat přiblížení","menu":"Menu","done":"Hotovo","edit":"Upravit","undo":"Zpět","redo":"Znovu","resetLibrary":"Obnovit knihovnu","createNewRoom":"Vytvořit novou místnost","fullScreen":"Celá obrazovka","darkMode":"Tmavý režim","lightMode":"Světlý režim","zenMode":"Zen mód","objectsSnapMode":"","exitZenMode":"Opustit zen mód","cancel":"Zrušit","clear":"Vyčistit","remove":"Odstranit","embed":"","publishLibrary":"Zveřejnit","submit":"Odeslat","confirm":"Potvrdit","embeddableInteractionButton":""},"alerts":{"clearReset":"Toto vymaže celé plátno. Jste si jisti?","couldNotCreateShareableLink":"Nepodařilo se vytvořit sdílitelný odkaz.","couldNotCreateShareableLinkTooBig":"Nepodařilo se vytvořit sdílený odkaz: scéna je příliš velká","couldNotLoadInvalidFile":"Nepodařilo se načíst neplatný soubor","importBackendFailed":"Import z backendu se nezdařil.","cannotExportEmptyCanvas":"Nelze exportovat prázdné plátno.","couldNotCopyToClipboard":"Nelze zkopírovat do schránky.","decryptFailed":"Nelze dešifrovat data.","uploadedSecurly":"Nahrávání je zabezpečeno koncovým šifrováním, což znamená, že server Excalidraw ani třetí strany nemohou obsah přečíst.","loadSceneOverridePrompt":"Načítání externího výkresu nahradí váš existující obsah. Přejete si pokračovat?","collabStopOverridePrompt":"Zastavení relace přepíše vaše předchozí, lokálně uložené kresby. Jste si jisti?\\n\\n(Pokud chcete zachovat místní kresbu, jednoduše zavřete kartu prohlížeče)","errorAddingToLibrary":"Položku nelze přidat do knihovny","errorRemovingFromLibrary":"Položku nelze odstranit z knihovny","confirmAddLibrary":"Tímto přidáte {{numShapes}} tvarů do tvé knihovny. Jste si jisti?","imageDoesNotContainScene":"Zdá se, že tento obrázek neobsahuje žádná data o scéně. Zapnuli jste při exportu vkládání scény?","cannotRestoreFromImage":"Scénu nelze obnovit z tohoto souboru obrázku","invalidSceneUrl":"Nelze importovat scénu z zadané URL. Je buď poškozená, nebo neobsahuje platná JSON data Excalidraw.","resetLibrary":"Tímto vymažete vaši knihovnu. Jste si jisti?","removeItemsFromsLibrary":"Smazat {{count}} položek z knihovny?","invalidEncryptionKey":"Šifrovací klíč musí mít 22 znaků. Live spolupráce je zakázána.","collabOfflineWarning":"Není k dispozici žádné internetové připojení.\\nVaše změny nebudou uloženy!"},"errors":{"unsupportedFileType":"Nepodporovaný typ souboru.","imageInsertError":"Nelze vložit obrázek. Zkuste to později...","fileTooBig":"Soubor je příliš velký. Maximální povolená velikost je {{maxSize}}.","svgImageInsertError":"Nelze vložit SVG obrázek. Značení SVG je neplatné.","failedToFetchImage":"","invalidSVGString":"Neplatný SVG.","cannotResolveCollabServer":"Nelze se připojit ke sdílenému serveru. Prosím obnovte stránku a zkuste to znovu.","importLibraryError":"Nelze načíst knihovnu","collabSaveFailed":"Nelze uložit do databáze na serveru. Pokud problémy přetrvávají, měli byste uložit soubor lokálně, abyste se ujistili, že neztratíte svou práci.","collabSaveFailed_sizeExceeded":"Nelze uložit do databáze na serveru, plátno se zdá být příliš velké. Měli byste uložit soubor lokálně, abyste se ujistili, že neztratíte svou práci.","brave_measure_text_error":{"line1":"Vypadá to, že používáte Brave prohlížeč s povoleným nastavením Aggressively Block Fingerprinting.","line2":"To by mohlo vést k narušení Textových elementů ve vašich výkresech.","line3":"Důrazně doporučujeme zakázat toto nastavení. Můžete sledovat tyto kroky jak to udělat.","line4":"Pokud vypnutí tohoto nastavení neopravuje zobrazení textových prvků, prosím, otevřete problém na našem GitHubu, nebo nám napište na Discord"},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Výběr","image":"Vložit obrázek","rectangle":"Obdélník","diamond":"Diamant","ellipse":"Elipsa","arrow":"Šipka","line":"Čára","freedraw":"Kreslení","text":"Text","library":"Knihovna","lock":"Po kreslení ponechat vybraný nástroj aktivní","penMode":"Režim Pera - zabránit dotyku","link":"Přidat/aktualizovat odkaz pro vybraný tvar","eraser":"Guma","frame":"","embeddable":"","laser":"","hand":"Ruka (nástroj pro posouvání)","extraTools":""},"headings":{"canvasActions":"Akce plátna","selectedShapeActions":"Akce vybraného tvaru","shapes":"Tvary"},"hints":{"canvasPanning":"Chcete-li přesunout plátno, podržte kolečko nebo mezerník při tažení nebo použijte nástroj Ruka","linearElement":"Kliknutím pro více bodů, táhnutím pro jednu čáru","freeDraw":"Klikněte a táhněte, pro ukončení pusťte","text":"Tip: Text můžete také přidat dvojitým kliknutím kdekoli pomocí nástroje pro výběr","embeddable":"","text_selected":"Dvojklikem nebo stisknutím klávesy ENTER upravíte text","text_editing":"Stiskněte Escape nebo Ctrl/Cmd+ENTER pro dokončení úprav","linearElementMulti":"Klikněte na poslední bod nebo stiskněte Escape anebo Enter pro dokončení","lockAngle":"Úhel můžete omezit podržením SHIFT","resize":"Můžete omezit proporce podržením SHIFT při změně velikosti,\\npodržte ALT pro změnu velikosti od středu","resizeImage":"Můžete volně změnit velikost podržením SHIFT,\\npodržením klávesy ALT změníte velikosti od středu","rotate":"Úhly můžete omezit podržením SHIFT při otáčení","lineEditor_info":"Podržte Ctrl/Cmd a dvakrát klikněte nebo stiskněte Ctrl/Cmd + Enter pro úpravu bodů","lineEditor_pointSelected":"Stisknutím tlačítka Delete odstraňte bod(y),\\nCtrl/Cmd+D pro duplicitu nebo táhnutím pro přesun","lineEditor_nothingSelected":"Vyberte bod, který chcete upravit (podržením klávesy SHIFT vyberete více položek),\\nnebo podržením klávesy Alt a kliknutím přidáte nové body","placeImage":"Kliknutím umístěte obrázek, nebo klepnutím a přetažením ručně nastavíte jeho velikost","publishLibrary":"Publikovat vlastní knihovnu","bindTextToElement":"Stiskněte Enter pro přidání textu","deepBoxSelect":"Podržte Ctrl/Cmd pro hluboký výběr a pro zabránění táhnutí","eraserRevert":"Podržením klávesy Alt vrátíte prvky označené pro smazání","firefox_clipboard_write":"Tato funkce může být povolena nastavením vlajky \\"dom.events.asyncClipboard.clipboardItem\\" na \\"true\\". Chcete-li změnit vlajky prohlížeče ve Firefoxu, navštivte stránku \\"about:config\\".","disableSnapping":""},"canvasError":{"cannotShowPreview":"Náhled nelze zobrazit","canvasTooBig":"Plátno je možná příliš velké.","canvasTooBigTip":"Tip: zkus posunout nejvzdálenější prvky trochu blíže k sobě."},"errorSplash":{"headingMain":"Chyba. Zkuste .","clearCanvasMessage":"Pokud opětovné načtení nefunguje, zkuste .","clearCanvasCaveat":" To povede ke ztrátě dat ","trackedToSentry":"Chyba identifikátoru {{eventId}} byl zaznamenán v našem systému.","openIssueMessage":"Byli jsme velmi opatrní, abychom neuváděli informace o Vaší scéně. Pokud vaše scéna není soukromá, zvažte prosím sledování na našem . Uveďte prosím níže uvedené informace kopírováním a vložením do problému na GitHubu.","sceneContent":"Obsah scény:"},"roomDialog":{"desc_intro":"Můžete pozvat lidi na vaši aktuální scénu ke spolupráci s vámi.","desc_privacy":"Nebojte se, relace používá end-to-end šifrování, takže cokoliv nakreslíte zůstane soukromé. Ani náš server nebude schopen vidět, s čím budete pracovat.","button_startSession":"Zahájit relaci","button_stopSession":"Ukončit relaci","desc_inProgressIntro":"Živá spolupráce právě probíhá.","desc_shareLink":"Sdílejte tento odkaz s každým, s kým chcete spolupracovat:","desc_exitSession":"Zastavením relace se odpojíte od místnosti, ale budete moci pokračovat v práci s touto scénou lokálně. Všimněte si, že to nebude mít vliv na ostatní lidi a budou stále moci spolupracovat na jejich verzi.","shareTitle":"Připojte se k aktivní spolupráci na Excalidraw"},"errorDialog":{"title":"Chyba"},"exportDialog":{"disk_title":"Uložit na disk","disk_details":"Exportovat data scény do souboru, ze kterého můžete importovat později.","disk_button":"Uložit do souboru","link_title":"Odkaz pro sdílení","link_details":"Exportovat jako odkaz pouze pro čtení.","link_button":"Exportovat do odkazu","excalidrawplus_description":"Uložit scénu do vašeho pracovního prostoru Excalidraw+.","excalidrawplus_button":"Exportovat","excalidrawplus_exportError":"Export do Excalidraw+ se v tuto chvíli nezdařil..."},"helpDialog":{"blog":"Přečtěte si náš blog","click":"kliknutí","deepSelect":"Hluboký výběr","deepBoxSelect":"Hluboký výběr uvnitř boxu a zabránění táhnnutí","curvedArrow":"Zakřivená šipka","curvedLine":"Zakřivená čára","documentation":"Dokumentace","doubleClick":"dvojklik","drag":"tažení","editor":"Editor","editLineArrowPoints":"Upravit body linií/šipek","editText":"Upravit text / přidat popis","github":"Našel jsi problém? Nahlaš ho","howto":"Sledujte naše návody","or":"nebo","preventBinding":"Zabránit vázání šipky","tools":"Nástroje","shortcuts":"Klávesové zkratky","textFinish":"Dokončit úpravy (textový editor)","textNewLine":"Přidat nový řádek (textový editor)","title":"Nápověda","view":"Zobrazení","zoomToFit":"Přiblížit na zobrazení všech prvků","zoomToSelection":"Přiblížit na výběr","toggleElementLock":"Zamknout/odemknout výběr","movePageUpDown":"Posunout stránku nahoru/dolů","movePageLeftRight":"Přesunout stránku doleva/doprava"},"clearCanvasDialog":{"title":"Vymazat plátno"},"publishDialog":{"title":"Publikovat knihovnu","itemName":"Název položky","authorName":"Jméno autora","githubUsername":"GitHub uživatelské jméno","twitterUsername":"Twitter uživatelské jméno","libraryName":"Název knihovny","libraryDesc":"Popis knihovny","website":"Webová stránka","placeholder":{"authorName":"Jméno nebo uživatelské jméno","libraryName":"Název vaší knihovny","libraryDesc":"Popis Vaší knihovny, který pomůže lidem pochopit její využití","githubHandle":"Github uživatelské jméno (nepovinné), abyste mohli upravovat knihovnu poté co je odeslána ke kontrole","twitterHandle":"Twitter uživatelské jméno (nepovinné), abychom věděli koho označit při propagaci na Twitteru","website":"Odkaz na Vaši osobní webovou stránku nebo jinam (nepovinné)"},"errors":{"required":"Povinné","website":"Zadejte platnou URL adresu"},"noteDescription":"Odešlete svou knihovnu, pro zařazení do veřejného úložiště knihoven, odkud ji budou moci při kreslení využít i ostatní uživatelé.","noteGuidelines":"Knihovna musí být nejdříve ručně schválena. Přečtěte si prosím pokyny","noteLicense":"Odesláním souhlasíte s tím, že knihovna bude zveřejněna pod MIT licencí, stručně řečeno, kdokoli ji může používat bez omezení.","noteItems":"Každá položka knihovny musí mít svůj vlastní název, aby byla filtrovatelná. Následující položky knihovny budou zahrnuty:","atleastOneLibItem":"Vyberte alespoň jednu položku knihovny, kterou chcete začít","republishWarning":"Poznámka: některé z vybraných položek jsou označeny jako již zveřejněné/odeslané. Položky byste měli znovu odeslat pouze při aktualizaci existující knihovny nebo podání."},"publishSuccessDialog":{"title":"Knihovna byla odeslána","content":"Děkujeme vám {{authorName}}. Vaše knihovna byla odeslána k posouzení. Stav můžete sledovat zde"},"confirmDialog":{"resetLibrary":"Resetovat knihovnu","removeItemsFromLib":"Odstranit vybrané položky z knihovny"},"imageExportDialog":{"header":"Exportovat obrázek","label":{"withBackground":"Pozadí","onlySelected":"Pouze vybrané","darkMode":"Tmavý režim","embedScene":"Vložit scénu","scale":"Měřítko","padding":"Odsazení"},"tooltip":{"embedScene":"Data scény budou uložena do exportovaného souboru PNG/SVG tak, aby z něj mohla být scéna obnovena.\\nZvýší se velikost exportovaného souboru."},"title":{"exportToPng":"Exportovat do PNG","exportToSvg":"Exportovat do SVG","copyPngToClipboard":"Kopírovat PNG do schránky"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Kopírovat do schránky"}},"encrypted":{"tooltip":"Vaše kresby jsou end-to-end šifrované, takže servery Excalidraw je nikdy neuvidí.","link":"Blog příspěvek na end-to-end šifrování v Excalidraw"},"stats":{"angle":"Úhel","element":"Prvek","elements":"Prvky","height":"Výška","scene":"Scéna","selected":"Vybráno","storage":"Úložiště","title":"Statistika pro nerdy","total":"Celkem","version":"Verze","versionCopy":"Kliknutím zkopírujete","versionNotAvailable":"Verze není k dispozici","width":"Šířka"},"toast":{"addedToLibrary":"Přidáno do knihovny","copyStyles":"Styly byly zkopírovány.","copyToClipboard":"Zkopírováno do schránky.","copyToClipboardAsPng":"{{exportSelection}} zkopírován do schránky jako PNG\\n({{exportColorScheme}})","fileSaved":"Soubor byl uložen.","fileSavedToFilename":"Uloženo do {filename}","canvas":"plátno","selection":"výběr","pasteAsSingleElement":"Pomocí {{shortcut}} vložte jako jeden prvek,\\nnebo vložte do existujícího textového editoru","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Průhledná","black":"Černá","white":"Bílá","red":"Červená","pink":"Růžová","grape":"Vínová","violet":"Fialová","gray":"Šedá","blue":"Modrá","cyan":"Azurová","teal":"Modrozelená","green":"Zelená","yellow":"Žlutá","orange":"Oranžová","bronze":"Bronzová"},"welcomeScreen":{"app":{"center_heading":"Všechna vaše data jsou uložena lokálně ve vašem prohlížeči.","center_heading_plus":"Chcete místo toho přejít na Excalidraw+?","menuHint":"Export, nastavení, jazyky, ..."},"defaults":{"menuHint":"Export, nastavení a další...","center_heading":"Diagramy. Vytvořeny. Jednoduše.","toolbarHint":"Vyberte nástroj a začněte kreslit!","helpHint":"Zkratky a pomoc"}},"colorPicker":{"mostUsedCustomColors":"Nejpoužívanější vlastní barvy","colors":"Barvy","shades":"Stíny","hexCode":"Hex kód","noShades":"Pro tuto barvu nejsou k dispozici žádné odstíny"},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/da-DK-json-34a60c9843cecd71376f.js b/public/excalidraw/excalidraw-assets-dev/locales/da-DK-json-34a60c9843cecd71376f.js
new file mode 100644
index 0000000..7bc45d9
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/da-DK-json-34a60c9843cecd71376f.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/da-DK-json"],{
+
+/***/ "../../locales/da-DK.json":
+/*!********************************!*\
+ !*** ../../locales/da-DK.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Indsæt","pasteAsPlaintext":"Indsæt som klartekst","pasteCharts":"Indsæt diagrammer","selectAll":"Marker alle","multiSelect":"Tilføj element til markering","moveCanvas":"Flyt lærred","cut":"Klip","copy":"Kopier","copyAsPng":"Kopier til klippebord som PNG","copyAsSvg":"Kopier til klippebord som SVG","copyText":"Kopiér til udklipsholder som tekst","bringForward":"Flyt fremad","sendToBack":"Placer bagest","bringToFront":"Placer forrest","sendBackward":"Send bagud","delete":"Fjern","copyStyles":"Kopier stil","pasteStyles":"Indsæt stil","stroke":"Linje","background":"Baggrund","fill":"Udfyld","strokeWidth":"Linjebredde","strokeStyle":"Linjeform","strokeStyle_solid":"Solid","strokeStyle_dashed":"Stiplet","strokeStyle_dotted":"Prikket","sloppiness":"Sjuskethed","opacity":"Gennemsigtighed","textAlign":"Tekstjustering","edges":"Kanter","sharp":"Skarp","round":"Rund","arrowheads":"Pilehoveder","arrowhead_none":"Ingen","arrowhead_arrow":"Pil","arrowhead_bar":"Bjælke","arrowhead_dot":"Prik","arrowhead_triangle":"Trekant","fontSize":"Skriftstørrelse","fontFamily":"Skrifttypefamilie","addWatermark":"Tilføj \\"Lavet med Excalidraw\\"","handDrawn":"Hånd-tegnet","normal":"Normal","code":"Kode","small":"Lille","medium":"Mellem","large":"Stor","veryLarge":"Meget stor","solid":"Solid","hachure":"Skravering","zigzag":"Zigzag","crossHatch":"Krydsskravering","thin":"Tynd","bold":"Fed","left":"Venstre","center":"Centrere","right":"Højre","extraBold":"Extra fed","architect":"Arkitekt","artist":"Kunstner","cartoonist":"Tegneserietegner","fileTitle":"Filnavn","colorPicker":"Farvevælger","canvasColors":"Brugt på lærred","canvasBackground":"Lærredsbaggrund","drawingCanvas":"Tegnelærred","layers":"Lag","actions":"Handlinger","language":"Sprog","liveCollaboration":"Live samarbejde...","duplicateSelection":"Duplikér","untitled":"Unavngivet","name":"Navn","yourName":"Dit navn","madeWithExcalidraw":"Fremstillet med Excalidraw","group":"","ungroup":"","collaborators":"","showGrid":"","addToLibrary":"","removeFromLibrary":"","libraryLoadingMessage":"","libraries":"","loadingScene":"","align":"","alignTop":"","alignBottom":"","alignLeft":"","alignRight":"","centerVertically":"","centerHorizontally":"","distributeHorizontally":"","distributeVertically":"","flipHorizontal":"","flipVertical":"","viewMode":"","share":"Del","showStroke":"","showBackground":"","toggleTheme":"","personalLib":"","excalidrawLib":"","decreaseFontSize":"","increaseFontSize":"","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"","editEmbed":"","create":"","createEmbed":"","label":"","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"","unlock":"","lockAll":"","unlockAll":""},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"","exportJSON":"","exportImage":"","export":"","copyToClipboard":"Kopier til klippebord","save":"","saveAs":"Gem som","load":"","getShareableLink":"Lav et delbart link","close":"Luk","selectLanguage":"Vælg sprog","scrollBackToContent":"Scroll tilbage til indhold","zoomIn":"Zoom ind","zoomOut":"Zoom ud","resetZoom":"Nulstil zoom","menu":"Menu","done":"Færdig","edit":"Rediger","undo":"Fortryd","redo":"Gendan","resetLibrary":"Nulstil bibliotek","createNewRoom":"Opret nyt rum","fullScreen":"Fuld skærm","darkMode":"Mørk tilstand","lightMode":"Lys baggrund","zenMode":"Zentilstand","objectsSnapMode":"","exitZenMode":"Stop zentilstand","cancel":"Annuller","clear":"Ryd","remove":"Fjern","embed":"","publishLibrary":"Publicér","submit":"Gem","confirm":"Bekræft","embeddableInteractionButton":""},"alerts":{"clearReset":"Dette vil rydde hele lærredet. Er du sikker?","couldNotCreateShareableLink":"Kunne ikke oprette delbart link.","couldNotCreateShareableLinkTooBig":"Kunne ikke oprette delbart link: scenen er for stor","couldNotLoadInvalidFile":"Kunne ikke indlæse ugyldig fil","importBackendFailed":"Import fra backend mislykkedes.","cannotExportEmptyCanvas":"","couldNotCopyToClipboard":"","decryptFailed":"","uploadedSecurly":"","loadSceneOverridePrompt":"","collabStopOverridePrompt":"","errorAddingToLibrary":"","errorRemovingFromLibrary":"","confirmAddLibrary":"","imageDoesNotContainScene":"","cannotRestoreFromImage":"","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"","invalidEncryptionKey":"","collabOfflineWarning":""},"errors":{"unsupportedFileType":"","imageInsertError":"","fileTooBig":"","svgImageInsertError":"","failedToFetchImage":"","invalidSVGString":"","cannotResolveCollabServer":"","importLibraryError":"","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"","image":"","rectangle":"","diamond":"","ellipse":"","arrow":"","line":"","freedraw":"","text":"","library":"","lock":"","penMode":"","link":"","eraser":"","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"","selectedShapeActions":"","shapes":""},"hints":{"canvasPanning":"","linearElement":"","freeDraw":"Klik og træk, slip når du er færdig","text":"","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"","lockAngle":"","resize":"","resizeImage":"","rotate":"","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"","canvasTooBig":"","canvasTooBigTip":""},"errorSplash":{"headingMain":"","clearCanvasMessage":"","clearCanvasCaveat":"","trackedToSentry":"","openIssueMessage":" Kopiere og indsæt venligst oplysningerne nedenfor i et GitHub problem.","sceneContent":"Scene indhold:"},"roomDialog":{"desc_intro":"Du kan invitere folk til din nuværende scene, så de kan samarbejde med dig.","desc_privacy":"Bare rolig, sessionen bruger end-to-end kryptering, så uanset hvad du tegner vil det forblive privat. Ikke engang vores server vil kunne se, hvad du kommer op med.","button_startSession":"Start session","button_stopSession":"Stop session","desc_inProgressIntro":"Live-samarbejde session er nu begyndt.","desc_shareLink":"Del dette link med enhver, du ønsker at samarbejde med:","desc_exitSession":"","shareTitle":""},"errorDialog":{"title":"Fejl"},"exportDialog":{"disk_title":"Gem til disk","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"","excalidrawplus_exportError":""},"helpDialog":{"blog":"Læs vores blog","click":"","deepSelect":"","deepBoxSelect":"","curvedArrow":"","curvedLine":"","documentation":"","doubleClick":"","drag":"","editor":"","editLineArrowPoints":"","editText":"","github":"","howto":"","or":"","preventBinding":"","tools":"","shortcuts":"","textFinish":"","textNewLine":"","title":"","view":"","zoomToFit":"","zoomToSelection":"","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"","githubUsername":"","twitterUsername":"","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"","link":""},"stats":{"angle":"","element":"","elements":"","height":"","scene":"","selected":"","storage":"","title":"Statistik for nørder","total":"","version":"","versionCopy":"Klik for at kopiere","versionNotAvailable":"","width":"Bredde"},"toast":{"addedToLibrary":"","copyStyles":"Kopieret stilarter.","copyToClipboard":"Kopieret til klippebord.","copyToClipboardAsPng":"Kopieret {{exportSelection}} til klippebord som PNG\\n({{exportColorScheme}})","fileSaved":"Fil gemt.","fileSavedToFilename":"Gemt som {filename}","canvas":"canvas","selection":"markering","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/de-DE-json-d13450595b795867412b.js b/public/excalidraw/excalidraw-assets-dev/locales/de-DE-json-d13450595b795867412b.js
new file mode 100644
index 0000000..d03160b
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/de-DE-json-d13450595b795867412b.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/de-DE-json"],{
+
+/***/ "../../locales/de-DE.json":
+/*!********************************!*\
+ !*** ../../locales/de-DE.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Einfügen","pasteAsPlaintext":"Als reinen Text einfügen","pasteCharts":"Diagramme einfügen","selectAll":"Alle auswählen","multiSelect":"Element zur Auswahl hinzufügen","moveCanvas":"Leinwand verschieben","cut":"Ausschneiden","copy":"Kopieren","copyAsPng":"In Zwischenablage kopieren (PNG)","copyAsSvg":"In Zwischenablage kopieren (SVG)","copyText":"In die Zwischenablage als Text kopieren","bringForward":"Nach vorne","sendToBack":"In den Hintergrund","bringToFront":"In den Vordergrund","sendBackward":"Nach hinten","delete":"Löschen","copyStyles":"Formatierung kopieren","pasteStyles":"Formatierung übernehmen","stroke":"Strich","background":"Hintergrund","fill":"Füllung","strokeWidth":"Strichstärke","strokeStyle":"Konturstil","strokeStyle_solid":"Durchgezogen","strokeStyle_dashed":"Gestrichelt","strokeStyle_dotted":"Gepunktet","sloppiness":"Sauberkeit","opacity":"Deckkraft","textAlign":"Textausrichtung","edges":"Kanten","sharp":"Scharf","round":"Rund","arrowheads":"Pfeilspitzen","arrowhead_none":"Keine","arrowhead_arrow":"Pfeil","arrowhead_bar":"Balken","arrowhead_dot":"Punkt","arrowhead_triangle":"Dreieck","fontSize":"Schriftgröße","fontFamily":"Schriftfamilie","addWatermark":"\\"Made with Excalidraw\\" hinzufügen","handDrawn":"Handgezeichnet","normal":"Normal","code":"Code","small":"Klein","medium":"Mittel","large":"Groß","veryLarge":"Sehr groß","solid":"Deckend","hachure":"Schraffiert","zigzag":"Zickzack","crossHatch":"Kreuzschraffiert","thin":"Dünn","bold":"Fett","left":"Links","center":"Zentriert","right":"Rechts","extraBold":"Extra Fett","architect":"Architekt","artist":"Künstler","cartoonist":"Karikaturist","fileTitle":"Dateiname","colorPicker":"Farbauswähler","canvasColors":"Auf Leinwand verwendet","canvasBackground":"Zeichenflächenhintergrund","drawingCanvas":"Leinwand","layers":"Ebenen","actions":"Aktionen","language":"Sprache","liveCollaboration":"Live-Zusammenarbeit...","duplicateSelection":"Duplizieren","untitled":"Unbenannt","name":"Name","yourName":"Dein Name","madeWithExcalidraw":"Made with Excalidraw","group":"Auswahl gruppieren","ungroup":"Gruppierung aufheben","collaborators":"Mitarbeitende","showGrid":"Raster anzeigen","addToLibrary":"Zur Bibliothek hinzufügen","removeFromLibrary":"Aus Bibliothek entfernen","libraryLoadingMessage":"Lade Bibliothek…","libraries":"Bibliotheken durchsuchen","loadingScene":"Lade Zeichnung…","align":"Ausrichten","alignTop":"Obere Kanten","alignBottom":"Untere Kanten","alignLeft":"Linke Kanten","alignRight":"Rechte Kanten","centerVertically":"Vertikal zentrieren","centerHorizontally":"Horizontal zentrieren","distributeHorizontally":"Horizontal verteilen","distributeVertically":"Vertikal verteilen","flipHorizontal":"Horizontal spiegeln","flipVertical":"Vertikal spiegeln","viewMode":"Ansichtsmodus","share":"Teilen","showStroke":"Auswahl für Strichfarbe anzeigen","showBackground":"Hintergrundfarbe auswählen","toggleTheme":"Design umschalten","personalLib":"Persönliche Bibliothek","excalidrawLib":"Excalidraw Bibliothek","decreaseFontSize":"Schriftgröße verkleinern","increaseFontSize":"Schrift vergrößern","unbindText":"Text lösen","bindText":"Text an Container binden","createContainerFromText":"Text in Container einbetten","link":{"edit":"Link bearbeiten","editEmbed":"Link bearbeiten & einbetten","create":"Link erstellen","createEmbed":"Link erstellen & einbetten","label":"Link","labelEmbed":"Verlinken & einbetten","empty":"Kein Link festgelegt"},"lineEditor":{"edit":"Linie bearbeiten","exit":"Linieneditor verlassen"},"elementLock":{"lock":"Sperren","unlock":"Entsperren","lockAll":"Alle sperren","unlockAll":"Alle entsperren"},"statusPublished":"Veröffentlicht","sidebarLock":"Seitenleiste offen lassen","selectAllElementsInFrame":"Alle Elemente im Rahmen auswählen","removeAllElementsFromFrame":"Alle Elemente aus dem Rahmen entfernen","eyeDropper":"Farbe von der Zeichenfläche auswählen"},"library":{"noItems":"Noch keine Elemente hinzugefügt...","hint_emptyLibrary":"Wähle ein Element auf der Zeichenfläche, um es hier hinzuzufügen. Oder installiere eine Bibliothek aus dem öffentlichen Verzeichnis.","hint_emptyPrivateLibrary":"Wähle ein Element von der Zeichenfläche, um es hier hinzuzufügen."},"buttons":{"clearReset":"Zeichenfläche löschen & Hintergrundfarbe zurücksetzen","exportJSON":"In Datei exportieren","exportImage":"Exportiere Bild...","export":"Speichern als...","copyToClipboard":"In Zwischenablage kopieren","save":"In aktueller Datei speichern","saveAs":"Speichern unter","load":"Öffnen","getShareableLink":"Teilbaren Link erhalten","close":"Schließen","selectLanguage":"Sprache auswählen","scrollBackToContent":"Zurück zum Inhalt","zoomIn":"Vergrößern","zoomOut":"Verkleinern","resetZoom":"Zoom zurücksetzen","menu":"Menü","done":"Fertig","edit":"Bearbeiten","undo":"Rückgängig machen","redo":"Wiederholen","resetLibrary":"Bibliothek zurücksetzen","createNewRoom":"Neuen Raum erstellen","fullScreen":"Vollbildanzeige","darkMode":"Dunkles Design","lightMode":"Helles Design","zenMode":"Zen-Modus","objectsSnapMode":"Einrasten an Objekten","exitZenMode":"Zen-Modus verlassen","cancel":"Abbrechen","clear":"Löschen","remove":"Entfernen","embed":"Einbettung umschalten","publishLibrary":"Veröffentlichen","submit":"Absenden","confirm":"Bestätigen","embeddableInteractionButton":"Klicken, um zu interagieren"},"alerts":{"clearReset":"Dies wird die ganze Zeichenfläche löschen. Bist du dir sicher?","couldNotCreateShareableLink":"Konnte keinen teilbaren Link erstellen.","couldNotCreateShareableLinkTooBig":"Konnte keinen teilbaren Link erstellen: Die Zeichnung ist zu groß","couldNotLoadInvalidFile":"Ungültige Datei konnte nicht geladen werden","importBackendFailed":"Import vom Server ist fehlgeschlagen.","cannotExportEmptyCanvas":"Leere Zeichenfläche kann nicht exportiert werden.","couldNotCopyToClipboard":"Kopieren in die Zwischenablage fehlgeschlagen.","decryptFailed":"Daten konnten nicht entschlüsselt werden.","uploadedSecurly":"Der Upload wurde mit Ende-zu-Ende-Verschlüsselung gespeichert. Weder Excalidraw noch Dritte können den Inhalt einsehen.","loadSceneOverridePrompt":"Das Laden einer externen Zeichnung ersetzt den vorhandenen Inhalt. Möchtest du fortfahren?","collabStopOverridePrompt":"Das Stoppen der Sitzung wird deine vorherige, lokal gespeicherte Zeichnung überschreiben. Bist du dir sicher?\\n\\n(Wenn du deine lokale Zeichnung behalten möchtest, schließe stattdessen den Browser-Tab.)","errorAddingToLibrary":"Das Element konnte nicht zur Bibliothek hinzugefügt werden","errorRemovingFromLibrary":"Das Element konnte nicht aus der Bibliothek entfernt werden","confirmAddLibrary":"Dies fügt {{numShapes}} Form(en) zu deiner Bibliothek hinzu. Bist du dir sicher?","imageDoesNotContainScene":"Dieses Bild scheint keine Szenendaten zu enthalten. Hast Du das Einbetten der Szene während des Exports aktiviert?","cannotRestoreFromImage":"Die Zeichnung konnte aus dieser Bilddatei nicht wiederhergestellt werden","invalidSceneUrl":"Die Szene konnte nicht von der angegebenen URL importiert werden. Sie ist entweder fehlerhaft oder enthält keine gültigen Excalidraw JSON-Daten.","resetLibrary":"Dieses löscht deine Bibliothek. Bist du sicher?","removeItemsFromsLibrary":"{{count}} Element(e) aus der Bibliothek löschen?","invalidEncryptionKey":"Verschlüsselungsschlüssel muss 22 Zeichen lang sein. Die Live-Zusammenarbeit ist deaktiviert.","collabOfflineWarning":"Keine Internetverbindung verfügbar.\\nDeine Änderungen werden nicht gespeichert!"},"errors":{"unsupportedFileType":"Nicht unterstützter Dateityp.","imageInsertError":"Das Bild konnte nicht eingefügt werden. Versuche es später erneut...","fileTooBig":"Die Datei ist zu groß. Die maximal zulässige Größe ist {{maxSize}}.","svgImageInsertError":"SVG-Bild konnte nicht eingefügt werden. Das SVG-Markup sieht ungültig aus.","failedToFetchImage":"Bild konnte nicht abgerufen werden.","invalidSVGString":"Ungültige SVG.","cannotResolveCollabServer":"Konnte keine Verbindung zum Collab-Server herstellen. Bitte lade die Seite neu und versuche es erneut.","importLibraryError":"Bibliothek konnte nicht geladen werden","collabSaveFailed":"Keine Speicherung in der Backend-Datenbank möglich. Wenn die Probleme weiterhin bestehen, solltest Du Deine Datei lokal speichern, um sicherzustellen, dass Du Deine Arbeit nicht verlierst.","collabSaveFailed_sizeExceeded":"Keine Speicherung in der Backend-Datenbank möglich, die Zeichenfläche scheint zu groß zu sein. Du solltest Deine Datei lokal speichern, um sicherzustellen, dass Du Deine Arbeit nicht verlierst.","brave_measure_text_error":{"line1":"Sieht so aus, als ob Du den Brave-Browser verwendest und die aggressive Blockierung von Fingerabdrücken aktiviert hast.","line2":"Dies könnte dazu führen, dass die Textelemente in Ihren Zeichnungen zerstört werden.","line3":"Wir empfehlen dringend, diese Einstellung zu deaktivieren. Dazu kannst Du diesen Schritten folgen.","line4":"Wenn die Deaktivierung dieser Einstellung die fehlerhafte Anzeige von Textelementen nicht behebt, öffne bitte ein Ticket auf unserem GitHub oder schreibe uns auf Discord"},"libraryElementTypeError":{"embeddable":"Einbettbare Elemente können der Bibliothek nicht hinzugefügt werden.","image":"Unterstützung für das Hinzufügen von Bildern in die Bibliothek kommt bald!"}},"toolBar":{"selection":"Auswahl","image":"Bild einfügen","rectangle":"Rechteck","diamond":"Raute","ellipse":"Ellipse","arrow":"Pfeil","line":"Linie","freedraw":"Zeichnen","text":"Text","library":"Bibliothek","lock":"Ausgewähltes Werkzeug nach Zeichnen aktiv lassen","penMode":"Stift-Modus - Berührung verhindern","link":"Link für ausgewählte Form hinzufügen / aktualisieren","eraser":"Radierer","frame":"Rahmenwerkzeug","embeddable":"Web-Einbettung","laser":"Laserpointer","hand":"Hand (Schwenkwerkzeug)","extraTools":"Weitere Werkzeuge"},"headings":{"canvasActions":"Aktionen für Zeichenfläche","selectedShapeActions":"Aktionen für Auswahl","shapes":"Formen"},"hints":{"canvasPanning":"Um die Zeichenfläche zu verschieben, halte das Mausrad oder die Leertaste während des Ziehens, oder verwende das Hand-Werkzeug","linearElement":"Klicken für Linie mit mehreren Punkten, Ziehen für einzelne Linie","freeDraw":"Klicke und ziehe. Lass los, wenn du fertig bist","text":"Tipp: Du kannst auch Text hinzufügen, indem du mit dem Auswahlwerkzeug auf eine beliebige Stelle doppelklickst","embeddable":"Klicken und ziehen, um eine Webseiten-Einbettung zu erstellen","text_selected":"Doppelklicken oder Eingabetaste drücken, um Text zu bearbeiten","text_editing":"Drücke Escape oder CtrlOrCmd+Eingabetaste, um die Bearbeitung abzuschließen","linearElementMulti":"Zum Beenden auf den letzten Punkt klicken oder Escape oder Eingabe drücken","lockAngle":"Du kannst Winkel einschränken, indem du SHIFT gedrückt hältst","resize":"Du kannst die Proportionen einschränken, indem du SHIFT während der Größenänderung gedrückt hältst. Halte ALT gedrückt, um die Größe vom Zentrum aus zu ändern","resizeImage":"Du kannst die Größe frei ändern, indem du SHIFT gedrückt hältst; halte ALT, um die Größe vom Zentrum aus zu ändern","rotate":"Du kannst Winkel einschränken, indem du SHIFT während der Drehung gedrückt hältst","lineEditor_info":"CtrlOrCmd halten und Doppelklick oder CtrlOrCmd + Eingabe drücken, um Punkte zu bearbeiten","lineEditor_pointSelected":"Drücke Löschen, um Punkt(e) zu entfernen, CtrlOrCmd+D zum Duplizieren oder ziehe zum Verschieben","lineEditor_nothingSelected":"Wähle einen zu bearbeitenden Punkt (halte SHIFT gedrückt um mehrere Punkte auszuwählen),\\noder halte Alt gedrückt und klicke um neue Punkte hinzuzufügen","placeImage":"Klicken, um das Bild zu platzieren oder klicken und ziehen um seine Größe manuell zu setzen","publishLibrary":"Veröffentliche deine eigene Bibliothek","bindTextToElement":"Zum Hinzufügen Eingabetaste drücken","deepBoxSelect":"Halte CtrlOrCmd gedrückt, um innerhalb der Gruppe auszuwählen, und um Ziehen zu vermeiden","eraserRevert":"Halte Alt gedrückt, um die zum Löschen markierten Elemente zurückzusetzen","firefox_clipboard_write":"Diese Funktion kann wahrscheinlich aktiviert werden, indem die Einstellung \\"dom.events.asyncClipboard.clipboardItem\\" auf \\"true\\" gesetzt wird. Um die Browsereinstellungen in Firefox zu ändern, besuche die Seite \\"about:config\\".","disableSnapping":"Halte CtrlOrCmd gedrückt, um das Einrasten zu deaktivieren"},"canvasError":{"cannotShowPreview":"Vorschau kann nicht angezeigt werden","canvasTooBig":"Die Leinwand ist möglicherweise zu groß.","canvasTooBigTip":"Tipp: Schiebe die am weitesten entfernten Elemente ein wenig näher zusammen."},"errorSplash":{"headingMain":"Es ist ein Fehler aufgetreten. Versuche ","clearCanvasMessage":"Wenn das Neuladen nicht funktioniert, versuche ","clearCanvasCaveat":" Dies wird zum Verlust von Daten führen ","trackedToSentry":"Der Fehler mit der Kennung {{eventId}} wurde in unserem System registriert.","openIssueMessage":"Wir waren sehr vorsichtig und haben deine Zeichnungsinformationen nicht in die Fehlerinformationen aufgenommen. Wenn deine Zeichnung nicht privat ist, unterstütze uns bitte über unseren . Bitte teile die unten stehenden Informationen mit uns im GitHub Issue (Kopieren und Einfügen).","sceneContent":"Zeichnungsinhalt:"},"roomDialog":{"desc_intro":"Du kannst Leute zu deiner aktuellen Zeichnung einladen um mit ihnen zusammenzuarbeiten.","desc_privacy":"Keine Sorge, die Sitzung nutzt eine Ende-zu-Ende-Verschlüsselung. Alles was du zeichnest, bleibt privat. Auch unser Server sieht nicht, was du dir einfallen lässt.","button_startSession":"Sitzung starten","button_stopSession":"Sitzung beenden","desc_inProgressIntro":"Die Live-Sitzung wird nun ausgeführt.","desc_shareLink":"Teile diesen Link mit allen, mit denen du zusammenarbeiten möchtest:","desc_exitSession":"Wenn du die Sitzung beendest, wird deine Verbindung zum Raum getrennt. Du kannst jedoch lokal weiter an der Zeichnung arbeiten. Beachte, dass dies keine Auswirkungen auf andere hat und diese weiterhin gemeinsam an ihrer Version arbeiten können.","shareTitle":"An einer Live-Kollaborationssitzung auf Excalidraw teilnehmen"},"errorDialog":{"title":"Fehler"},"exportDialog":{"disk_title":"Auf Festplatte speichern","disk_details":"Exportiere die Zeichnungsdaten in eine Datei, die Du später importieren kannst.","disk_button":"Als Datei speichern","link_title":"Teilbarer Link","link_details":"Als schreibgeschützten Link exportieren.","link_button":"Als Link exportieren","excalidrawplus_description":"Speichere die Szene in deinem Excalidraw+ Arbeitsbereich.","excalidrawplus_button":"Exportieren","excalidrawplus_exportError":"Konnte nicht nach Excalidraw+ exportieren..."},"helpDialog":{"blog":"Lies unseren Blog","click":"klicken","deepSelect":"Auswahl innerhalb der Gruppe","deepBoxSelect":"Auswahl innerhalb der Gruppe, und Ziehen vermeiden","curvedArrow":"Gebogener Pfeil","curvedLine":"Gebogene Linie","documentation":"Dokumentation","doubleClick":"doppelklicken","drag":"ziehen","editor":"Editor","editLineArrowPoints":"Linien-/Pfeil-Punkte bearbeiten","editText":"Text bearbeiten / Label hinzufügen","github":"Ein Problem gefunden? Informiere uns","howto":"Folge unseren Anleitungen","or":"oder","preventBinding":"Pfeil-Bindung verhindern","tools":"Werkzeuge","shortcuts":"Tastaturkürzel","textFinish":"Bearbeitung beenden (Texteditor)","textNewLine":"Neue Zeile hinzufügen (Texteditor)","title":"Hilfe","view":"Ansicht","zoomToFit":"Zoomen um alle Elemente einzupassen","zoomToSelection":"Auf Auswahl zoomen","toggleElementLock":"Auswahl sperren/entsperren","movePageUpDown":"Seite nach oben/unten verschieben","movePageLeftRight":"Seite nach links/rechts verschieben"},"clearCanvasDialog":{"title":"Zeichenfläche löschen"},"publishDialog":{"title":"Bibliothek veröffentlichen","itemName":"Elementname","authorName":"Name des Autors","githubUsername":"GitHub-Benutzername","twitterUsername":"Twitter-Benutzername","libraryName":"Name der Bibliothek","libraryDesc":"Beschreibung der Bibliothek","website":"Webseite","placeholder":{"authorName":"Dein Name oder Benutzername","libraryName":"Name deiner Bibliothek","libraryDesc":"Beschreibung deiner Bibliothek, um anderen Nutzern bei der Verwendung zu helfen","githubHandle":"GitHub-Handle (optional), damit du die Bibliothek bearbeiten kannst, wenn sie zur Überprüfung eingereicht wurde","twitterHandle":"Twitter-Benutzername (optional), damit wir wissen, wen wir bei Werbung über Twitter nennen können","website":"Link zu deiner persönlichen Webseite oder zu anderer Seite (optional)"},"errors":{"required":"Erforderlich","website":"Gültige URL eingeben"},"noteDescription":"Sende deine Bibliothek ein, um in die öffentliche Bibliotheks-Repository aufgenommen zu werdendamit andere Nutzer sie in ihren Zeichnungen verwenden können.","noteGuidelines":"Die Bibliothek muss zuerst manuell freigegeben werden. Bitte lies die Richtlinien vor dem Absenden. Du benötigst ein GitHub-Konto, um zu kommunizieren und Änderungen vorzunehmen, falls erforderlich, aber es ist nicht unbedingt erforderlich.","noteLicense":"Mit dem Absenden stimmst du zu, dass die Bibliothek unter der MIT-Lizenz, die zusammengefasst beinhaltet, dass jeder sie ohne Einschränkungen nutzen kann.","noteItems":"Jedes Bibliothekselement muss einen eigenen Namen haben, damit es gefiltert werden kann. Die folgenden Bibliothekselemente werden hinzugefügt:","atleastOneLibItem":"Bitte wähle mindestens ein Bibliothekselement aus, um zu beginnen","republishWarning":"Hinweis: Einige der ausgewählten Elemente sind bereits als veröffentlicht/eingereicht markiert. Du solltest Elemente nur erneut einreichen, wenn Du eine existierende Bibliothek oder Einreichung aktualisierst."},"publishSuccessDialog":{"title":"Bibliothek übermittelt","content":"Vielen Dank {{authorName}}. Deine Bibliothek wurde zur Überprüfung eingereicht. Du kannst den Status verfolgenhier"},"confirmDialog":{"resetLibrary":"Bibliothek zurücksetzen","removeItemsFromLib":"Ausgewählte Elemente aus der Bibliothek entfernen"},"imageExportDialog":{"header":"Bild exportieren","label":{"withBackground":"Hintergrund","onlySelected":"Nur ausgewählte","darkMode":"Dunkler Modus","embedScene":"Szene einbetten","scale":"Skalierung","padding":"Abstand"},"tooltip":{"embedScene":"Die Zeichnungsdaten werden in der exportierten PNG/SVG-Datei gespeichert, sodass das Dokument später weiter bearbeitet werden kann. \\nDieses wird die exportierte Datei vergrößern."},"title":{"exportToPng":"Als PNG exportieren","exportToSvg":"Als SVG exportieren","copyPngToClipboard":"PNG in die Zwischenablage kopieren"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"In Zwischenablage kopieren"}},"encrypted":{"tooltip":"Da deine Zeichnungen Ende-zu-Ende verschlüsselt werden, sehen auch unsere Excalidraw-Server sie niemals.","link":"Blogbeitrag über Ende-zu-Ende-Verschlüsselung in Excalidraw"},"stats":{"angle":"Winkel","element":"Element","elements":"Elemente","height":"Höhe","scene":"Zeichnung","selected":"Ausgewählt","storage":"Speicher","title":"Statistiken für Nerds","total":"Gesamt","version":"Version","versionCopy":"Zum Kopieren klicken","versionNotAvailable":"Version nicht verfügbar","width":"Breite"},"toast":{"addedToLibrary":"Zur Bibliothek hinzugefügt","copyStyles":"Formatierungen kopiert.","copyToClipboard":"In die Zwischenablage kopiert.","copyToClipboardAsPng":"{{exportSelection}} als PNG in die Zwischenablage kopiert\\n({{exportColorScheme}})","fileSaved":"Datei gespeichert.","fileSavedToFilename":"Als {filename} gespeichert","canvas":"Zeichenfläche","selection":"Auswahl","pasteAsSingleElement":"Verwende {{shortcut}} , um als einzelnes Element\\neinzufügen oder in einen existierenden Texteditor einzufügen","unableToEmbed":"Einbetten dieser URL ist derzeit nicht zulässig. Erstelle einen Issue auf GitHub, um die URL freigeben zu lassen","unrecognizedLinkFormat":"Der Link, den Du eingebettet hast, stimmt nicht mit dem erwarteten Format überein. Bitte versuche den \'embed\' String einzufügen, der von der Quellseite zur Verfügung gestellt wird"},"colors":{"transparent":"Transparent","black":"Schwarz","white":"Weiß","red":"Rot","pink":"Pink","grape":"Traube","violet":"Violett","gray":"Grau","blue":"Blau","cyan":"Cyan","teal":"Blaugrün","green":"Grün","yellow":"Gelb","orange":"Orange","bronze":"Bronze"},"welcomeScreen":{"app":{"center_heading":"Alle Daten werden lokal in Deinem Browser gespeichert.","center_heading_plus":"Möchtest du stattdessen zu Excalidraw+ gehen?","menuHint":"Exportieren, Einstellungen, Sprachen, ..."},"defaults":{"menuHint":"Exportieren, Einstellungen und mehr...","center_heading":"Diagramme. Einfach. Gemacht.","toolbarHint":"Wähle ein Werkzeug & beginne zu zeichnen!","helpHint":"Kurzbefehle & Hilfe"}},"colorPicker":{"mostUsedCustomColors":"Beliebteste benutzerdefinierte Farben","colors":"Farben","shades":"Schattierungen","hexCode":"Hex-Code","noShades":"Keine Schattierungen für diese Farbe verfügbar"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Als Bild exportieren","button":"Als Bild exportieren","description":"Exportiere die Zeichnungsdaten als ein Bild, von dem Du später importieren kannst."},"saveToDisk":{"title":"Auf Festplatte speichern","button":"Auf Festplatte speichern","description":"Exportiere die Zeichnungsdaten in eine Datei, von der Du später importieren kannst."},"excalidrawPlus":{"title":"Excalidraw+","button":"Export nach Excalidraw+","description":"Speichere die Szene in deinem Excalidraw+-Arbeitsbereich."}},"modal":{"loadFromFile":{"title":"Aus Datei laden","button":"Aus Datei laden","description":"Das Laden aus einer Datei wird Deinen vorhandenen Inhalt ersetzen. Du kannst Deine Zeichnung zuerst mit einer der folgenden Optionen sichern."},"shareableLink":{"title":"Aus Link laden","button":"Meinen Inhalt ersetzen","description":"Das Laden einer externen Zeichnung wird Deinen vorhandenen Inhalt ersetzen. Du kannst Deine Zeichnung zuerst mit einer der folgenden Optionen sichern."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/el-GR-json-c854b199f3ac07d40294.js b/public/excalidraw/excalidraw-assets-dev/locales/el-GR-json-c854b199f3ac07d40294.js
new file mode 100644
index 0000000..890e140
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/el-GR-json-c854b199f3ac07d40294.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/el-GR-json"],{
+
+/***/ "../../locales/el-GR.json":
+/*!********************************!*\
+ !*** ../../locales/el-GR.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Επικόλληση","pasteAsPlaintext":"Επικόλληση ως απλό κείμενο","pasteCharts":"Επικόλληση γραφημάτων","selectAll":"Επιλογή όλων","multiSelect":"Προσθέστε το στοιχείο στην επιλογή","moveCanvas":"Μετακίνηση καμβά","cut":"Αποκοπή","copy":"Αντιγραφή","copyAsPng":"Αντιγραφή στο πρόχειρο ως PNG","copyAsSvg":"Αντιγραφή στο πρόχειρο ως SVG","copyText":"Αντιγραφή στο πρόχειρο ως κείμενο","bringForward":"Στο προσκήνιο","sendToBack":"Ένα επίπεδο πίσω","bringToFront":"Ένα επίπεδο μπροστά","sendBackward":"Στο παρασκήνιο","delete":"Διαγραφή","copyStyles":"Αντιγραφή εμφάνισης","pasteStyles":"Επικόλληση εμφάνισης","stroke":"Μολυβιά","background":"Φόντο","fill":"Γέμισμα","strokeWidth":"Πάχος μολυβιάς","strokeStyle":"Στυλ περιγράμματος","strokeStyle_solid":"Συμπαγής","strokeStyle_dashed":"Διακεκομμένη με παύλες","strokeStyle_dotted":"Διακεκομμένη με τελείες","sloppiness":"Ακαταστασία","opacity":"Διαφάνεια","textAlign":"Στοίχιση κειμένου","edges":"Άκρες","sharp":"Οξύ","round":"Στρογγυλό","arrowheads":"Σύμβολα βελών","arrowhead_none":"Κανένα","arrowhead_arrow":"Βέλος","arrowhead_bar":"Μπάρα","arrowhead_dot":"Τελεία","arrowhead_triangle":"Τρίγωνο","fontSize":"Μέγεθος γραμματοσειράς","fontFamily":"Γραμματοσειρά","addWatermark":"Προσθήκη \\"Φτιαγμένο με Excalidraw\\"","handDrawn":"Σχεδιασμένο στο χέρι","normal":"Κανονική","code":"Κώδικας","small":"Μικρό","medium":"Μεσαίο","large":"Μεγάλο","veryLarge":"Πολύ μεγάλο","solid":"Συμπαγής","hachure":"Εκκόλαψη","zigzag":"","crossHatch":"Διασταυρούμενη εκκόλαψη","thin":"Λεπτή","bold":"Έντονη","left":"Αριστερά","center":"Κέντρο","right":"Δεξιά","extraBold":"Πολύ έντονη","architect":"Αρχιτέκτονας","artist":"Καλλιτέχνης","cartoonist":"Σκιτσογράφος","fileTitle":"Όνομα αρχείου","colorPicker":"Επιλογή Χρώματος","canvasColors":"Χρησιμοποείται στον καμβά","canvasBackground":"Φόντο καμβά","drawingCanvas":"Σχεδίαση καμβά","layers":"Στρώματα","actions":"Ενέργειες","language":"Γλώσσα","liveCollaboration":"Live συνεργασία...","duplicateSelection":"Δημιουργία αντιγράφου","untitled":"Χωρίς τίτλο","name":"Όνομα","yourName":"Το όνομά σου","madeWithExcalidraw":"Φτιαγμένο με Excalidraw","group":"Δημιουργία ομάδας από επιλογή","ungroup":"Κατάργηση ομάδας από επιλογή","collaborators":"Συνεργάτες","showGrid":"Προβολή πλέγματος","addToLibrary":"Προσθήκη στη βιβλιοθήκη","removeFromLibrary":"Αφαίρεση από τη βιβλιοθήκη","libraryLoadingMessage":"Φόρτωση βιβλιοθήκης…","libraries":"Άλλες βιβλιοθήκες","loadingScene":"Φόρτωση σκηνής…","align":"Στοίχιση","alignTop":"Στοίχιση πάνω","alignBottom":"Στοίχιση κάτω","alignLeft":"Στοίχιση αριστερά","alignRight":"Στοίχιση δεξιά","centerVertically":"Κέντρο κάθετα","centerHorizontally":"Κέντρο οριζόντια","distributeHorizontally":"Οριζόντια κατανομή","distributeVertically":"Κατακόρυφη κατανομή","flipHorizontal":"Οριζόντια αναστροφή","flipVertical":"Κατακόρυφη αναστροφή","viewMode":"Λειτουργία προβολής","share":"Κοινοποίηση","showStroke":"Εμφάνιση επιλογέα χρωμάτων πινελιάς","showBackground":"Εμφάνιση επιλογέα χρώματος φόντου","toggleTheme":"Εναλλαγή θέματος","personalLib":"Προσωπική Βιβλιοθήκη","excalidrawLib":"Βιβλιοθήκη Excalidraw","decreaseFontSize":"Μείωση μεγέθους γραμματοσειράς","increaseFontSize":"Αύξηση μεγέθους γραμματοσειράς","unbindText":"Αποσύνδεση κειμένου","bindText":"Δέσμευση κειμένου στο δοχείο","createContainerFromText":"","link":{"edit":"Επεξεργασία συνδέσμου","editEmbed":"","create":"Δημιουργία συνδέσμου","createEmbed":"","label":"Σύνδεσμος","labelEmbed":"","empty":""},"lineEditor":{"edit":"Επεξεργασία γραμμής","exit":"Έξοδος επεξεργαστή κειμένου"},"elementLock":{"lock":"Κλείδωμα","unlock":"Ξεκλείδωμα","lockAll":"Κλείδωμα όλων","unlockAll":"Ξεκλείδωμα όλων"},"statusPublished":"Δημοσιευμένο","sidebarLock":"Κρατήστε την πλαϊνή μπάρα ανοιχτή","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Δεν έχουν προστεθεί αντικείμενα ακόμη...","hint_emptyLibrary":"Επιλέξτε ένα στοιχείο στον καμβά για να το προσθέσετε εδώ, ή εγκαταστήστε μια βιβλιοθήκη από το δημόσιο αποθετήριο, παρακάτω.","hint_emptyPrivateLibrary":"Επιλέξτε ένα στοιχείο στον καμβά για να το προσθέσετε εδώ."},"buttons":{"clearReset":"Επαναφορά του καμβά","exportJSON":"Εξαγωγή σε αρχείο","exportImage":"Εξαγωγή εικόνας...","export":"Αποθήκευση ως...","copyToClipboard":"Αντιγραφή στο πρόχειρο","save":"Αποθήκευση στο τρέχον αρχείο","saveAs":"Αποθήκευση ως","load":"Άνοιγμα","getShareableLink":"Δημόσιος σύνδεσμος","close":"Κλείσιμο","selectLanguage":"Επιλογή γλώσσας","scrollBackToContent":"Μετακινηθείτε πίσω στο περιεχόμενο","zoomIn":"Μεγέθυνση","zoomOut":"Σμίκρυνση","resetZoom":"Επαναφορά μεγέθυνσης","menu":"Μενού","done":"Τέλος","edit":"Επεξεργασία","undo":"Αναίρεση","redo":"Επαναφορά","resetLibrary":"Καθαρισμός βιβλιοθήκης","createNewRoom":"Δημιουργία νέου χώρου","fullScreen":"Πλήρης οθόνη","darkMode":"Σκοτεινή λειτουργία","lightMode":"Φωτεινή λειτουργία","zenMode":"Λειτουργία Zεν","objectsSnapMode":"","exitZenMode":"Έξοδος από την λειτουργία Zen","cancel":"Ακύρωση","clear":"Καθαρισμός","remove":"Κατάργηση","embed":"","publishLibrary":"Δημοσίευση","submit":"Υποβολή","confirm":"Επιβεβαίωση","embeddableInteractionButton":""},"alerts":{"clearReset":"Αυτό θα σβήσει ολόκληρο τον καμβά. Είσαι σίγουρος;","couldNotCreateShareableLink":"Δεν ήταν δυνατή η δημιουργία συνδέσμου κοινής χρήσης.","couldNotCreateShareableLinkTooBig":"Δεν ήταν δυνατή η δημιουργία κοινόχρηστου συνδέσμου: η σκηνή είναι πολύ μεγάλη","couldNotLoadInvalidFile":"Δεν μπόρεσε να ανοίξει εσφαλμένο αρχείο","importBackendFailed":"Η εισαγωγή από το backend απέτυχε.","cannotExportEmptyCanvas":"Δεν είναι δυνατή η εξαγωγή κενού καμβά.","couldNotCopyToClipboard":"Αδυναμία αντιγραφής στο πρόχειρο.","decryptFailed":"Δεν ήταν δυνατή η αποκρυπτογράφηση δεδομένων.","uploadedSecurly":"Η μεταφόρτωση έχει εξασφαλιστεί με κρυπτογράφηση από άκρο σε άκρο, πράγμα που σημαίνει ότι ο διακομιστής Excalidraw και τρίτα μέρη δεν μπορούν να διαβάσουν το περιεχόμενο.","loadSceneOverridePrompt":"Η φόρτωση εξωτερικού σχεδίου θα αντικαταστήσει το υπάρχον περιεχόμενο. Επιθυμείτε να συνεχίσετε;","collabStopOverridePrompt":"Η διακοπή της συνεδρίας θα αντικαταστήσει το προηγούμενο, τοπικά αποθηκευμένο σχέδιο. Είστε σίγουροι?\\n\\n(Αν θέλετε να διατηρήσετε το τοπικό σας σχέδιο, απλά κλείστε την καρτέλα του προγράμματος περιήγησης.)","errorAddingToLibrary":"Αδυναμία προσθήκης αντικειμένου στη βιβλιοθήκη","errorRemovingFromLibrary":"Αδυναμία αφαίρεσης αντικειμένου από τη βιβλιοθήκη","confirmAddLibrary":"Αυτό θα προσθέσει {{numShapes}} σχήμα(τα) στη βιβλιοθήκη σας. Είστε σίγουροι;","imageDoesNotContainScene":"Αυτή η εικόνα δεν φαίνεται να περιέχει δεδομένα σκηνής. Έχετε ενεργοποιήσει την ενσωμάτωση σκηνής κατά την εξαγωγή;","cannotRestoreFromImage":"Η σκηνή δεν ήταν δυνατό να αποκατασταθεί από αυτό το αρχείο εικόνας","invalidSceneUrl":"Δεν ήταν δυνατή η εισαγωγή σκηνής από το URL που δώσατε. Είτε έχει λάθος μορφή, είτε δεν περιέχει έγκυρα δεδομένα JSON Excalidraw.","resetLibrary":"Αυτό θα καθαρίσει τη βιβλιοθήκη σας. Είστε σίγουροι;","removeItemsFromsLibrary":"Διαγραφή {{count}} αντικειμένου(ων) από τη βιβλιοθήκη;","invalidEncryptionKey":"Το κλειδί κρυπτογράφησης πρέπει να είναι 22 χαρακτήρες. Η ζωντανή συνεργασία είναι απενεργοποιημένη.","collabOfflineWarning":"Δεν υπάρχει διαθέσιμη σύνδεση στο internet.\\nΟι αλλαγές σας δεν θα αποθηκευτούν!"},"errors":{"unsupportedFileType":"Μη υποστηριζόμενος τύπος αρχείου.","imageInsertError":"Αδυναμία εισαγωγής εικόνας. Προσπαθήστε ξανά αργότερα...","fileTooBig":"Το αρχείο είναι πολύ μεγάλο. Το μέγιστο επιτρεπόμενο μέγεθος είναι {{maxSize}}.","svgImageInsertError":"Αδυναμία εισαγωγής εικόνας SVG. Η σήμανση της SVG δεν φαίνεται έγκυρη.","failedToFetchImage":"","invalidSVGString":"Μη έγκυρο SVG.","cannotResolveCollabServer":"Αδυναμία σύνδεσης με τον διακομιστή συνεργασίας. Παρακαλώ ανανεώστε τη σελίδα και προσπαθήστε ξανά.","importLibraryError":"Αδυναμία φόρτωσης βιβλιοθήκης","collabSaveFailed":"Η αποθήκευση στη βάση δεδομένων δεν ήταν δυνατή. Αν το προβλήματα παραμείνει, θα πρέπει να αποθηκεύσετε το αρχείο σας τοπικά για να βεβαιωθείτε ότι δεν χάνετε την εργασία σας.","collabSaveFailed_sizeExceeded":"Η αποθήκευση στη βάση δεδομένων δεν ήταν δυνατή, ο καμβάς φαίνεται να είναι πολύ μεγάλος. Θα πρέπει να αποθηκεύσετε το αρχείο τοπικά για να βεβαιωθείτε ότι δεν θα χάσετε την εργασία σας.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Επιλογή","image":"Εισαγωγή εικόνας","rectangle":"Ορθογώνιο","diamond":"Ρόμβος","ellipse":"Έλλειψη","arrow":"Βέλος","line":"Γραμμή","freedraw":"Σχεδίαση","text":"Κείμενο","library":"Βιβλιοθήκη","lock":"Κράτησε επιλεγμένο το εργαλείο μετά το σχέδιο","penMode":"Λειτουργία μολυβιού - αποτροπή αφής","link":"Προσθήκη/ Ενημέρωση συνδέσμου για ένα επιλεγμένο σχήμα","eraser":"Γόμα","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"Ενέργειες καμβά","selectedShapeActions":"Επιλεγμένες ενέργειες σχήματος","shapes":"Σχήματα"},"hints":{"canvasPanning":"","linearElement":"Κάνε κλικ για να ξεκινήσεις πολλαπλά σημεία, σύρε για μια γραμμή","freeDraw":"Κάντε κλικ και σύρτε, απελευθερώσατε όταν έχετε τελειώσει","text":"Tip: μπορείτε επίσης να προσθέστε κείμενο με διπλό-κλικ οπουδήποτε με το εργαλείο επιλογών","embeddable":"","text_selected":"Κάντε διπλό κλικ ή πατήστε ENTER για να επεξεργαστείτε το κείμενο","text_editing":"Πατήστε Escape ή CtrlOrCmd+ENTER για να ολοκληρώσετε την επεξεργασία","linearElementMulti":"Κάνε κλικ στο τελευταίο σημείο ή πάτησε Escape ή Enter για να τελειώσεις","lockAngle":"Μπορείτε να περιορίσετε τη γωνία κρατώντας πατημένο το SHIFT","resize":"Μπορείς να περιορίσεις τις αναλογίες κρατώντας το SHIFT ενώ αλλάζεις μέγεθος,\\nκράτησε πατημένο το ALT για αλλαγή μεγέθους από το κέντρο","resizeImage":"Μπορείτε να αλλάξετε το μέγεθος ελεύθερα κρατώντας πατημένο το SHIFT,\\nκρατήστε πατημένο το ALT για να αλλάξετε το μέγεθος από το κέντρο","rotate":"Μπορείς να περιορίσεις τις γωνίες κρατώντας πατημένο το πλήκτρο SHIFT κατά την περιστροφή","lineEditor_info":"Κρατήστε πατημένο Ctrl ή Cmd και πατήστε το πλήκτρο Ctrl ή Cmd + Enter για επεξεργασία σημείων","lineEditor_pointSelected":"Πατήστε Διαγραφή για αφαίρεση σημείου(ων),\\nCtrlOrCmd+D για αντιγραφή, ή σύρετε για μετακίνηση","lineEditor_nothingSelected":"Επιλέξτε ένα σημείο για να επεξεργαστείτε (κρατήστε πατημένο το SHIFT για να επιλέξετε πολλαπλά),\\nή κρατήστε πατημένο το Alt και κάντε κλικ για να προσθέσετε νέα σημεία","placeImage":"Κάντε κλικ για να τοποθετήσετε την εικόνα ή κάντε κλικ και σύρετε για να ορίσετε το μέγεθός της χειροκίνητα","publishLibrary":"Δημοσιεύστε τη δική σας βιβλιοθήκη","bindTextToElement":"Πατήστε Enter για προσθήκη κειμένου","deepBoxSelect":"Κρατήστε πατημένο το CtrlOrCmd για να επιλέξετε βαθιά, και να αποτρέψετε τη μεταφορά","eraserRevert":"Κρατήστε πατημένο το Alt για να επαναφέρετε τα στοιχεία που σημειώθηκαν για διαγραφή","firefox_clipboard_write":"Αυτή η επιλογή μπορεί πιθανώς να ενεργοποιηθεί αλλάζοντας την ρύθμιση \\"dom.events.asyncClipboard.clipboardItem\\" σε \\"true\\". Για να αλλάξετε τις ρυθμίσεις του προγράμματος περιήγησης στο Firefox, επισκεφθείτε τη σελίδα \\"about:config\\".","disableSnapping":""},"canvasError":{"cannotShowPreview":"Αδυναμία εμφάνισης προεπισκόπησης","canvasTooBig":"Ο καμβάς μπορεί να είναι μεγάλος.","canvasTooBigTip":"Συμβουλή: προσπαθήστε να μετακινήσετε τα πιο απομακρυσμένα στοιχεία λίγο πιο κοντά μαζί."},"errorSplash":{"headingMain":"Συνέβη κάποιο σφάλμα. Προσπάθησε ","clearCanvasMessage":"Εάν το παραπάνω δεν δουλέψει, προσπάθησε ","clearCanvasCaveat":" Αυτό θα προκαλέσει απώλεια της δουλειάς σου ","trackedToSentry":"Το σφάλμα με αναγνωριστικό {{eventId}} παρακολουθήθηκε στο σύστημά μας.","openIssueMessage":"Ήμασταν πολύ προσεκτικοί για να μην συμπεριλάβουμε τις πληροφορίες της σκηνής σου στο σφάλμα. Αν η σκηνή σου δεν είναι ιδιωτική, παρακαλώ σκέψου να ακολουθήσεις το δικό μας Παρακαλώ να συμπεριλάβετε τις παρακάτω πληροφορίες, αντιγράφοντας και επικολλώντας το ζήτημα στο GitHub.","sceneContent":"Περιεχόμενο σκηνής:"},"roomDialog":{"desc_intro":"Μπορείς να προσκαλέσεις άλλους να δουλέψουν μαζί σου.","desc_privacy":"Μην ανησυχείς, η συνεδρία χρησιμοποιεί κρυπτογράφηση από σημείο σε σημείο, άρα οτιδήποτε κάνεις θα παραμείνει ανοιχτό μόνο σε εσένα. Ούτε οι μηχανές μας μπορούν να δουν τι κάνεις.","button_startSession":"Έναρξη Συνεδρίας","button_stopSession":"Τερματισμός Συνεδρίας","desc_inProgressIntro":"Η ζωντανή συνεργασία με άλλους είναι σε ενεργή.","desc_shareLink":"Μοιραστείτε τον σύνδεσμο με όποιον θέλετε να δουλέψετε μαζί:","desc_exitSession":"Η διακοπή θα σας αποσυνδέσει από το δωμάτιο, αλλά θα μπορείτε να συνεχίσετε να δουλεύετε στον πίνακα, τοπικά. Σημειώσατε ότι αυτό δεν θα επηρεάσει τον πίνακα άλλων, και θα μπορούν ακόμα να συνεισφέρουν στην δική τους έκδοση.","shareTitle":"Συμμετάσχετε σε μια ζωντανή συνεδρία συνεργασίας για το Excalidraw"},"errorDialog":{"title":"Σφάλμα"},"exportDialog":{"disk_title":"Αποθήκευση στο δίσκο","disk_details":"Εξαγωγή δεδομένων σκηνής σε ένα αρχείο από το οποίο μπορείτε να εισάγετε αργότερα.","disk_button":"Αποθήκευση σε αρχείο","link_title":"Κοινόχρηστος σύνδεσμος","link_details":"Εξαγωγή ως σύνδεσμο μόνο για ανάγνωση.","link_button":"Εξαγωγή σε Σύνδεση","excalidrawplus_description":"Αποθηκεύστε τη σκηνή στο χώρο εργασίας σας Excalidraw+.","excalidrawplus_button":"Εξαγωγή","excalidrawplus_exportError":"Δεν ήταν δυνατή η εξαγωγή στο Excalidraw+ αυτή τη στιγμή..."},"helpDialog":{"blog":"Διαβάστε το Blog μας","click":"κλικ","deepSelect":"Βαθιά επιλογή","deepBoxSelect":"Βαθιά επιλογή μέσα στο πλαίσιο και αποτροπή συρσίματος","curvedArrow":"Κυρτό βέλος","curvedLine":"Κυρτή γραμμή","documentation":"Εγχειρίδιο","doubleClick":"διπλό κλικ","drag":"σύρε","editor":"Επεξεργαστής","editLineArrowPoints":"","editText":"","github":"Βρήκατε πρόβλημα; Υποβάλετε το","howto":"Ακολουθήστε τους οδηγούς μας","or":"ή","preventBinding":"Αποτροπή δέσμευσης βέλων","tools":"Εργαλεία","shortcuts":"Συντομεύσεις πληκτρολογίου","textFinish":"Ολοκλήρωση επεξεργασίας (επεξεργαστής κειμένου)","textNewLine":"Προσθήκη νέας γραμμής (επεξεργαστής κειμένου)","title":"Βοήθεια","view":"Προβολή","zoomToFit":"Zoom ώστε να χωρέσουν όλα τα στοιχεία","zoomToSelection":"Ζουμ στην επιλογή","toggleElementLock":"Κλείδωμα/Ξεκλείδωμα επιλογής","movePageUpDown":"Μετακίνηση σελίδας πάνω/κάτω","movePageLeftRight":"Μετακίνηση σελίδας αριστερά/δεξιά"},"clearCanvasDialog":{"title":"Καθαρισμός καμβά"},"publishDialog":{"title":"Δημοσίευση βιβλιοθήκης","itemName":"Όνομα αντικειμένου","authorName":"Όνομα δημιουργού","githubUsername":"GitHub username","twitterUsername":"Twitter username","libraryName":"Όνομα βιβλιοθήκης","libraryDesc":"Περιγραφή βιβλιοθήκης","website":"Ιστοσελίδα","placeholder":{"authorName":"Όνομα ή όνομα χρήστη","libraryName":"Όνομα της βιβλιοθήκης σας","libraryDesc":"Περιγραφή της βιβλιοθήκης σας ώστε να βοηθήσει το κοινό να κατανοήσει τη χρήση της","githubHandle":"Όνομα χρήστη στο GitHub (προαιρετικό), ώστε να μπορείτε να επεξεργαστείτε τη βιβλιοθήκη αφού υποβληθεί για αξιολόγηση","twitterHandle":"Όνομα χρήστη Twitter (προαιρετικό), ώστε να γνωρίζουμε σε ποιον/η να δώσουμε εύσημα κατά την προώθηση μέσω Twitter","website":"Σύνδεσμος για την προσωπική σας ιστοσελίδα ή αλλού (προαιρετικό)"},"errors":{"required":"Απαιτείται","website":"Εισάγετε μια έγκυρη διεύθυνση URL"},"noteDescription":"Υποβάλετε τη βιβλιοθήκη σας για να συμπεριληφθεί στο δημόσιο αποθετήριο βιβλιοθήκηςώστε να χρησιμοποιηθεί από άλλα άτομα στα σχέδιά τους.","noteGuidelines":"Η βιβλιοθήκη πρέπει πρώτα να εγκριθεί χειροκίνητα. Παρακαλώ διαβάστε τους οδηγίες πριν την υποβολή. Θα χρειαστείτε έναν λογαριασμό GitHub για την επικοινωνία και για να προβείτε σε αλλαγές εφ\' όσον χρειαστεί, αλλά δεν είναι αυστηρή απαίτηση.","noteLicense":"Με την υποβολή, συμφωνείτε ότι η βιβλιοθήκη θα δημοσιευθεί υπό την Άδεια MIT, που εν συντομία σημαίνει ότι ο καθένας μπορεί να τα χρησιμοποιήσει χωρίς περιορισμούς.","noteItems":"Κάθε αντικείμενο της βιβλιοθήκης πρέπει να έχει το δικό του όνομα ώστε να μπορεί να φιλτραριστεί. Θα συμπεριληφθούν τα ακόλουθα αντικείμενα βιβλιοθήκης:","atleastOneLibItem":"Παρακαλώ επιλέξτε τουλάχιστον ένα αντικείμενο βιβλιοθήκης για να ξεκινήσετε","republishWarning":"Σημείωση: μερικά από τα επιλεγμένα αντικέιμενα έχουν ήδη επισημανθεί ως δημοσιευμένα/υποβεβλημένα. Θα πρέπει να υποβάλετε αντικείμενα εκ νέου μόνο για να ενημερώσετε μία ήδη υπάρχουσα βιβλιοθήκη ή υποβολή."},"publishSuccessDialog":{"title":"Η βιβλιοθήκη υποβλήθηκε","content":"Ευχαριστούμε {{authorName}}. Η βιβλιοθήκη σας έχει υποβληθεί για αξιολόγηση. Μπορείτε να παρακολουθείτε τη διαδικασίαεδώ"},"confirmDialog":{"resetLibrary":"Καθαρισμός βιβλιοθήκης","removeItemsFromLib":"Αφαίρεση επιλεγμένων αντικειμένων από τη βιβλιοθήκη"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"Τα σχέδιά σου είναι κρυπτογραφημένα από άκρο σε άκρο, έτσι δεν θα είναι ποτέ ορατά μέσα από τους διακομιστές του Excalidraw.","link":"Blog post στην κρυπτογράφηση end-to-end στο Excalidraw"},"stats":{"angle":"Γωνία","element":"Στοιχείο","elements":"Στοιχεία","height":"Ύψος","scene":"Σκηνή","selected":"Επιλεγμένα","storage":"Χώρος","title":"Στατιστικά για σπασίκλες","total":"Σύνολο ","version":"Έκδοση","versionCopy":"Κάνε κλικ για αντιγραφή","versionNotAvailable":"Έκδοση μη διαθέσιμη","width":"Πλάτος"},"toast":{"addedToLibrary":"Προστέθηκε στη βιβλιοθήκη","copyStyles":"Αντιγράφηκαν στυλ.","copyToClipboard":"Αντιγράφηκε στο πρόχειρο.","copyToClipboardAsPng":"Αντιγράφηκε {{exportSelection}} στο πρόχειρο ως PNG\\n({{exportColorScheme}})","fileSaved":"Το αρχείο αποθηκεύτηκε.","fileSavedToFilename":"Αποθηκεύτηκε στο {filename}","canvas":"καμβάς","selection":"επιλογή","pasteAsSingleElement":"Χρησιμοποίησε το {{shortcut}} για να επικολλήσεις ως ένα μόνο στοιχείο,\\nή να επικολλήσεις σε έναν υπάρχοντα επεξεργαστή κειμένου","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Διαφανές","black":"Μαύρο","white":"Λευκό","red":"Κόκκινο","pink":"Ροζ","grape":"Σταφυλί","violet":"Βιολετί","gray":"Γκρι","blue":"Μπλε","cyan":"Κυανό","teal":"Τιρκουάζ","green":"Πράσινο","yellow":"Κίτρινο","orange":"Πορτοκαλί","bronze":"Χαλκινο"},"welcomeScreen":{"app":{"center_heading":"Όλα τα δεδομένα σας αποθηκεύονται τοπικά στο πρόγραμμα περιήγησης.","center_heading_plus":"Μήπως θέλατε να πάτε στο Excalidraw+;","menuHint":"Εξαγωγή, προτιμήσεις, γλώσσες, ..."},"defaults":{"menuHint":"Εξαγωγή, προτιμήσεις και άλλες επιλογές...","center_heading":"Διαγράμματα. Εύκολα. Γρήγορα.","toolbarHint":"Επιλέξτε ένα εργαλείο και ξεκινήστε να σχεδιάζεται!","helpHint":"Συντομεύσεις και βοήθεια"}},"colorPicker":{"mostUsedCustomColors":"Πιο χρησιμοποιούμενα χρώματα","colors":"Χρώματα","shades":"Αποχρώσεις","hexCode":"Κωδικός Hex","noShades":"Δεν υπάρχουν διαθέσιμες αποχρώσεις για αυτό το χρώμα"},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/es-ES-json-6a667bfbf4ff3d0181a7.js b/public/excalidraw/excalidraw-assets-dev/locales/es-ES-json-6a667bfbf4ff3d0181a7.js
new file mode 100644
index 0000000..062aac9
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/es-ES-json-6a667bfbf4ff3d0181a7.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/es-ES-json"],{
+
+/***/ "../../locales/es-ES.json":
+/*!********************************!*\
+ !*** ../../locales/es-ES.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Pegar","pasteAsPlaintext":"Pegar como texto sin formato","pasteCharts":"Pegar gráficos","selectAll":"Seleccionar todo","multiSelect":"Añadir elemento a la selección","moveCanvas":"Mover el lienzo","cut":"Cortar","copy":"Copiar","copyAsPng":"Copiar al portapapeles como PNG","copyAsSvg":"Copiar al portapapeles como SVG","copyText":"Copiar al portapapeles como texto","bringForward":"Traer hacia delante","sendToBack":"Enviar al fondo","bringToFront":"Traer al frente","sendBackward":"Enviar atrás","delete":"Borrar","copyStyles":"Copiar estilos","pasteStyles":"Pegar estilos","stroke":"Trazo","background":"Fondo","fill":"Rellenar","strokeWidth":"Grosor del trazo","strokeStyle":"Estilo del trazo","strokeStyle_solid":"Sólido","strokeStyle_dashed":"Discontinua","strokeStyle_dotted":"Punteado","sloppiness":"Estilo de trazo","opacity":"Opacidad","textAlign":"Alineado de texto","edges":"Bordes","sharp":"Afilado","round":"Redondo","arrowheads":"Puntas de flecha","arrowhead_none":"Ninguna","arrowhead_arrow":"Flecha","arrowhead_bar":"Barra","arrowhead_dot":"Punto","arrowhead_triangle":"Triángulo","fontSize":"Tamaño de la fuente","fontFamily":"Tipo de fuente","addWatermark":"Agregar \\"Hecho con Excalidraw\\"","handDrawn":"Dibujado a mano","normal":"Normal","code":"Código","small":"Pequeña","medium":"Mediana","large":"Grande","veryLarge":"Muy grande","solid":"Sólido","hachure":"Folleto","zigzag":"Zigzag","crossHatch":"Rayado transversal","thin":"Fino","bold":"Grueso","left":"Izquierda","center":"Centrado","right":"Derecha","extraBold":"Extra negrita","architect":"Arquitecto","artist":"Artista","cartoonist":"Caricatura","fileTitle":"Nombre del archivo","colorPicker":"Selector de color","canvasColors":"Usado en lienzo","canvasBackground":"Fondo del lienzo","drawingCanvas":"Lienzo de dibujo","layers":"Capas","actions":"Acciones","language":"Idioma","liveCollaboration":"Colaboración en directo...","duplicateSelection":"Duplicar","untitled":"Sin título","name":"Nombre","yourName":"Tu nombre","madeWithExcalidraw":"Hecho con Excalidraw","group":"Agrupar selección","ungroup":"Desagrupar selección","collaborators":"Colaboradores","showGrid":"Mostrar cuadrícula","addToLibrary":"Añadir a la biblioteca","removeFromLibrary":"Eliminar de la biblioteca","libraryLoadingMessage":"Cargando biblioteca…","libraries":"Explorar bibliotecas","loadingScene":"Cargando escena…","align":"Alinear","alignTop":"Alineación superior","alignBottom":"Alineación inferior","alignLeft":"Alinear a la izquierda","alignRight":"Alinear a la derecha","centerVertically":"Centrar verticalmente","centerHorizontally":"Centrar horizontalmente","distributeHorizontally":"Distribuir horizontalmente","distributeVertically":"Distribuir verticalmente","flipHorizontal":"Girar horizontalmente","flipVertical":"Girar verticalmente","viewMode":"Modo presentación","share":"Compartir","showStroke":"Mostrar selector de color de trazo","showBackground":"Mostrar el selector de color de fondo","toggleTheme":"Cambiar tema","personalLib":"Biblioteca personal","excalidrawLib":"Biblioteca Excalidraw","decreaseFontSize":"Disminuir tamaño de letra","increaseFontSize":"Aumentar el tamaño de letra","unbindText":"Desvincular texto","bindText":"Vincular texto al contenedor","createContainerFromText":"Envolver el texto en un contenedor","link":{"edit":"Editar enlace","editEmbed":"Editar enlace e incrustar","create":"Crear enlace","createEmbed":"Crear enlace e incrustar","label":"Enlace","labelEmbed":"Enlazar e incrustar","empty":"No se ha establecido un enlace"},"lineEditor":{"edit":"Editar línea","exit":"Salir del editor en línea"},"elementLock":{"lock":"Bloquear","unlock":"Desbloquear","lockAll":"Bloquear todo","unlockAll":"Desbloquear todo"},"statusPublished":"Publicado","sidebarLock":"Mantener barra lateral abierta","selectAllElementsInFrame":"Seleccionar todos los elementos en el marco","removeAllElementsFromFrame":"Eliminar todos los elementos del marco","eyeDropper":"Seleccionar un color del lienzo"},"library":{"noItems":"No hay elementos añadidos todavía...","hint_emptyLibrary":"Seleccione un elemento en el lienzo para añadirlo aquí, o instale una biblioteca del repositorio público, a continuación.","hint_emptyPrivateLibrary":"Seleccione un elemento del lienzo para añadirlo aquí."},"buttons":{"clearReset":"Limpiar lienzo y reiniciar el color de fondo","exportJSON":"Exportar a archivo","exportImage":"Exportar imagen...","export":"Guardar en...","copyToClipboard":"Copiar al portapapeles","save":"Guardar en archivo actual","saveAs":"Guardar como","load":"Abrir","getShareableLink":"Obtener enlace para compartir","close":"Cerrar","selectLanguage":"Elegir idioma","scrollBackToContent":"Volver al contenido","zoomIn":"Acercarse","zoomOut":"Alejarse","resetZoom":"Restablecer zoom","menu":"Menú","done":"Hecho","edit":"Editar","undo":"Deshacer","redo":"Rehacer","resetLibrary":"Reiniciar biblioteca","createNewRoom":"Crear nueva sala","fullScreen":"Pantalla completa","darkMode":"Modo oscuro","lightMode":"Modo claro","zenMode":"Modo Zen","objectsSnapMode":"Ajustar a los objetos","exitZenMode":"Salir del modo Zen","cancel":"Cancelar","clear":"Borrar","remove":"Eliminar","embed":"","publishLibrary":"Publicar","submit":"Enviar","confirm":"Confirmar","embeddableInteractionButton":"Pulsa para interactuar"},"alerts":{"clearReset":"Esto limpiará todo el lienzo. Estás seguro?","couldNotCreateShareableLink":"No se pudo crear un enlace para compartir.","couldNotCreateShareableLinkTooBig":"No se pudo crear el enlace para compartir: la escena es demasiado grande","couldNotLoadInvalidFile":"No se pudo cargar el archivo no válido","importBackendFailed":"La importación falló.","cannotExportEmptyCanvas":"No se puede exportar un lienzo vació","couldNotCopyToClipboard":"No se pudo copiar al portapapeles.","decryptFailed":"No se pudieron descifrar los datos.","uploadedSecurly":"La carga ha sido asegurada con cifrado de principio a fin, lo que significa que el servidor de Excalidraw y terceros no pueden leer el contenido.","loadSceneOverridePrompt":"Si carga este dibujo externo, reemplazará el que tiene. ¿Desea continuar?","collabStopOverridePrompt":"Detener la sesión sobrescribirá su dibujo anterior almacenado localmente. ¿Está seguro?\\n\\n(Si desea mantener su dibujo local, simplemente cierre la pestaña del navegador.)","errorAddingToLibrary":"No se pudo agregar el elemento a la biblioteca","errorRemovingFromLibrary":"No se pudo quitar el elemento de la biblioteca","confirmAddLibrary":"Esto añadirá {{numShapes}} forma(s) a tu biblioteca. ¿Estás seguro?","imageDoesNotContainScene":"Esta imagen no parece contener datos de escena. ¿Ha habilitado la inserción de la escena durante la exportación?","cannotRestoreFromImage":"No se pudo restaurar la escena desde este archivo de imagen","invalidSceneUrl":"No se ha podido importar la escena desde la URL proporcionada. Está mal formada, o no contiene datos de Excalidraw JSON válidos.","resetLibrary":"Esto borrará tu biblioteca. ¿Estás seguro?","removeItemsFromsLibrary":"¿Eliminar {{count}} elemento(s) de la biblioteca?","invalidEncryptionKey":"La clave de cifrado debe tener 22 caracteres. La colaboración en vivo está deshabilitada.","collabOfflineWarning":"No hay conexión a internet disponible.\\n¡No se guardarán los cambios!"},"errors":{"unsupportedFileType":"Tipo de archivo no admitido.","imageInsertError":"No se pudo insertar la imagen. Inténtelo de nuevo más tarde...","fileTooBig":"Archivo demasiado grande. El tamaño máximo permitido es {{maxSize}}.","svgImageInsertError":"No se pudo insertar la imagen SVG. El código SVG parece inválido.","failedToFetchImage":"","invalidSVGString":"SVG no válido.","cannotResolveCollabServer":"No se pudo conectar al servidor colaborador. Por favor, vuelva a cargar la página y vuelva a intentarlo.","importLibraryError":"No se pudo cargar la librería","collabSaveFailed":"No se pudo guardar en la base de datos del backend. Si los problemas persisten, debería guardar su archivo localmente para asegurarse de que no pierde su trabajo.","collabSaveFailed_sizeExceeded":"No se pudo guardar en la base de datos del backend, el lienzo parece ser demasiado grande. Debería guardar el archivo localmente para asegurarse de que no pierde su trabajo.","brave_measure_text_error":{"line1":"Parece que estás usando el navegador Brave con el ajuste Forzar el bloqueo de huellas digitales habilitado.","line2":"Esto podría resultar en errores en los Elementos de Texto en tus dibujos.","line3":"Recomendamos fuertemente deshabilitar esta configuración. Puedes seguir estos pasos sobre cómo hacerlo.","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Selección","image":"Insertar imagen","rectangle":"Rectángulo","diamond":"Diamante","ellipse":"Elipse","arrow":"Flecha","line":"Línea","freedraw":"Dibujar","text":"Texto","library":"Biblioteca","lock":"Mantener la herramienta seleccionada activa después de dibujar","penMode":"Modo Lápiz - previene toque","link":"Añadir/Actualizar enlace para una forma seleccionada","eraser":"Borrar","frame":"","embeddable":"Incrustar Web","laser":"Puntero láser","hand":"Mano (herramienta de panoramización)","extraTools":"Más herramientas"},"headings":{"canvasActions":"Acciones del lienzo","selectedShapeActions":"Acciones de la forma seleccionada","shapes":"Formas"},"hints":{"canvasPanning":"Para mover el lienzo, mantenga la rueda del ratón o la barra espaciadora mientras arrastra o utilice la herramienta de mano","linearElement":"Haz clic para dibujar múltiples puntos, arrastrar para solo una línea","freeDraw":"Haz clic y arrastra, suelta al terminar","text":"Consejo: también puedes añadir texto haciendo doble clic en cualquier lugar con la herramienta de selección","embeddable":"Haga clic y arrastre para crear un sitio web incrustado","text_selected":"Doble clic o pulse ENTER para editar el texto","text_editing":"Pulse Escape o Ctrl/Cmd + ENTER para terminar de editar","linearElementMulti":"Haz clic en el último punto o presiona Escape o Enter para finalizar","lockAngle":"Puedes restringir el ángulo manteniendo presionado el botón SHIFT","resize":"Para mantener las proporciones mantén SHIFT presionado mientras modificas el tamaño, \\nmantén presionado ALT para modificar el tamaño desde el centro","resizeImage":"Puede redimensionar libremente pulsando SHIFT,\\npulse ALT para redimensionar desde el centro","rotate":"Puedes restringir los ángulos manteniendo presionado SHIFT mientras giras","lineEditor_info":"Mantenga pulsado CtrlOrCmd y haga doble click o presione CtrlOrCmd + Enter para editar puntos","lineEditor_pointSelected":"Presione Suprimir para eliminar el/los punto(s), CtrlOrCmd+D para duplicarlo, o arrástrelo para moverlo","lineEditor_nothingSelected":"Seleccione un punto a editar (mantenga MAYÚSCULAS para seleccionar múltiples),\\no mantenga pulsado Alt y haga click para añadir nuevos puntos","placeImage":"Haga clic para colocar la imagen o haga click y arrastre para establecer su tamaño manualmente","publishLibrary":"Publica tu propia biblioteca","bindTextToElement":"Presione Entrar para agregar","deepBoxSelect":"Mantén CtrlOrCmd para seleccionar en profundidad, y para evitar arrastrar","eraserRevert":"Mantenga pulsado Alt para revertir los elementos marcados para su eliminación","firefox_clipboard_write":"Esta característica puede ser habilitada estableciendo la bandera \\"dom.events.asyncClipboard.clipboardItem\\" a \\"true\\". Para cambiar las banderas del navegador en Firefox, visite la página \\"about:config\\".","disableSnapping":"Mantén pulsado CtrlOrCmd para desactivar el ajuste"},"canvasError":{"cannotShowPreview":"No se puede mostrar la vista previa","canvasTooBig":"El lienzo podría ser demasiado grande.","canvasTooBigTip":"Sugerencia: intenta acercar un poco más los elementos más lejanos."},"errorSplash":{"headingMain":"Se encontró un error. Intente ","clearCanvasMessage":"Si la recarga no funciona, intente ","clearCanvasCaveat":" Esto provocará la pérdida de su trabajo ","trackedToSentry":"El error con el identificador {{eventId}} fue rastreado en nuestro sistema.","openIssueMessage":"Fuimos muy cautelosos de no incluir la información de tu escena en el error. Si tu escena no es privada, por favor considera seguir nuestro Por favor, incluya la siguiente información copiándola y pegándola en el issue de GitHub.","sceneContent":"Contenido de la escena:"},"roomDialog":{"desc_intro":"Puede invitar a otras personas a tu actual escena para que colaboren contigo.","desc_privacy":"No te preocupes, la sesión usa encriptación de punta a punta, por lo que todo lo que se dibuje se mantendrá privadamente. Ni siquiera nuestro servidor podrá ver lo que haces.","button_startSession":"Iniciar sesión","button_stopSession":"Detener sesión","desc_inProgressIntro":"La sesión de colaboración en vivo está ahora en progreso.","desc_shareLink":"Comparte este enlace con cualquier persona con quien quieras colaborar:","desc_exitSession":"Detener la sesión te desconectará de la sala, pero podrás seguir trabajando con la escena en su computadora, esto es de modo local. Ten en cuenta que esto no afectará a otras personas, y que las mismas seguirán siendo capaces de colaborar en tu escena.","shareTitle":"Únase a una sesión colaborativa en vivo en Excalidraw"},"errorDialog":{"title":"Error"},"exportDialog":{"disk_title":"Guardar en disco","disk_details":"Exportar los datos de la escena a un archivo desde el cual pueda importar más tarde.","disk_button":"Guardar en archivo","link_title":"Enlace para compartir","link_details":"Exportar como enlace de sólo lectura.","link_button":"Exportar a Link","excalidrawplus_description":"Guarde la escena en su espacio de trabajo de Excalidraw+.","excalidrawplus_button":"Exportar","excalidrawplus_exportError":"No se pudo exportar a Excalidraw+ en este momento..."},"helpDialog":{"blog":"Lea nuestro blog","click":"click","deepSelect":"Selección profunda","deepBoxSelect":"Seleccione en profundidad dentro de la caja, y evite arrastrar","curvedArrow":"Flecha curva","curvedLine":"Línea curva","documentation":"Documentación","doubleClick":"doble clic","drag":"arrastrar","editor":"Editor","editLineArrowPoints":"Editar puntos de línea/flecha","editText":"Editar texto / añadir etiqueta","github":"¿Ha encontrado un problema? Envíelo","howto":"Siga nuestras guías","or":"o","preventBinding":"Evitar enlace de flechas","tools":"Herramientas","shortcuts":"Atajos del teclado","textFinish":"Finalizar edición (editor de texto)","textNewLine":"Añadir nueva linea (editor de texto)","title":"Ayuda","view":"Vista","zoomToFit":"Ajustar la vista para mostrar todos los elementos","zoomToSelection":"Ampliar selección","toggleElementLock":"Bloquear/desbloquear selección","movePageUpDown":"Mover página hacia arriba/abajo","movePageLeftRight":"Mover página hacia la izquierda/derecha"},"clearCanvasDialog":{"title":"Borrar lienzo"},"publishDialog":{"title":"Publicar biblioteca","itemName":"Nombre del artículo","authorName":"Nombre del autor","githubUsername":"Nombre de usuario de GitHub","twitterUsername":"Nombre de usuario de Twitter","libraryName":"Nombre de la biblioteca","libraryDesc":"Descripción de la biblioteca","website":"Sitio Web","placeholder":{"authorName":"Nombre o nombre de usuario","libraryName":"Nombre de tu biblioteca","libraryDesc":"Descripción de su biblioteca para ayudar a la gente a entender su uso","githubHandle":"Nombre de usuario de GitHub (opcional), así podrá editar la biblioteca una vez enviada para su revisión","twitterHandle":"Nombre de usuario de Twitter (opcional), así sabemos a quién acreditar cuando se promociona en Twitter","website":"Enlace a su sitio web personal o en cualquier otro lugar (opcional)"},"errors":{"required":"Requerido","website":"Introduce una URL válida"},"noteDescription":"Envía tu biblioteca para ser incluida en el repositorio de librería públicapara que otras personas utilicen en sus dibujos.","noteGuidelines":"La biblioteca debe ser aprobada manualmente primero. Por favor, lea la pautas antes de enviar. Necesitará una cuenta de GitHub para comunicarse y hacer cambios si se solicita, pero no es estrictamente necesario.","noteLicense":"Al enviar, usted acepta que la biblioteca se publicará bajo el Licencia MIT que en breve significa que cualquiera puede utilizarlos sin restricciones.","noteItems":"Cada elemento de la biblioteca debe tener su propio nombre para que sea filtrable. Los siguientes elementos de la biblioteca serán incluidos:","atleastOneLibItem":"Por favor, seleccione al menos un elemento de la biblioteca para empezar","republishWarning":"Nota: algunos de los elementos seleccionados están marcados como ya publicados/enviados. Sólo debería volver a enviar elementos cuando se actualice una biblioteca o envío."},"publishSuccessDialog":{"title":"Biblioteca enviada","content":"Gracias {{authorName}}. Su biblioteca ha sido enviada para ser revisada. Puede seguir el estadoaquí"},"confirmDialog":{"resetLibrary":"Reiniciar biblioteca","removeItemsFromLib":"Eliminar elementos seleccionados de la biblioteca"},"imageExportDialog":{"header":"Exportar imagen","label":{"withBackground":"Fondo","onlySelected":"Sólo seleccionados","darkMode":"Modo oscuro","embedScene":"Incrustar escena","scale":"Escalar","padding":"Espaciado"},"tooltip":{"embedScene":""},"title":{"exportToPng":"Exportar a PNG","exportToSvg":"Exportar a SVG","copyPngToClipboard":"Copiar PNG al portapapeles"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Copiar al portapapeles"}},"encrypted":{"tooltip":"Tus dibujos están cifrados de punto a punto, por lo que los servidores de Excalidraw nunca los verán.","link":"Entrada en el blog sobre cifrado de extremo a extremo"},"stats":{"angle":"Ángulo","element":"Elemento","elements":"Elementos","height":"Alto","scene":"Escena","selected":"Seleccionado","storage":"Almacenamiento","title":"Estadísticas para nerds","total":"Total","version":"Versión","versionCopy":"Click para copiar","versionNotAvailable":"Versión no disponible","width":"Ancho"},"toast":{"addedToLibrary":"Añadido a la biblioteca","copyStyles":"Estilos copiados.","copyToClipboard":"Copiado en el portapapeles.","copyToClipboardAsPng":"Copiado {{exportSelection}} al portapapeles como PNG\\n({{exportColorScheme}})","fileSaved":"Archivo guardado.","fileSavedToFilename":"Guardado en {filename}","canvas":"lienzo","selection":"selección","pasteAsSingleElement":"Usa {{shortcut}} para pegar como un solo elemento,\\no pegar en un editor de texto existente","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Transparente","black":"Negro","white":"Blanco","red":"Rojo","pink":"Rosa","grape":"Uva","violet":"Violeta","gray":"Gris","blue":"Azul","cyan":"Cian","teal":"Turquesa","green":"Verde","yellow":"Amarillo","orange":"Naranja","bronze":"Bronce"},"welcomeScreen":{"app":{"center_heading":"Toda su información es guardada localmente en su navegador.","center_heading_plus":"¿Quieres ir a Excalidraw+?","menuHint":"Exportar, preferencias, idiomas, ..."},"defaults":{"menuHint":"Exportar, preferencias y más...","center_heading":"Diagramas. Hecho. Simplemente.","toolbarHint":"¡Elige una herramienta y empieza a dibujar!","helpHint":"Atajos y ayuda"}},"colorPicker":{"mostUsedCustomColors":"Colores personalizados más utilizados","colors":"Colores","shades":"","hexCode":"Código Hexadecimal","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"Exportar como imagen","button":"Exportar como imagen","description":""},"saveToDisk":{"title":"Guardar en el disco","button":"Guardar en el disco","description":"Exporta los datos de la escena a un archivo desde el cual podrás importar más tarde."},"excalidrawPlus":{"title":"","button":"Exportar a Excalidraw+","description":""}},"modal":{"loadFromFile":{"title":"Cargar desde un archivo","button":"Cargar desde un archivo","description":""},"shareableLink":{"title":"Cargar desde un enlace","button":"Reemplazar mi contenido","description":"Cargar un dibujo externo reemplazará tu contenido existente. Puedes primero hacer una copia de seguridad de tu dibujo usando una de las opciones de abajo."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/eu-ES-json-3ec11367a80491b09056.js b/public/excalidraw/excalidraw-assets-dev/locales/eu-ES-json-3ec11367a80491b09056.js
new file mode 100644
index 0000000..66635e9
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/eu-ES-json-3ec11367a80491b09056.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/eu-ES-json"],{
+
+/***/ "../../locales/eu-ES.json":
+/*!********************************!*\
+ !*** ../../locales/eu-ES.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Itsatsi","pasteAsPlaintext":"Itsatsi testu arrunt gisa","pasteCharts":"Itsatsi grafikoak","selectAll":"Hautatu dena","multiSelect":"Gehitu elementua hautapenera","moveCanvas":"Mugitu oihala","cut":"Ebaki","copy":"Kopiatu","copyAsPng":"Kopiatu arbelera PNG gisa","copyAsSvg":"Kopiatu arbelera SVG gisa","copyText":"Kopiatu arbelera testu gisa","bringForward":"Ekarri aurrerago","sendToBack":"Eraman atzera","bringToFront":"Ekarri aurrera","sendBackward":"Eraman atzerago","delete":"Ezabatu","copyStyles":"Kopiatu estiloak","pasteStyles":"Itsatsi estiloak","stroke":"Marra","background":"Atzeko planoa","fill":"Bete","strokeWidth":"Marraren zabalera","strokeStyle":"Marraren estiloa","strokeStyle_solid":"Solidoa","strokeStyle_dashed":"Marratua","strokeStyle_dotted":"Puntukatua","sloppiness":"Marraren trazoa","opacity":"Opakotasuna","textAlign":"Testuaren lerrokapena","edges":"Ertzak","sharp":"Ertz bizia","round":"Borobildua","arrowheads":"Gezi-puntak","arrowhead_none":"Bat ere ez","arrowhead_arrow":"Gezia","arrowhead_bar":"Barra","arrowhead_dot":"Puntua","arrowhead_triangle":"Hirukia","fontSize":"Letra-tamaina","fontFamily":"Letra-tipoa","addWatermark":"Gehitu \\"Excalidraw bidez egina\\"","handDrawn":"Eskuz marraztua","normal":"Normala","code":"Kodea","small":"Txikia","medium":"Ertaina","large":"Handia","veryLarge":"Oso handia","solid":"Solidoa","hachure":"Itzalduna","zigzag":"Sigi-saga","crossHatch":"Marraduna","thin":"Mehea","bold":"Lodia","left":"Ezkerrean","center":"Erdian","right":"Eskuinean","extraBold":"Oso lodia","architect":"Arkitektoa","artist":"Artista","cartoonist":"Marrazkilaria","fileTitle":"Fitxategi izena","colorPicker":"Kolore-hautatzailea","canvasColors":"Oihalean erabilita","canvasBackground":"Oihalaren atzeko planoa","drawingCanvas":"Marrazteko oihala","layers":"Geruzak","actions":"Ekintzak","language":"Hizkuntza","liveCollaboration":"Zuzeneko elkarlana...","duplicateSelection":"Bikoiztu","untitled":"Izengabea","name":"Izena","yourName":"Zure izena","madeWithExcalidraw":"Excalidraw bidez egina","group":"Hautapena taldea bihurtu","ungroup":"Desegin hautapenaren taldea","collaborators":"Kolaboratzaileak","showGrid":"Erakutsi sareta","addToLibrary":"Gehitu liburutegira","removeFromLibrary":"Kendu liburutegitik","libraryLoadingMessage":"Liburutegia kargatzen…","libraries":"Arakatu liburutegiak","loadingScene":"Eszena kargatzen…","align":"Lerrokatu","alignTop":"Lerrokatu goian","alignBottom":"Lerrokatu behean","alignLeft":"Lerrokatu ezkerrean","alignRight":"Lerrokatu eskuinean","centerVertically":"Erdiratu bertikalki","centerHorizontally":"Erdiratu horizontalki","distributeHorizontally":"Banandu horizontalki","distributeVertically":"Banandu bertikalki","flipHorizontal":"Irauli horizontalki","flipVertical":"Irauli bertikalki","viewMode":"Ikuspegia","share":"Partekatu","showStroke":"Erakutsi marraren kolore-hautatzailea","showBackground":"Erakutsi atzeko planoaren kolore-hautatzailea","toggleTheme":"Aldatu gaia","personalLib":"Liburutegi pertsonala","excalidrawLib":"Excalidraw liburutegia","decreaseFontSize":"Txikitu letra tamaina","increaseFontSize":"Handitu letra tamaina","unbindText":"Askatu testua","bindText":"Lotu testua edukiontziari","createContainerFromText":"Bilatu testua edukiontzi batean","link":{"edit":"Editatu esteka","editEmbed":"Editatu esteka eta kapsulatu","create":"Sortu esteka","createEmbed":"Sortu esteka eta kapsulatu","label":"Esteka","labelEmbed":"Esteka eta kapsula","empty":"Ez da estekarik ezarri"},"lineEditor":{"edit":"Editatu lerroa","exit":"Irten lerro-editoretik"},"elementLock":{"lock":"Blokeatu","unlock":"Desblokeatu","lockAll":"Blokeatu guztiak","unlockAll":"Desblokeatu guztiak"},"statusPublished":"Argitaratua","sidebarLock":"Mantendu alboko barra irekita","selectAllElementsInFrame":"Hautatu markoko elementu guztiak","removeAllElementsFromFrame":"Kendu markoko elementu guztiak","eyeDropper":"Aukeratu kolorea oihaletik"},"library":{"noItems":"Oraindik ez da elementurik gehitu...","hint_emptyLibrary":"Hautatu oihaleko elementu bat hemen gehitzeko, edo instalatu liburutegi bat beheko biltegi publikotik.","hint_emptyPrivateLibrary":"Hautatu oihaleko elementu bat hemen gehitzeko."},"buttons":{"clearReset":"Garbitu oihala","exportJSON":"Esportatu fitxategira","exportImage":"Esportatu irudia...","export":"Gorde hemen...","copyToClipboard":"Kopiatu arbelera","save":"Gorde uneko fitxategian","saveAs":"Gorde honela","load":"Ireki","getShareableLink":"Lortu partekatzeko esteka","close":"Itxi","selectLanguage":"Hautatu hizkuntza","scrollBackToContent":"Joan atzera edukira","zoomIn":"Handiagotu","zoomOut":"Txikiagotu","resetZoom":"Leheneratu zooma","menu":"Menua","done":"Egina","edit":"Editatu","undo":"Desegin","redo":"Berregin","resetLibrary":"Leheneratu liburutegia","createNewRoom":"Sortu gela berria","fullScreen":"Pantaila osoa","darkMode":"Modu iluna","lightMode":"Modu argia","zenMode":"Zen modua","objectsSnapMode":"Atxiki objektuei","exitZenMode":"Irten Zen modutik","cancel":"Utzi","clear":"Garbitu","remove":"Kendu","embed":"Aldatu kapsulatzea","publishLibrary":"Argitaratu","submit":"Bidali","confirm":"Bai","embeddableInteractionButton":"Egin klik elkar eragiteko"},"alerts":{"clearReset":"Honek oihal osoa garbituko du. Ziur zaude?","couldNotCreateShareableLink":"Ezin izan da partekatzeko estekarik sortu.","couldNotCreateShareableLinkTooBig":"Ezin izan da partekatzeko estekarik sortu: eszena handiegia da","couldNotLoadInvalidFile":"Ezin izan da kargatu, fitxategiak ez du balio","importBackendFailed":"Inportazioak huts egin du.","cannotExportEmptyCanvas":"Ezin izan da oihal hutsa esportatu.","couldNotCopyToClipboard":"Ezin izan da arbelean kopiatu.","decryptFailed":"Ezin izan da deszifratu.","uploadedSecurly":"Kargatzea muturretik muturrerako zifratze bidez ziurtatu da, hau da, Excalidraw zerbitzariak eta hirugarrenek ezin dutela edukia irakurri.","loadSceneOverridePrompt":"Kanpoko marrazkia kargatzeak lehendik duzun edukia ordezkatuko du. Jarraitu nahi duzu?","collabStopOverridePrompt":"Saioa gelditzeak lokalean gordetako zure aurreko marrazkia gainidatziko du. Ziur zaude?\\n\\n(Zure marrazki lokala mantendu nahi baduzu, itxi arakatzailearen fitxa.)","errorAddingToLibrary":"Ezin izan da elementua liburutegian gehitu","errorRemovingFromLibrary":"Ezin izan da elementua liburutegitik kendu","confirmAddLibrary":"Honek {{numShapes}} forma gehituko ditu zure liburutegian. Ziur zaude?","imageDoesNotContainScene":"Irudi honek ez dirudi eszena daturik duenik. Eszena kapsulatzea gaitu al duzu esportazioan?","cannotRestoreFromImage":"Ezin izan da eszena leheneratu irudi fitxategi honetatik","invalidSceneUrl":"Ezin izan da eszena inportatu emandako URLtik. Gaizki eratuta dago edo ez du baliozko Excalidraw JSON daturik.","resetLibrary":"Honek zure liburutegia garbituko du. Ziur zaude?","removeItemsFromsLibrary":"Liburutegitik {{count}} elementu ezabatu?","invalidEncryptionKey":"Enkriptazio-gakoak 22 karaktere izan behar ditu. Zuzeneko lankidetza desgaituta dago.","collabOfflineWarning":"Ez dago Interneteko konexiorik.\\nZure aldaketak ez dira gordeko!"},"errors":{"unsupportedFileType":"Onartu gabeko fitxategi mota.","imageInsertError":"Ezin izan da irudia txertatu. Saiatu berriro geroago...","fileTooBig":"Fitxategia handiegia da. Onartutako gehienezko tamaina {{maxSize}} da.","svgImageInsertError":"Ezin izan da SVG irudia txertatu. SVG markak baliogabea dirudi.","failedToFetchImage":"","invalidSVGString":"SVG baliogabea.","cannotResolveCollabServer":"Ezin izan da elkarlaneko zerbitzarira konektatu. Mesedez, berriro kargatu orria eta saiatu berriro.","importLibraryError":"Ezin izan da liburutegia kargatu","collabSaveFailed":"Ezin izan da backend datu-basean gorde. Arazoak jarraitzen badu, zure fitxategia lokalean gorde beharko zenuke zure lana ez duzula galtzen ziurtatzeko.","collabSaveFailed_sizeExceeded":"Ezin izan da backend datu-basean gorde, ohiala handiegia dela dirudi. Fitxategia lokalean gorde beharko zenuke zure lana galtzen ez duzula ziurtatzeko.","brave_measure_text_error":{"line1":"Brave arakatzailea erabiltzen ari zarela dirudi Blokeatu hatz-markak erasokorki ezarpena gaituta.","line2":"Honek zure marrazkietako Testu-elementuak hautsi ditzake.","line3":"Ezarpen hau desgaitzea gomendatzen dugu. urrats hauek jarrai ditzakezu hori nola egin jakiteko.","line4":"Ezarpen hau desgaituz gero, testu-elementuen bistaratzea konpontzen ez bada, ireki arazo gure GitHub-en edo idatzi iezaguzu Discord helbidera"},"libraryElementTypeError":{"embeddable":"Kapsulatutako elementuak ezin dira liburutegira gehitu.","image":"Laster egongo da irudiak liburutegian gehitzeko laguntza!"}},"toolBar":{"selection":"Hautapena","image":"Txertatu irudia","rectangle":"Laukizuzena","diamond":"Diamantea","ellipse":"Elipsea","arrow":"Gezia","line":"Lerroa","freedraw":"Marraztu","text":"Testua","library":"Liburutegia","lock":"Mantendu aktibo hautatutako tresna marraztu ondoren","penMode":"Luma modua - ukipena saihestu","link":"Gehitu / Eguneratu esteka hautatutako forma baterako","eraser":"Borragoma","frame":"Marko tresna","embeddable":"Web kapsulatzea","laser":"Laser punteroa","hand":"Eskua (panoratze tresna)","extraTools":"Tresna gehiago"},"headings":{"canvasActions":"Canvas ekintzak","selectedShapeActions":"Hautatutako formaren ekintzak","shapes":"Formak"},"hints":{"canvasPanning":"Oihala mugitzeko, eutsi saguaren gurpila edo zuriune-barra arrastatzean, edo erabili esku tresna","linearElement":"Egin klik hainbat puntu hasteko, arrastatu lerro bakarrerako","freeDraw":"Egin klik eta arrastatu, askatu amaitutakoan","text":"Aholkua: testua gehitu dezakezu edozein lekutan klik bikoitza eginez hautapen tresnarekin","embeddable":"Egin klik eta arrastatu webgunea kapsulatzeko","text_selected":"Egin klik bikoitza edo sakatu SARTU testua editatzeko","text_editing":"Sakatu Esc edo Ctrl+SARTU editatzen amaitzeko","linearElementMulti":"Egin klik azken puntuan edo sakatu Esc edo Sartu amaitzeko","lockAngle":"SHIFT sakatuta angelua mantendu dezakezu","resize":"Proportzioak mantendu ditzakezu SHIFT sakatuta tamaina aldatzen duzun bitartean.\\nsakatu ALT erditik tamaina aldatzeko","resizeImage":"Tamaina libreki alda dezakezu SHIFT sakatuta,\\nsakatu ALT erditik tamaina aldatzeko","rotate":"Angeluak mantendu ditzakezu SHIFT sakatuta biratzen duzun bitartean","lineEditor_info":"Eutsi sakatuta Ctrl edo Cmd eta egin klik bikoitza edo sakatu Ctrl edo Cmd + Sartu puntuak editatzeko","lineEditor_pointSelected":"Sakatu Ezabatu puntuak kentzeko,\\nKtrl+D bikoizteko, edo arrastatu mugitzeko","lineEditor_nothingSelected":"Hautatu editatzeko puntu bat (SHIFT sakatuta anitz hautatzeko),\\nedo eduki Alt sakatuta eta egin klik puntu berriak gehitzeko","placeImage":"Egin klik irudia kokatzeko, edo egin klik eta arrastatu bere tamaina eskuz ezartzeko","publishLibrary":"Argitaratu zure liburutegia","bindTextToElement":"Sakatu Sartu testua gehitzeko","deepBoxSelect":"Eutsi Ctrl edo Cmd sakatuta aukeraketa sakona egiteko eta arrastatzea saihesteko","eraserRevert":"Eduki Alt sakatuta ezabatzeko markatutako elementuak leheneratzeko","firefox_clipboard_write":"Ezaugarri hau \\"dom.events.asyncClipboard.clipboardItem\\" marka \\"true\\" gisa ezarrita gaitu daiteke. Firefox-en arakatzailearen banderak aldatzeko, bisitatu \\"about:config\\" orrialdera.","disableSnapping":"Eduki sakatuta Ctrl edo Cmd tekla atxikipena desgaitzeko"},"canvasError":{"cannotShowPreview":"Ezin da oihala aurreikusi","canvasTooBig":"Agian oihala handiegia da.","canvasTooBigTip":"Aholkua: saiatu urrunen dauden elementuak pixka bat hurbiltzen."},"errorSplash":{"headingMain":"Errore bat aurkitu da. Saiatu ","clearCanvasMessage":"Birkargatzea ez bada burutzen, saiatu ","clearCanvasCaveat":" Honen ondorioz lana galduko da ","trackedToSentry":"Identifikatzailearen errorea {{eventId}} gure sistemak behatu du.","openIssueMessage":"Oso kontuz ibili gara zure eszenaren informazioa errorean ez sartzeko. Zure eszena pribatua ez bada, kontuan hartu gure Sartu beheko informazioa kopiatu eta itsatsi bidez GitHub issue-n.","sceneContent":"Eszenaren edukia:"},"roomDialog":{"desc_intro":"Jendea zure uneko eszenara gonbida dezakezu zurekin elkarlanean aritzeko.","desc_privacy":"Ez kezkatu, saioak muturretik muturrerako enkriptatzea erabiltzen du, beraz, marrazten duzuna pribatua izango da. Gure zerbitzariak ere ezingo du ikusi zer egiten duzun.","button_startSession":"Hasi saioa","button_stopSession":"Itxi saioa","desc_inProgressIntro":"Zuzeneko lankidetza saioa abian da.","desc_shareLink":"Partekatu esteka hau elkarlanean aritu nahi duzun edonorekin:","desc_exitSession":"Saioa ixteak aretotik deskonektatuko zaitu, baina eszenarekin lanean jarraitu ahal izango duzu lokalean. Kontuan izan honek ez diela beste pertsonei eragingo, eta euren bertsioan elkarlanean aritu ahal izango dira.","shareTitle":"Sartu Excalidraw-en zuzeneko lankidetza-saio batean"},"errorDialog":{"title":"Errorea"},"exportDialog":{"disk_title":"Gorde diskoan","disk_details":"Esportatu eszenaren datuak geroago inportatu ahal izango duzun fitxategi batan.","disk_button":"Gorde fitxategian","link_title":"Partekatzeko esteka","link_details":"Esportatu irakurtzeko soilik moduko esteka.","link_button":"Esportatu esteka","excalidrawplus_description":"Gorde eszena zure Excalidraw+ laneko areara.","excalidrawplus_button":"Esportatu","excalidrawplus_exportError":"Une honetan ezin izan da esportatu Excalidraw+era..."},"helpDialog":{"blog":"Irakurri gure bloga","click":"sakatu","deepSelect":"Hautapen sakona","deepBoxSelect":"Hautapen sakona egin laukizuzen bidez, eta saihestu arrastatzea","curvedArrow":"Gezi kurbatua","curvedLine":"Lerro kurbatua","documentation":"Dokumentazioa","doubleClick":"klik bikoitza","drag":"arrastatu","editor":"Editorea","editLineArrowPoints":"Editatu lerroak/gezi-puntuak","editText":"Editatu testua / gehitu etiketa","github":"Arazorik izan al duzu? Eman horren berri","howto":"Jarraitu gure gidak","or":"edo","preventBinding":"Saihestu gezien gainjartzea","tools":"Tresnak","shortcuts":"Laster-teklak","textFinish":"Bukatu edizioa (testu editorea)","textNewLine":"Gehitu lerro berri bat (testu editorea)","title":"Laguntza","view":"Bistaratu","zoomToFit":"Egin zoom elementu guztiak ikusteko","zoomToSelection":"Zooma hautapenera","toggleElementLock":"Blokeatu/desbloketatu hautapena","movePageUpDown":"Mugitu orria gora/behera","movePageLeftRight":"Mugitu orria ezker/eskuin"},"clearCanvasDialog":{"title":"Garbitu oihala"},"publishDialog":{"title":"Argitaratu liburutegia","itemName":"Elementuaren izena","authorName":"Egilearen izena","githubUsername":"GitHub-eko erabiltzaile-izena","twitterUsername":"Twitter-eko erabiltzaile-izena","libraryName":"Liburutegiaren izena","libraryDesc":"Liburutegiaren deskripzioa","website":"Webgunea","placeholder":{"authorName":"Zure izena edo erabiltzaile-izena","libraryName":"Zure liburutegiaren izena","libraryDesc":"Zure liburutegiaren deskripzioa laguntzeko jendeari ulertzen haren erabilpena","githubHandle":"GitHub heldulekua (aukerakoa), liburutegia editatu ahal izateko berrikustera bidalitakoan","twitterHandle":"Twitter-eko erabiltzaile-izena (aukerakoa), badakigu nori kreditatu behar dugun Twitter bidez sustatzeko","website":"Estekatu zure webgunera edo nahi duzun tokira (aukerakoa)"},"errors":{"required":"Beharrezkoa","website":"Sartu baliozko URL bat"},"noteDescription":"Bidali zure liburutegira sartu ahal izateko zure liburutegiko biltegianbeste jendeak bere marrazkietan erabili ahal izateko.","noteGuidelines":"Liburutegia eskuz onartu behar da. Irakurri gidalerroak bidali aurretik. GitHub kontu bat edukitzea komeni da komunikatzeko eta aldaketak egin ahal izateko, baina ez da guztiz beharrezkoa.","noteLicense":"Bidaltzen baduzu, onartzen duzu liburutegia MIT lizentziarekin argitaratuko dela, zeinak, laburbilduz, esan nahi du edozeinek erabiltzen ahal duela murrizketarik gabe.","noteItems":"Liburutegiko elementu bakoitzak bere izena eduki behar du iragazi ahal izateko. Liburutegiko hurrengo elementuak barne daude:","atleastOneLibItem":"Hautatu gutxienez liburutegiko elementu bat gutxienez hasi ahal izateko","republishWarning":"Oharra: hautatutako elementu batzuk dagoeneko argitaratuta/bidalita bezala markatuta daude. Elementuak berriro bidali behar dituzu lehendik dagoen liburutegi edo bidalketa eguneratzen duzunean."},"publishSuccessDialog":{"title":"Liburutegia bidali da","content":"Eskerrik asko {{authorName}}. Zure liburutegia bidali da berrikustera. Jarraitu dezakezu haren egoerahemen"},"confirmDialog":{"resetLibrary":"Leheneratu liburutegia","removeItemsFromLib":"Kendu hautatutako elementuak liburutegitik"},"imageExportDialog":{"header":"Esportatu irudia","label":{"withBackground":"Atzeko planoa","onlySelected":"Hautapena soilik","darkMode":"Modu iluna","embedScene":"Txertatu eszena","scale":"Eskala","padding":"Betegarria"},"tooltip":{"embedScene":"Eszenaren datuak esportatutako PNG/SVG fitxategian gordeko dira, eszena bertatik berrezartzeko.\\nEsportatutako fitxategien tamaina handituko da."},"title":{"exportToPng":"Esportatu PNG gisa","exportToSvg":"Esportatu SVG gisa","copyPngToClipboard":"Kopiatu PNG arbelera"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Kopiatu arbelean"}},"encrypted":{"tooltip":"Zure marrazkiak muturretik muturrera enkriptatu dira, beraz Excalidraw-ren zerbitzariek ezingo dituzte ikusi.","link":"Excalidraw-ren muturretik muturrerako enkriptatzearen gaineko mezua blogean"},"stats":{"angle":"Angelua","element":"Elementua","elements":"Elementuak","height":"Altuera","scene":"Eszena","selected":"Hautatua","storage":"Biltegia","title":"Datuak","total":"Guztira","version":"Bertsioa","versionCopy":"Klikatu kopiatzeko","versionNotAvailable":"Bertsio ez eskuragarria","width":"Zabalera"},"toast":{"addedToLibrary":"Liburutegira gehitu da","copyStyles":"Estiloak kopiatu dira.","copyToClipboard":"Arbelean kopiatu da.","copyToClipboardAsPng":"{{exportSelection}} kopiatu da arbelean PNG gisa\\n({{exportColorScheme}})","fileSaved":"Fitxategia gorde da.","fileSavedToFilename":"{filename}-n gorde da","canvas":"oihala","selection":"hautapena","pasteAsSingleElement":"Erabili {{shortcut}} elementu bakar gisa itsasteko,\\nedo itsatsi lehendik dagoen testu-editore batean","unableToEmbed":"Url hau txertatzea ez da une honetan onartzen. Sortu issue bat GitHub-en Urla zerrenda zurian sartzea eskatzeko","unrecognizedLinkFormat":"Kapsulatu duzun esteka ez dator bat espero den formatuarekin. Mesedez, saiatu iturburu-guneak emandako \'kapsulatu\' katea itsasten"},"colors":{"transparent":"Gardena","black":"Beltza","white":"Zuria","red":"Gorria","pink":"Arrosa","grape":"Mahats kolorea","violet":"Bioleta","gray":"Grisa","blue":"Urdina","cyan":"Ziana","teal":"Berde urdinxka","green":"Berdea","yellow":"Horia","orange":"Laranja","bronze":"Brontzea"},"welcomeScreen":{"app":{"center_heading":"Zure datu guztiak lokalean gordetzen dira zure nabigatzailean.","center_heading_plus":"Horren ordez Excalidraw+-era joan nahi al zenuen?","menuHint":"Esportatu, hobespenak, hizkuntzak..."},"defaults":{"menuHint":"Esportatu, hobespenak eta gehiago...","center_heading":"Diagramak. Egina. Sinplea.","toolbarHint":"Aukeratu tresna bat eta hasi marrazten!","helpHint":"Lasterbideak eta laguntza"}},"colorPicker":{"mostUsedCustomColors":"Gehien erabilitako kolore pertsonalizatuak","colors":"Koloreak","shades":"Ñabardurak","hexCode":"Hez kodea","noShades":"Kolore honetarako ez dago ñabardurarik eskuragarri"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Esportatu irudi gisa","button":"Esportatu irudi gisa","description":"Esportatu eszenaren datuak geroago inportatu ahal izango duzun irudi gisa."},"saveToDisk":{"title":"Gorde diskoan","button":"Gorde diskoan","description":"Esportatu eszenaren datuak geroago inportatu ahal izango duzun fitxategi batan."},"excalidrawPlus":{"title":"Excalidraw+","button":"Esportatu Excalidraw+ra","description":"Gorde eszena zure Excalidraw+ laneko areara."}},"modal":{"loadFromFile":{"title":"Fitxategitik kargatu","button":"Fitxategitik kargatu","description":"Fitxategi batetik kargatzeak lehendik duzun edukia ordezkatuko du. Lehenengo marrazkiaren babeskopia egin dezakezu beheko aukeretako bat erabiliz."},"shareableLink":{"title":"Estekatik kargatu","button":"Ordeztu nire edukia","description":"Kanpoko irudi bat kargatzeak lehendik duzun edukia ordezkatuko du. . Zure marrazkiaren babeskopia egin dezakezu lehenik beheko aukeretako bat erabiliz."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/fa-IR-json-e459964936177074abe7.js b/public/excalidraw/excalidraw-assets-dev/locales/fa-IR-json-e459964936177074abe7.js
new file mode 100644
index 0000000..c4ac168
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/fa-IR-json-e459964936177074abe7.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/fa-IR-json"],{
+
+/***/ "../../locales/fa-IR.json":
+/*!********************************!*\
+ !*** ../../locales/fa-IR.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"جای گذاری","pasteAsPlaintext":"جایگذاری به عنوان متن ساده","pasteCharts":"قراردادن نمودارها","selectAll":"انتخاب همه","multiSelect":"یک ایتم به انتخاب شده ها اضافه کنید.","moveCanvas":"جابجایی بوم","cut":"بریدن","copy":"کپی","copyAsPng":"کپی در حافطه موقت به صورت PNG","copyAsSvg":"کپی در حافطه موقت به صورت SVG","copyText":"کپی در حافطه موقت به صورت متن","bringForward":"جلو آوردن","sendToBack":"پس فرستادن","bringToFront":"جلو آوردن","sendBackward":"پس فرستادن","delete":"حذف","copyStyles":"کپی سبک","pasteStyles":"جای گذاری سبک","stroke":"حاشیه","background":"پس زمینه","fill":"رنگ آمیزی","strokeWidth":"ضخامت حاشیه","strokeStyle":"استایل حاشیه","strokeStyle_solid":"یکدست","strokeStyle_dashed":"خط چین","strokeStyle_dotted":"نقطه چین","sloppiness":"دقت","opacity":"شفافیت","textAlign":"چیدمان متن","edges":"لبه ها","sharp":"تیز","round":"دور","arrowheads":"سر پیکان","arrowhead_none":"هیچ کدام","arrowhead_arrow":"پیکان","arrowhead_bar":"میله ای","arrowhead_dot":"نقطه","arrowhead_triangle":"مثلث","fontSize":"اندازه قلم","fontFamily":"نوع قلم","addWatermark":"\\"ساخته شده با Excalidraw\\" را اضافه کن","handDrawn":"دست نویس","normal":"عادی","code":"کد","small":"کوچک","medium":"متوسط","large":"بزرگ","veryLarge":"بسیار بزرگ","solid":"توپر","hachure":"هاشور","zigzag":"زیگزاگ","crossHatch":"هاشور متقاطع","thin":"نازک","bold":"ضخیم","left":"چپ","center":"وسط","right":"راست","extraBold":"خیلی ضخیم","architect":"معمار","artist":"هنرمند","cartoonist":"کارتونیست","fileTitle":"نام فایل","colorPicker":"انتخابگر رنگ","canvasColors":"رنگ های بوم","canvasBackground":"بوم","drawingCanvas":"بوم نقاشی","layers":"لایه ها","actions":"عملیات","language":"زبان","liveCollaboration":"همکاری آنلاین...","duplicateSelection":"تکرار","untitled":"بدون عنوان","name":"نام","yourName":"نام شما","madeWithExcalidraw":"ساخته شده با Excalidraw","group":"گروهبندی انتخابها","ungroup":"حذف گروهبندی انتخابها","collaborators":"همکاران","showGrid":"نمایش گرید","addToLibrary":"افزودن به کتابخانه","removeFromLibrary":"حذف از کتابخانه","libraryLoadingMessage":"بارگذاری کتابخانه…","libraries":"مرور کردن کتابخانه ها","loadingScene":"باگذاری صحنه…","align":"تراز","alignTop":"تراز به بالا","alignBottom":"تراز به پایین","alignLeft":"تراز به چپ","alignRight":"تراز به راست","centerVertically":"وسط قرار دادن به صورت عمودی","centerHorizontally":"وسط قرار دادن به صورت افقی","distributeHorizontally":"توزیع کردن به صورت افقی","distributeVertically":"توزیع کردن به صورت عمودی","flipHorizontal":"چرخش افقی","flipVertical":"چرخش عمودی","viewMode":"حالت نمایش","share":"اشتراکگذاری","showStroke":"نمایش انتخاب کننده رنگ حاشیه","showBackground":"نمایش انتخاب کننده رنگ پس زمینه","toggleTheme":"تغییر تم","personalLib":"کتابخانه شخصی","excalidrawLib":"کتابخانه","decreaseFontSize":"کاهش اندازه فونت","increaseFontSize":"افزایش دادن اندازه فونت","unbindText":"بازکردن نوشته","bindText":"بستن نوشته","createContainerFromText":"متن را در یک جایگاه بپیچید","link":{"edit":"ویرایش لینک","editEmbed":"","create":"ایجاد پیوند","createEmbed":"","label":"لینک","labelEmbed":"","empty":""},"lineEditor":{"edit":"ویرایش لینک","exit":"خروج از ویرایشگر"},"elementLock":{"lock":"قفل","unlock":"باز کردن","lockAll":"قفل همه","unlockAll":"باز کردن قفل همه"},"statusPublished":"منتشر شده","sidebarLock":"باز نگه داشتن سایدبار","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":"انتخاب رنگ از کرباس"},"library":{"noItems":"آیتمی به اینجا اضافه نشده...","hint_emptyLibrary":"یک آیتم روی بوم را برای اضافه شده به اینجا انتخاب کنید، یا یک کتابخانه از مخزن عمومی در بخش پایین را نصب کنید.","hint_emptyPrivateLibrary":"یک آیتم روی بوم را برای اضافه شدن به اینجا انتخاب کنید."},"buttons":{"clearReset":"پاکسازی بوم نقاشی","exportJSON":"خروجی در فایل","exportImage":"خروجی گرفتن از تصویر...","export":"ذخیره در...","copyToClipboard":"کپی در حافظه موقت","save":"ذخیره در همین فایل","saveAs":"ذخیره با نام","load":"باز کردن","getShareableLink":"دریافت لینک قابل اشتراک","close":"بستن","selectLanguage":"انتخاب زبان","scrollBackToContent":"به محتوا بروید","zoomIn":"بزرگ نمایی","zoomOut":"کوچک نمایی","resetZoom":"اندازه اصلی","menu":"فهرست","done":"انجام شد","edit":"ویرایش","undo":"بازگرد","redo":"از سر","resetLibrary":"تنظیم مجدد کتابخانه","createNewRoom":"ایجاد یک اتاق جدید","fullScreen":"تمامصفحه","darkMode":"حالت تیره","lightMode":"حالت روشن","zenMode":"حالت ذن","objectsSnapMode":"","exitZenMode":"خروج از حالت تمرکز","cancel":"لغو","clear":"پاک کردن","remove":"پاک کردن","embed":"","publishLibrary":"انتشار","submit":"ارسال","confirm":"تایید","embeddableInteractionButton":""},"alerts":{"clearReset":"این کار کل صفحه را پاک میکند. آیا مطمئنید؟","couldNotCreateShareableLink":"عدم توانایی در ساخت یک لینک قابل اشتراک.","couldNotCreateShareableLinkTooBig":"لینک قابل اشتراک گذاری ایجاد نشد: محتوای صحنه بسیار بزرگ است","couldNotLoadInvalidFile":"عدم توانایی در بازگذاری فایل نامعتبر","importBackendFailed":"بارگیری از پشت صحنه با شکست مواجه شد.","cannotExportEmptyCanvas":"بوم خالی قابل تبدیل نیست.","couldNotCopyToClipboard":"به کلیپ بورد کپی نشد.","decryptFailed":"رمزگشایی داده ها امکان پذیر نیست.","uploadedSecurly":"آپلود با رمزگذاری دو طرفه انجام میشود، به این معنی که سرور Excalidraw و اشخاص ثالث نمی توانند مطالب شما را بخوانند.","loadSceneOverridePrompt":"بارگزاری یک طرح خارجی محتوای فعلی رو از بین میبرد. آیا میخواهید ادامه دهید؟","collabStopOverridePrompt":"با توقف بوم نقاشی، نقشه قبلی و ذخیره شده محلی شما را بازنویسی می کند. مطمئنی؟\\n\\n(اگر می خواهید نقاشی محلی خود را حفظ کنید، به سادگی برگه مرورگر را ببندید.)","errorAddingToLibrary":"مورد به کتابخانه اضافه نشد","errorRemovingFromLibrary":"مورد از کتابخانه حذف نشد","confirmAddLibrary":"{{numShapes}} از اشکال به کتابخانه شما اضافه خواهد شد. مطمئن هستید؟","imageDoesNotContainScene":"به نظر نمی رسد این تصویر حاوی داده های بوم نقاشی باشد. آیا جاسازی صحنه را در حین خروجی فعال کرده اید?","cannotRestoreFromImage":"صحنه را نمی توان از این فایل تصویری بازیابی کرد","invalidSceneUrl":"بوم نقاشی از آدرس ارائه شده وارد نشد. این یا نادرست است، یا حاوی داده Excalidraw JSON معتبر نیست.","resetLibrary":"ین کار کل صفحه را پاک میکند. آیا مطمئنید?","removeItemsFromsLibrary":"حذف {{count}} آیتم(ها) از کتابخانه?","invalidEncryptionKey":"کلید رمزگذاری باید 22 کاراکتر باشد. همکاری زنده غیرفعال است.","collabOfflineWarning":"اتصال به اینترنت در دسترس نیست.\\nتغییرات شما ذخیره نمی شود!"},"errors":{"unsupportedFileType":"نوع فایل پشتیبانی نشده.","imageInsertError":"عکس ارسال نشد. بعداً دوباره تلاش کنید...","fileTooBig":"فایل خیلی بزرگ است حداکثر اندازه مجاز {{maxSize}}.","svgImageInsertError":"تصویر SVG وارد نشد. نشانه گذاری SVG نامعتبر به نظر می رسد.","failedToFetchImage":"","invalidSVGString":"SVG نادرست.","cannotResolveCollabServer":"به سرور collab متصل نشد. لطفا صفحه را مجددا بارگذاری کنید و دوباره تلاش کنید.","importLibraryError":"دادهها بارگذاری نشدند","collabSaveFailed":"در پایگاه داده باطن ذخیره نشد. اگر مشکلات همچنان ادامه داشت، باید فایل خود را به صورت محلی ذخیره کنید تا مطمئن شوید کار خود را از دست نمی دهید.","collabSaveFailed_sizeExceeded":"در پایگاه داده بکند ذخیره نشد. اگر مشکلات همچنان ادامه داشت، باید فایل خود را به صورت محلی ذخیره کنید تا مطمئن شوید کار خود را از دست نمی دهید.","brave_measure_text_error":{"line1":"به نظر میرسد از مرورگر Brave با تنظیم مسدود کردن شدید اثرانگشت استفاده میکنید.","line2":"این می تواند منجر به شکستن عناصر متن در نقاشی های شما شود.","line3":"اکیداً توصیه می کنیم این تنظیم را غیرفعال کنید. برای نحوه انجام این کار میتوانید این مراحل را دنبال کنید.","line4":"اگر غیرفعال کردن این تنظیم نمایش عناصر متنی را برطرف نکرد، لطفاً یک مشکل را در GitHub ما باز کنید یا برای ما در Discord بنویسید."},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"گزینش","image":"وارد کردن تصویر","rectangle":"مستطیل","diamond":"لوزی","ellipse":"بیضی","arrow":"پیکان","line":"خط","freedraw":"کشیدن","text":"متن","library":"کتابخانه","lock":"ابزار انتخاب شده را بعد از کشیدن نگه دار","penMode":"حالت قلم - جلوگیری از تماس","link":"افزودن/بهروزرسانی پیوند برای شکل انتخابی","eraser":"پاک کن","frame":"","embeddable":"","laser":"","hand":"دست (ابزار پانینگ)","extraTools":"ابزارهای بیشتر"},"headings":{"canvasActions":"عملیات روی بوم","selectedShapeActions":"عملیات روی شکل انتخاب شده","shapes":"شکلها"},"hints":{"canvasPanning":"برای حرکت دادن بوم، چرخ ماوس یا فاصله را در حین کشیدن نگه دارید یا از ابزار دستی استفاده کنید","linearElement":"برای چند نقطه کلیک و برای یک خط بکشید","freeDraw":"کلیک کنید و بکشید و وقتی کار تمام شد رها کنید","text":"نکته: با برنامه انتخاب شده شما میتوانید با دوبار کلیک کردن هرکجا میخواید متن اظاف کنید","embeddable":"","text_selected":"دوبار کلیک کنید یا Enter را فشار دهید تا نقاط را ویرایش کنید","text_editing":"Escape یا CtrlOrCmd+ENTER را فشار دهید تا ویرایش تمام شود","linearElementMulti":"روی آخرین نقطه کلیک کنید یا کلید ESC را بزنید یا کلید Enter را بزنید برای اتمام کار","lockAngle":"با نگه داشتن SHIFT هنگام چرخش می توانید زاویه ها را محدود کنید","resize":"می توانید با نگه داشتن SHIFT در هنگام تغییر اندازه، نسبت ها را محدود کنید،ALT را برای تغییر اندازه از مرکز نگه دارید","resizeImage":"با نگه داشتن SHIFT می توانید آزادانه اندازه را تغییر دهید،\\nبرای تغییر اندازه از مرکز، ALT را نگه دارید","rotate":"با نگه داشتن SHIFT هنگام چرخش می توانید زاویه ها را محدود کنید","lineEditor_info":"CtrlOrCmd را نگه دارید و دوبار کلیک کنید یا CtrlOrCmd + Enter را فشار دهید تا نقاط را ویرایش کنید.","lineEditor_pointSelected":"برای حذف نقطه Delete برای کپی زدن Ctrl یا Cmd+D را بزنید و یا برای جابجایی بکشید","lineEditor_nothingSelected":"یک نقطه را برای ویرایش انتخاب کنید (SHIFT را برای انتخاب چندگانه نگه دارید)،\\nیا Alt را نگه دارید و برای افزودن نقاط جدید کلیک کنید","placeImage":"برای قرار دادن تصویر کلیک کنید، یا کلیک کنید و بکشید تا اندازه آن به صورت دستی تنظیم شود","publishLibrary":"کتابخانه خود را منتشر کنید","bindTextToElement":"برای افزودن اینتر را بزنید","deepBoxSelect":"CtrlOrCmd را برای انتخاب عمیق و جلوگیری از کشیدن نگه دارید","eraserRevert":"Alt را نگه دارید تا عناصر علامت گذاری شده برای حذف برگردند","firefox_clipboard_write":"احتمالاً میتوان این ویژگی را با تنظیم پرچم «dom.events.asyncClipboard.clipboardItem» روی «true» فعال کرد. برای تغییر پرچم های مرورگر در فایرفاکس، از صفحه \\"about:config\\" دیدن کنید.","disableSnapping":""},"canvasError":{"cannotShowPreview":"پیش نمایش نشان داده نمی شود","canvasTooBig":"بوم نقاشی بسیار بزرگ است.","canvasTooBigTip":"نکته: سعی کنید دورترین عناصر را کمی به همدیگر نزدیک کنید."},"errorSplash":{"headingMain":"","clearCanvasMessage":"اگر بازنشانی صفحه مشکل را حل نکرد این را امتحان کنید ","clearCanvasCaveat":" این باعث میشود کارهای شما ذخیره نشود ","trackedToSentry":"","openIssueMessage":"","sceneContent":"محتوای صحنه:"},"roomDialog":{"desc_intro":"می توانید افرادی را به صحنه فعلی خود دعوت کنید تا با شما همکاری کنند.","desc_privacy":"نگران نباشید، این جلسه از رمزگذاری دوطرفه استفاده می کند، پس هر چیزی بکشید خصوصی خواهد ماند. حتی سرور ما نمیتواند ببیند چیزی که شما طراحی میکنید.","button_startSession":"شروع جلسه","button_stopSession":"پایان جلسه","desc_inProgressIntro":"جلسه همکاری آنلاین در حال انجام است.","desc_shareLink":"این لینک را با هر کسی که می خواهید با او همکاری کنید به اشتراک بگذارید:","desc_exitSession":"با پایان دادن جلسه، شما از اتاق حذف میکند، اما می توانید به صورت محلی کار خود را با بوم ادامه دهید. توجه داشته باشید که این مورد بر سایر افراد تأثیر نمی گذارد و همچنان می توانند در نسخه خود همکاری کنند.","shareTitle":"به یک جلسه همکاری زنده در Excalidraw بپیوندید"},"errorDialog":{"title":"خطا"},"exportDialog":{"disk_title":"ذخیره در دیسک","disk_details":"داده های صحنه را به فایلی که بعداً می توانید از آن وارد کنید صادر کنید.","disk_button":"ذخیره در فایل","link_title":"لینک قابل اشتراکگذاری","link_details":"خروجی به عنوان یک پیوند فقط خواندنی.","link_button":"خروجی در فایل","excalidrawplus_description":"صحنه را در فضای کاری Excalidraw+ خود ذخیره کنید.","excalidrawplus_button":"خروجی گرفتن","excalidrawplus_exportError":"در حال حاضر نمیتوان به Excalidraw+ صادر کرد..."},"helpDialog":{"blog":"بلاگ ما را بخوانید","click":"کلیک","deepSelect":"انتخاب عمیق","deepBoxSelect":"انتخاب عمیق در کادر، و جلوگیری از کشیدن","curvedArrow":"فلش خمیده","curvedLine":"منحنی","documentation":"مستندات","doubleClick":"دابل کلیک","drag":"کشیدن","editor":"ویرایشگر","editLineArrowPoints":"نقاط خط/پیکان را ویرایش کنید","editText":"ویرایش متن / افزودن برچسب","github":"اشکالی می بینید؟ گزارش دهید","howto":"راهنمای ما را دنبال کنید","or":"یا","preventBinding":"مانع شدن از چسبیدن فلش ها","tools":"ابزار","shortcuts":"میانبرهای صفحه کلید","textFinish":"پایان ویرایش (ویرایشگر متن)","textNewLine":"افزودن خط جدید (ویرایشگر متن)","title":"راهنما","view":"مشاهده","zoomToFit":"بزرگنمایی برای دیدن تمام آیتم ها","zoomToSelection":"بزرگنمایی قسمت انتخاب شده","toggleElementLock":"قفل/بازکردن انتخاب شده ها","movePageUpDown":"حرکت صفحه به بالا/پایین","movePageLeftRight":"حرکت صفحه به چپ/راست"},"clearCanvasDialog":{"title":"پاک کردن بوم"},"publishDialog":{"title":"انتشار کتابخانه","itemName":"نام آیتم","authorName":"نام نویسنده","githubUsername":"نام کاربری گیت هاب","twitterUsername":"نام کاربری توییتر","libraryName":"نام کتابخانه","libraryDesc":"توضیحات کتابخانه","website":"تارنما","placeholder":{"authorName":"نام یا نام کاربری شما","libraryName":"اسم کتابخانه","libraryDesc":"شرحی از کتابخانه شما برای کمک به مردم برای درک استفاده از آن","githubHandle":"دسته GitHub (اختیاری)، بنابراین می توانید پس از ارسال برای بررسی، کتابخانه را ویرایش کنید","twitterHandle":"نام کاربری توییتر (اختیاری)، بنابراین می دانیم هنگام تبلیغ در توییتر به چه کسی اعتبار دهیم","website":"پیوند به وب سایت شخصی شما یا هر جای دیگر (اختیاری)"},"errors":{"required":"لازم","website":"وارد کردن آدرس درست"},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"هر مورد کتابخانه باید نام خاص خود را داشته باشد تا قابل فیلتر باشد. اقلام کتابخانه زیر شامل خواهد شد:","atleastOneLibItem":"لطفاً حداقل یک مورد از کتابخانه را برای شروع انتخاب کنید","republishWarning":"توجه: برخی از موارد انتخاب شده به عنوان قبلاً منتشر شده/ارسال شده علامت گذاری شده اند. شما فقط باید هنگام بهروزرسانی یک کتابخانه موجود یا ارسال، موارد را دوباره ارسال کنید."},"publishSuccessDialog":{"title":"کتابخانه ارسال شد","content":"تشکر از شما {{authorName}}. کتابخانه شما برای بررسی ارسال شده است. می توانید وضعیت را پیگیری کنید"},"confirmDialog":{"resetLibrary":"تنظیم مجدد کتابخانه","removeItemsFromLib":"موارد انتخاب شده از موارد پسندیده حذف شوند"},"imageExportDialog":{"header":"","label":{"withBackground":"پس زمینه","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"شما در یک محیط رمزگزاری شده دو طرفه در حال طراحی هستید پس Excalidraw هرگز طرح های شما را نمیبند.","link":"پست وبلاگ در مورد رمزگذاری سرتاسر در Excalidraw"},"stats":{"angle":"زاویه","element":"اِلمان","elements":"اِلمان ها","height":"ارتفاع","scene":"صحنه","selected":"انتخاب شده","storage":"حافظه","title":"آمار برای نردها","total":"مجموع","version":"نسخه","versionCopy":"برای کپی کردن کلیک کنید","versionNotAvailable":"نسخه غیرقابل دسترس","width":"عرض"},"toast":{"addedToLibrary":"به مجموعه اضافه شد","copyStyles":"کپی سبک.","copyToClipboard":"در کلیپبورد کپی شد.","copyToClipboardAsPng":"کپی {{exportSelection}} در کلیپبورد به عنوان PNG\\n({{exportColorScheme}})","fileSaved":"فایل ذخیره شد.","fileSavedToFilename":"ذخیره در {filename}","canvas":"بوم","selection":"انتخاب","pasteAsSingleElement":"از {{shortcut}} برای چسباندن به عنوان یک عنصر استفاده کنید،\\nیا در یک ویرایشگر متن موجود جایگذاری کنید","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"شفاف","black":"سیاه","white":"سفید","red":"قرمز","pink":"صورتی","grape":"یاقوتی","violet":"بنفش","gray":"خاکستری","blue":"آبی","cyan":"فیروزهای","teal":"سبزآبی","green":"سبز","yellow":"زرد","orange":"نارنجی","bronze":"برنزی"},"welcomeScreen":{"app":{"center_heading":"تمام داده های شما به صورت محلی در مرورگر شما ذخیره می شود.","center_heading_plus":"آیا میخواهید به جای آن به Excalidraw+ بروید؟","menuHint":"خروجی، ترجیحات، زبان ها، ..."},"defaults":{"menuHint":"خروجی، ترجیحات، وبیشتر ...","center_heading":"نمودارها .ساخته شده. ساده.","toolbarHint":"ابزاری را انتخاب کنید و نقاشی را شروع کنید!","helpHint":"میانبرها و راهنما"}},"colorPicker":{"mostUsedCustomColors":"","colors":"رنگها","shades":"جلوهها","hexCode":"کدِ هگز","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"ذخیره در دیسک","button":"ذخیره در دیسک","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"بارگذاری از فایل","button":"بارگذاری از فایل","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/fi-FI-json-f7839bb6f5ad0a3c7e0d.js b/public/excalidraw/excalidraw-assets-dev/locales/fi-FI-json-f7839bb6f5ad0a3c7e0d.js
new file mode 100644
index 0000000..7f94a39
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/fi-FI-json-f7839bb6f5ad0a3c7e0d.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/fi-FI-json"],{
+
+/***/ "../../locales/fi-FI.json":
+/*!********************************!*\
+ !*** ../../locales/fi-FI.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Liitä","pasteAsPlaintext":"Liitä pelkkänä tekstinä","pasteCharts":"Liitä kaaviot","selectAll":"Valitse kaikki","multiSelect":"Lisää kohde valintaan","moveCanvas":"Siirrä piirtoaluetta","cut":"Leikkaa","copy":"Kopioi","copyAsPng":"Kopioi leikepöydälle PNG-tiedostona","copyAsSvg":"Kopioi leikepöydälle SVG-tiedostona","copyText":"Kopioi tekstinä","bringForward":"Tuo eteenpäin","sendToBack":"Vie taakse","bringToFront":"Tuo eteen","sendBackward":"Vie taaksepäin","delete":"Poista","copyStyles":"Kopioi tyyli","pasteStyles":"Liitä tyyli","stroke":"Piirto","background":"Tausta","fill":"Täyttö","strokeWidth":"Viivan leveys","strokeStyle":"Viivan tyyli","strokeStyle_solid":"Yhtenäinen","strokeStyle_dashed":"Katkoviiva","strokeStyle_dotted":"Pisteviiva","sloppiness":"Viivan tarkkuus","opacity":"Peittävyys","textAlign":"Tekstin tasaus","edges":"Reunat","sharp":"Terävä","round":"Pyöristetty","arrowheads":"Nuolenkärjet","arrowhead_none":"Ei mitään","arrowhead_arrow":"Nuoli","arrowhead_bar":"Tasapää","arrowhead_dot":"Piste","arrowhead_triangle":"Kolmio","fontSize":"Kirjasinkoko","fontFamily":"Kirjasintyyppi","addWatermark":"Lisää \\"Tehty Excalidrawilla\\"","handDrawn":"Käsinpiirretty","normal":"Tavallinen","code":"Koodi","small":"Pieni","medium":"Keskikoko","large":"Suuri","veryLarge":"Erittäin suuri","solid":"Yhtenäinen","hachure":"Vinoviivoitus","zigzag":"","crossHatch":"Ristiviivoitus","thin":"Ohut","bold":"Lihavoitu","left":"Vasen","center":"Keskitä","right":"Oikea","extraBold":"Erittäin lihavoitu","architect":"Arkkitehti","artist":"Taiteilija","cartoonist":"Sarjakuva","fileTitle":"Tiedostonimi","colorPicker":"Värin valinta","canvasColors":"Käytössä piirtoalueella","canvasBackground":"Piirtoalueen tausta","drawingCanvas":"Piirtoalue","layers":"Tasot","actions":"Toiminnot","language":"Kieli","liveCollaboration":"Live Yhteistyö...","duplicateSelection":"Monista","untitled":"Nimetön","name":"Nimi","yourName":"Nimesi","madeWithExcalidraw":"Tehty Excalidrawilla","group":"Ryhmitä valinta","ungroup":"Pura valittu ryhmä","collaborators":"Yhteistyökumppanit","showGrid":"Näytä ruudukko","addToLibrary":"Lisää kirjastoon","removeFromLibrary":"Poista kirjastosta","libraryLoadingMessage":"Ladataan kirjastoa…","libraries":"Selaa kirjastoja","loadingScene":"Ladataan työtä…","align":"Tasaa","alignTop":"Tasaa ylös","alignBottom":"Tasaa alas","alignLeft":"Tasaa vasemmalle","alignRight":"Tasaa oikealle","centerVertically":"Keskitä pystysuunnassa","centerHorizontally":"Keskitä vaakasuunnassa","distributeHorizontally":"Jaa vaakasuunnassa","distributeVertically":"Jaa pystysuunnassa","flipHorizontal":"Käännä vaakasuunnassa","flipVertical":"Käännä pystysuunnassa","viewMode":"Katselutila","share":"Jaa","showStroke":"Näytä viivan värin valitsin","showBackground":"Näytä taustavärin valitsin","toggleTheme":"Vaihda teema","personalLib":"Oma kirjasto","excalidrawLib":"Excalidraw kirjasto","decreaseFontSize":"Pienennä kirjasinkokoa","increaseFontSize":"Kasvata kirjasinkokoa","unbindText":"Irroita teksti","bindText":"Kiinnitä teksti säiliöön","createContainerFromText":"","link":{"edit":"Muokkaa linkkiä","editEmbed":"","create":"Luo linkki","createEmbed":"","label":"Linkki","labelEmbed":"","empty":""},"lineEditor":{"edit":"Muokkaa riviä","exit":"Poistu rivieditorista"},"elementLock":{"lock":"Lukitse","unlock":"Poista lukitus","lockAll":"Lukitse kaikki","unlockAll":"Poista lukitus kaikista"},"statusPublished":"Julkaistu","sidebarLock":"Pidä sivupalkki avoinna","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Kirjastossa ei ole vielä yhtään kohdetta...","hint_emptyLibrary":"Valitse lisättävä kohde piirtoalueelta, tai asenna alta julkinen kirjasto.","hint_emptyPrivateLibrary":"Valitse lisättävä kohde piirtoalueelta."},"buttons":{"clearReset":"Tyhjennä piirtoalue","exportJSON":"Vie tiedostoon","exportImage":"Vie kuva...","export":"Tallenna nimellä...","copyToClipboard":"Kopioi leikepöydälle","save":"Tallenna nykyiseen tiedostoon","saveAs":"Tallenna nimellä","load":"Avaa","getShareableLink":"Hae jaettava linkki","close":"Sulje","selectLanguage":"Valitse kieli","scrollBackToContent":"Näytä sisältö","zoomIn":"Lähennä","zoomOut":"Loitonna","resetZoom":"Nollaa suurennuksen taso","menu":"Valikko","done":"Valmis","edit":"Muokkaa","undo":"Kumoa","redo":"Tee uudelleen","resetLibrary":"Tyhjennä kirjasto","createNewRoom":"Luo huone","fullScreen":"Koko näyttö","darkMode":"Tumma tila","lightMode":"Vaalea tila","zenMode":"Zen-tila","objectsSnapMode":"","exitZenMode":"Poistu zen-tilasta","cancel":"Peruuta","clear":"Pyyhi","remove":"Poista","embed":"","publishLibrary":"Julkaise","submit":"Lähetä","confirm":"Vahvista","embeddableInteractionButton":""},"alerts":{"clearReset":"Tämä tyhjentää koko piirtoalueen. Jatketaanko?","couldNotCreateShareableLink":"Jaettavan linkin luominen epäonnistui.","couldNotCreateShareableLinkTooBig":"Jaettavaa linkkiä ei voitu luoda: teos on liian suuri","couldNotLoadInvalidFile":"Virheellistä tiedostoa ei voitu avata","importBackendFailed":"Palvelimelta tuonti epäonnistui.","cannotExportEmptyCanvas":"Tyhjää piirtoaluetta ei voi viedä.","couldNotCopyToClipboard":"Leikepöydälle vieminen epäonnistui.","decryptFailed":"Salauksen purkaminen epäonnistui.","uploadedSecurly":"Lähetys on turvattu päästä-päähän-salauksella. Excalidrawin palvelin ja kolmannet osapuolet eivät voi lukea sisältöä.","loadSceneOverridePrompt":"Ulkopuolisen piirroksen lataaminen korvaa nykyisen sisältösi. Jatketaanko?","collabStopOverridePrompt":"Istunnon lopettaminen korvaa aiemman, paikallisesti tallennetun piirustuksen. Jatketaanko?\\n\\n(Jos haluat säilyttää paikallisesti tallennetun piirustuksen, sulje selaimen välilehti lopettamisen sijaan.)","errorAddingToLibrary":"Kohdetta ei voitu lisätä kirjastoon","errorRemovingFromLibrary":"Kohdetta ei voitu poistaa kirjastosta","confirmAddLibrary":"Tämä lisää {{numShapes}} muotoa kirjastoosi. Jatketaanko?","imageDoesNotContainScene":"Tämä kuva ei näytä sisältävän piirrostietoja. Oletko ottanut käyttöön piirroksen tallennuksen viennin aikana?","cannotRestoreFromImage":"Teosta ei voitu palauttaa tästä kuvatiedostosta","invalidSceneUrl":"Teosta ei voitu tuoda annetusta URL-osoitteesta. Tallenne on vioittunut, tai osoitteessa ei ole Excalidraw JSON-dataa.","resetLibrary":"Tämä tyhjentää kirjastosi. Jatketaanko?","removeItemsFromsLibrary":"Poista {{count}} kohdetta kirjastosta?","invalidEncryptionKey":"Salausavaimen on oltava 22 merkkiä pitkä. Live-yhteistyö ei ole käytössä.","collabOfflineWarning":"Internet-yhteyttä ei ole saatavilla.\\nMuutoksiasi ei tallenneta!"},"errors":{"unsupportedFileType":"Tiedostotyyppiä ei tueta.","imageInsertError":"Kuvan lisääminen epäonnistui. Yritä myöhemmin uudelleen...","fileTooBig":"Tiedosto on liian suuri. Suurin sallittu koko on {{maxSize}}.","svgImageInsertError":"SVG- kuvaa ei voitu lisätä. Tiedoston SVG-sisältö näyttää virheelliseltä.","failedToFetchImage":"","invalidSVGString":"Virheellinen SVG.","cannotResolveCollabServer":"Yhteyden muodostaminen collab-palvelimeen epäonnistui. Virkistä sivu ja yritä uudelleen.","importLibraryError":"Kokoelman lataaminen epäonnistui","collabSaveFailed":"Ei voitu tallentaan palvelimen tietokantaan. Jos ongelmia esiintyy, sinun kannatta tallentaa tallentaa tiedosto paikallisesti varmistaaksesi, että et menetä työtäsi.","collabSaveFailed_sizeExceeded":"Ei voitu tallentaan palvelimen tietokantaan. Jos ongelmia esiintyy, sinun kannatta tallentaa tallentaa tiedosto paikallisesti varmistaaksesi, että et menetä työtäsi.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Valinta","image":"Lisää kuva","rectangle":"Suorakulmio","diamond":"Vinoneliö","ellipse":"Soikio","arrow":"Nuoli","line":"Viiva","freedraw":"Piirrä","text":"Teksti","library":"Kirjasto","lock":"Pidä valittu työkalu aktiivisena piirron jälkeen","penMode":"Kynätila - estä kosketus","link":"Lisää/päivitä linkki valitulle muodolle","eraser":"Poistotyökalu","frame":"","embeddable":"","laser":"","hand":"Käsi (panning-työkalu)","extraTools":""},"headings":{"canvasActions":"Piirtoalueen toiminnot","selectedShapeActions":"Valitun muodon toiminnot","shapes":"Muodot"},"hints":{"canvasPanning":"Piirtoalueen liikuttamiseksi pidä hiiren pyörää tai välilyöntiä pohjassa tai käytä käsityökalua","linearElement":"Klikkaa piirtääksesi useampi piste, raahaa piirtääksesi yksittäinen viiva","freeDraw":"Paina ja raahaa, päästä irti kun olet valmis","text":"Vinkki: voit myös lisätä tekstiä kaksoisnapsauttamalla mihin tahansa valintatyökalulla","embeddable":"","text_selected":"Kaksoisnapsauta tai paina ENTER muokataksesi tekstiä","text_editing":"Paina Escape tai CtrlOrCmd+ENTER lopettaaksesi muokkaamisen","linearElementMulti":"Lopeta klikkaamalla viimeistä pistettä, painamalla Escape- tai Enter-näppäintä","lockAngle":"Voit rajoittaa kulmaa pitämällä SHIFT-näppäintä alaspainettuna","resize":"Voit rajoittaa mittasuhteet pitämällä SHIFT-näppäintä alaspainettuna kun muutat kokoa, pidä ALT-näppäintä alaspainettuna muuttaaksesi kokoa keskipisteen suhteen","resizeImage":"Voit muuttaa kokoa vapaasti pitämällä SHIFTiä pohjassa, pidä ALT pohjassa muuttaaksesi kokoa keskipisteen ympäri","rotate":"Voit rajoittaa kulman pitämällä SHIFT pohjassa pyörittäessäsi","lineEditor_info":"Pidä CtrlOrCmd pohjassa ja kaksoisnapsauta tai paina CtrlOrCmd + Enter muokataksesi pisteitä","lineEditor_pointSelected":"Poista piste(et) painamalla delete, monista painamalla CtrlOrCmd+D, tai liikuta raahaamalla","lineEditor_nothingSelected":"Valitse muokattava piste (monivalinta pitämällä SHIFT pohjassa), tai paina Alt ja klikkaa lisätäksesi uusia pisteitä","placeImage":"Klikkaa asettaaksesi kuvan, tai klikkaa ja raahaa asettaaksesi sen koon manuaalisesti","publishLibrary":"Julkaise oma kirjasto","bindTextToElement":"Lisää tekstiä painamalla enter","deepBoxSelect":"Käytä syvävalintaa ja estä raahaus painamalla CtrlOrCmd","eraserRevert":"Pidä Alt alaspainettuna, kumotaksesi merkittyjen elementtien poistamisen","firefox_clipboard_write":"Tämä ominaisuus voidaan todennäköisesti ottaa käyttöön asettamalla \\"dom.events.asyncClipboard.clipboardItem\\" kohta \\"true\\":ksi. Vaihtaaksesi selaimen kohdan Firefoxissa, käy \\"about:config\\" sivulla.","disableSnapping":""},"canvasError":{"cannotShowPreview":"Esikatselua ei voitu näyttää","canvasTooBig":"Piirtoalue saattaa olla liian suuri.","canvasTooBigTip":"Vinkki: yritä siirtää kaukaisimpia elementtejä hieman lähemmäs toisiaan."},"errorSplash":{"headingMain":"Tapahtui virhe. Yritä ","clearCanvasMessage":"Mikäli sivun lataaminen uudelleen ei auta, yritä ","clearCanvasCaveat":" Tämä johtaa työn menetykseen ","trackedToSentry":"Virhe tunnisteella {{eventId}} tallennettiin järjestelmäämme.","openIssueMessage":"Olimme varovaisia emmekä sisällyttäneet tietoa piirroksestasi virheeseen. Mikäli piirroksesi ei ole yksityinen, harkitsethan kertovasi meille Sisällytä alla olevat tiedot kopioimalla ne GitHub-ongelmaan.","sceneContent":"Piirroksen tiedot:"},"roomDialog":{"desc_intro":"Voit kutsua ihmisiä piirrokseesi tekemään yhteistyötä kanssasi.","desc_privacy":"Älä huoli, istunto käyttää päästä-päähän-salausta, joten mitä tahansa piirrätkin, se pysyy salassa. Edes palvelimemme eivät näe mitä keksit.","button_startSession":"Aloita istunto","button_stopSession":"Lopeta istunto","desc_inProgressIntro":"Jaettu istunto on nyt käynnissä.","desc_shareLink":"Jaa tämä linkki kenelle tahansa, jonka kanssa haluat tehdä yhteistyötä:","desc_exitSession":"Istunnon pysäyttäminen katkaisee yhteyden huoneeseen, mutta voit vielä jatkaa työskentelyä paikallisesti. Huomaa, että tämä ei vaikuta muihin käyttäjiin ja he voivat jatkaa oman versionsa parissa työskentelyä.","shareTitle":"Liity Excalidraw live-yhteistyöistuntoon"},"errorDialog":{"title":"Virhe"},"exportDialog":{"disk_title":"Tallenna levylle","disk_details":"Vie työn tiedot tiedostoon, josta sen voi tuoda myöhemmin.","disk_button":"Tallenna tiedostoon","link_title":"Jaettava linkki","link_details":"Vie vain luku -linkkinä.","link_button":"Vie linkkinä","excalidrawplus_description":"Tallenna teos Excalidraw+ tilaan.","excalidrawplus_button":"Vie","excalidrawplus_exportError":"Ei voitu viedä Excalidraw+-palveluun tällä hetkellä..."},"helpDialog":{"blog":"Lue blogiamme","click":"klikkaa","deepSelect":"Syvävalinta","deepBoxSelect":"Käytä syvävalintaa ja estä raahaus","curvedArrow":"Kaareva nuoli","curvedLine":"Kaareva viiva","documentation":"Käyttöohjeet","doubleClick":"kaksoisnapsautus","drag":"vedä","editor":"Muokkausohjelma","editLineArrowPoints":"","editText":"","github":"Löysitkö ongelman? Kerro meille","howto":"Seuraa oppaitamme","or":"tai","preventBinding":"Estä nuolten kiinnitys","tools":"Työkalut","shortcuts":"Pikanäppäimet","textFinish":"Lopeta muokkaus (tekstieditori)","textNewLine":"Lisää uusi rivi (tekstieditori)","title":"Ohjeet","view":"Näkymä","zoomToFit":"Näytä kaikki elementit","zoomToSelection":"Näytä valinta","toggleElementLock":"Lukitse / poista lukitus valinta","movePageUpDown":"Siirrä sivua ylös/alas","movePageLeftRight":"Siirrä sivua vasemmalle/oikealle"},"clearCanvasDialog":{"title":"Pyyhi piirtoalue"},"publishDialog":{"title":"Julkaise kirjasto","itemName":"Kohteen nimi","authorName":"Tekijän nimi","githubUsername":"GitHub-käyttäjätunnus","twitterUsername":"Twitter-käyttäjätunnus","libraryName":"Kirjaston nimi","libraryDesc":"Kirjaston kuvaus","website":"Verkkosivu","placeholder":{"authorName":"Nimesi tai käyttäjänimesi","libraryName":"Kirjastosi nimi","libraryDesc":"Kirjaston kuvaus, joka auttaa ihmisiä ymmärtämään sen käyttötarkoitukset","githubHandle":"GitHub-tunnuksesi (valinnainen), jotta voit muokata kirjastoa sen jälkeen kun se on lähetetty tarkastettavaksi","twitterHandle":"Twitter-tunnus (valinnainen), jotta tiedämme ketä kiittää kun viestimme Twitterissä","website":"Linkki henkilökohtaiselle verkkosivustollesi tai muualle (valinnainen)"},"errors":{"required":"Pakollinen","website":"Syötä oikeamuotoinen URL-osoite"},"noteDescription":"Lähetä kirjastosi, jotta se voidaan sisällyttää julkisessa kirjastolistauksessamuiden käyttöön omissa piirrustuksissaan.","noteGuidelines":"Kirjasto on ensin hyväksyttävä manuaalisesti. Ole hyvä ja lue ohjeet ennen lähettämistä. Tarvitset GitHub-tilin, jotta voit viestiä ja tehdä muutoksia pyydettäessä, mutta se ei ole ehdottoman välttämätöntä.","noteLicense":"Lähettämällä hyväksyt että kirjasto julkaistaan MIT-lisenssin alla, mikä lyhyesti antaa muiden käyttää sitä ilman rajoituksia.","noteItems":"Jokaisella kirjaston kohteella on oltava oma nimensä suodatusta varten. Seuraavat kirjaston kohteet sisältyvät:","atleastOneLibItem":"Valitse vähintään yksi kirjaston kohde aloittaaksesi","republishWarning":"Huom! Osa valituista kohteista on merkitty jo julkaistu/lähetetyiksi. Lähetä kohteita uudelleen vain päivitettäessä olemassa olevaa kirjastoa tai ehdotusta."},"publishSuccessDialog":{"title":"Kirjasto lähetetty","content":"Kiitos {{authorName}}. Kirjastosi on lähetetty tarkistettavaksi. Voit seurata sen tilaatäällä"},"confirmDialog":{"resetLibrary":"Tyhjennä kirjasto","removeItemsFromLib":"Poista valitut kohteet kirjastosta"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"Piirroksesi ovat päästä-päähän-salattuja, joten Excalidrawin palvelimet eivät koskaan näe niitä.","link":"Blogiartikkeli päästä päähän -salauksesta Excalidraw:ssa"},"stats":{"angle":"Kulma","element":"Elementti","elements":"Elementit","height":"Korkeus","scene":"Teos","selected":"Valitut","storage":"Tallennustila","title":"Tilastoja nörteille","total":"Yhteensä","version":"Versio","versionCopy":"Klikkaa kopioidaksesi","versionNotAvailable":"Versio ei saatavilla","width":"Leveys"},"toast":{"addedToLibrary":"Lisätty kirjastoon","copyStyles":"Tyylit kopioitiin.","copyToClipboard":"Kopioitiin leikepöydälle.","copyToClipboardAsPng":"Kopioitiin {{exportSelection}} leikepöydälle PNG:nä\\n({{exportColorScheme}})","fileSaved":"Tiedosto tallennettu.","fileSavedToFilename":"Tallennettiin kohteeseen {filename}","canvas":"piirtoalue","selection":"valinta","pasteAsSingleElement":"Käytä {{shortcut}} liittääksesi yhtenä elementtinä,\\ntai liittääksesi olemassa olevaan tekstieditoriin","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Läpinäkyvä","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"Kaikki tietosi on tallennettu paikallisesti selaimellesi.","center_heading_plus":"Haluatko sen sijaan mennä Excalidraw+:aan?","menuHint":"Vie, asetukset, kielet, ..."},"defaults":{"menuHint":"Vie, asetukset ja lisää...","center_heading":"Kaaviot. Tehty. Yksinkertaiseksi.","toolbarHint":"Valitse työkalu ja aloita piirtäminen!","helpHint":"Pikanäppäimet & ohje"}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/fr-FR-json-20e8535e2675a6736c81.js b/public/excalidraw/excalidraw-assets-dev/locales/fr-FR-json-20e8535e2675a6736c81.js
new file mode 100644
index 0000000..c865c8d
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/fr-FR-json-20e8535e2675a6736c81.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/fr-FR-json"],{
+
+/***/ "../../locales/fr-FR.json":
+/*!********************************!*\
+ !*** ../../locales/fr-FR.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Coller","pasteAsPlaintext":"Coller comme texte brut","pasteCharts":"Coller les graphiques","selectAll":"Tout sélectionner","multiSelect":"Ajouter l\'élément à la sélection","moveCanvas":"Déplacer le canevas","cut":"Couper","copy":"Copier","copyAsPng":"Copier dans le presse-papier en PNG","copyAsSvg":"Copier dans le presse-papier en SVG","copyText":"Copier dans le presse-papier en tant que texte","bringForward":"Envoyer vers l\'avant","sendToBack":"Déplacer à l\'arrière-plan","bringToFront":"Mettre au premier plan","sendBackward":"Reculer d\'un plan","delete":"Supprimer","copyStyles":"Copier les styles","pasteStyles":"Coller les styles","stroke":"Trait","background":"Arrière-plan","fill":"Remplissage","strokeWidth":"Largeur du contour","strokeStyle":"Style du trait","strokeStyle_solid":"Continu","strokeStyle_dashed":"Tirets","strokeStyle_dotted":"Pointillés","sloppiness":"Style de tracé","opacity":"Transparence","textAlign":"Alignement du texte","edges":"Angles","sharp":"Pointus","round":"Arrondis","arrowheads":"Extrémités","arrowhead_none":"Sans","arrowhead_arrow":"Flèche","arrowhead_bar":"Barre","arrowhead_dot":"Point","arrowhead_triangle":"Triangle","fontSize":"Taille de la police","fontFamily":"Police","addWatermark":"Ajouter \\"Réalisé avec Excalidraw\\"","handDrawn":"À main levée","normal":"Normale","code":"Code","small":"Petite","medium":"Moyenne","large":"Grande","veryLarge":"Très grande","solid":"Solide","hachure":"Hachures","zigzag":"Zigzag","crossHatch":"Hachures croisées","thin":"Fine","bold":"Épaisse","left":"À gauche","center":"Au centre","right":"À droite","extraBold":"Très épaisse","architect":"Architecte","artist":"Artiste","cartoonist":"Caricaturiste","fileTitle":"Nom du fichier","colorPicker":"Sélecteur de couleur","canvasColors":"Utilisé sur la zone de dessin","canvasBackground":"Arrière-plan du canevas","drawingCanvas":"Zone de dessin","layers":"Disposition","actions":"Actions","language":"Langue","liveCollaboration":"Collaboration en direct...","duplicateSelection":"Dupliquer","untitled":"Sans-titre","name":"Nom","yourName":"Votre nom","madeWithExcalidraw":"Fait avec Excalidraw","group":"Grouper la sélection","ungroup":"Dégrouper la sélection","collaborators":"Collaborateurs","showGrid":"Afficher la grille","addToLibrary":"Ajouter à la bibliothèque","removeFromLibrary":"Supprimer de la bibliothèque","libraryLoadingMessage":"Chargement de la bibliothèque…","libraries":"Parcourir les bibliothèques","loadingScene":"Chargement de la scène…","align":"Alignement","alignTop":"Aligner en haut","alignBottom":"Aligner en bas","alignLeft":"Aligner à gauche","alignRight":"Aligner à droite","centerVertically":"Centrer verticalement","centerHorizontally":"Centrer horizontalement","distributeHorizontally":"Répartir horizontalement","distributeVertically":"Répartir verticalement","flipHorizontal":"Retourner horizontalement","flipVertical":"Retourner verticalement","viewMode":"Mode présentation","share":"Partager","showStroke":"Afficher le sélecteur de couleur de trait","showBackground":"Afficher le sélecteur de couleur de fond","toggleTheme":"Changer le thème","personalLib":"Bibliothèque personnelle","excalidrawLib":"Bibliothèque Excalidraw","decreaseFontSize":"Diminuer la taille de police","increaseFontSize":"Augmenter la taille de la police","unbindText":"Dissocier le texte","bindText":"Associer le texte au conteneur","createContainerFromText":"Encadrer le texte dans un conteneur","link":{"edit":"Modifier le lien","editEmbed":"Éditer le lien & intégrer","create":"Ajouter un lien","createEmbed":"Créer un lien & intégrer","label":"Lien","labelEmbed":"","empty":"Aucun lien défini"},"lineEditor":{"edit":"Modifier la ligne","exit":"Quitter l\'éditeur de ligne"},"elementLock":{"lock":"Verrouiller","unlock":"Déverrouiller","lockAll":"Tout verrouiller","unlockAll":"Tout déverrouiller"},"statusPublished":"Publié","sidebarLock":"Maintenir la barre latérale ouverte","selectAllElementsInFrame":"Sélectionner tous les éléments du cadre","removeAllElementsFromFrame":"Supprimer tous les éléments du cadre","eyeDropper":""},"library":{"noItems":"Aucun élément n\'a encore été ajouté ...","hint_emptyLibrary":"Sélectionnez un élément sur le canevas pour l\'ajouter ici ou installez une bibliothèque depuis le dépôt public, ci-dessous.","hint_emptyPrivateLibrary":"Sélectionnez un élément sur le canevas pour l\'ajouter ici."},"buttons":{"clearReset":"Réinitialiser le canevas","exportJSON":"Exporter comme fichier","exportImage":"Exporter l\'image...","export":"Enregistrer sous...","copyToClipboard":"Copier dans le presse-papier","save":"Enregistrer dans le fichier actuel","saveAs":"Enregistrer sous","load":"Ouvrir","getShareableLink":"Obtenir un lien de partage","close":"Fermer","selectLanguage":"Choisir une langue","scrollBackToContent":"Revenir au contenu","zoomIn":"Zoomer","zoomOut":"Dézoomer","resetZoom":"Réinitialiser le zoom","menu":"Menu","done":"Terminé","edit":"Modifier","undo":"Annuler","redo":"Rétablir","resetLibrary":"Réinitialiser la bibliothèque","createNewRoom":"Créer une nouvelle salle","fullScreen":"Plein écran","darkMode":"Mode sombre","lightMode":"Mode clair","zenMode":"Mode zen","objectsSnapMode":"Aimanter aux objets","exitZenMode":"Quitter le mode zen","cancel":"Annuler","clear":"Effacer","remove":"Supprimer","embed":"Activer/Désactiver l\'intégration","publishLibrary":"Publier","submit":"Envoyer","confirm":"Confirmer","embeddableInteractionButton":"Cliquez pour interagir"},"alerts":{"clearReset":"L\'intégralité du canevas va être effacée. Êtes-vous sûr ?","couldNotCreateShareableLink":"Impossible de créer un lien de partage.","couldNotCreateShareableLinkTooBig":"Impossible de créer un lien de partage : la scène est trop volumineuse","couldNotLoadInvalidFile":"Impossible de charger un fichier invalide","importBackendFailed":"L\'importation depuis le serveur a échoué.","cannotExportEmptyCanvas":"Impossible d\'exporter un canevas vide.","couldNotCopyToClipboard":"Impossible de copier dans le presse-papiers.","decryptFailed":"Les données n\'ont pas pu être déchiffrées.","uploadedSecurly":"Le téléchargement a été sécurisé avec un chiffrement de bout en bout, ce qui signifie que ni Excalidraw ni personne d\'autre ne peut en lire le contenu.","loadSceneOverridePrompt":"Le chargement d\'un dessin externe remplacera votre contenu actuel. Souhaitez-vous continuer ?","collabStopOverridePrompt":"Arrêter la session écrasera votre précédent dessin stocké localement. Êtes-vous sûr·e ?\\n\\n(Si vous voulez garder votre dessin local, fermez simplement l\'onglet du navigateur à la place.)","errorAddingToLibrary":"Impossible d\'ajouter l\'élément à la bibliothèque","errorRemovingFromLibrary":"Impossible de retirer l\'élément de la bibliothèque","confirmAddLibrary":"Cela va ajouter {{numShapes}} forme(s) à votre bibliothèque. Êtes-vous sûr·e ?","imageDoesNotContainScene":"Cette image ne semble pas contenir de données de scène. Avez-vous activé l\'intégration de scène lors de l\'exportation ?","cannotRestoreFromImage":"Impossible de restaurer la scène depuis ce fichier image","invalidSceneUrl":"Impossible d\'importer la scène depuis l\'URL fournie. Elle est soit incorrecte, soit ne contient pas de données JSON Excalidraw valides.","resetLibrary":"Cela va effacer votre bibliothèque. Êtes-vous sûr·e ?","removeItemsFromsLibrary":"Supprimer {{count}} élément(s) de la bibliothèque ?","invalidEncryptionKey":"La clé de chiffrement doit comporter 22 caractères. La collaboration en direct est désactivée.","collabOfflineWarning":"Aucune connexion internet disponible.\\nVos modifications ne seront pas enregistrées !"},"errors":{"unsupportedFileType":"Type de fichier non supporté.","imageInsertError":"Impossible d\'insérer l\'image. Réessayez plus tard...","fileTooBig":"Le fichier est trop volumineux. La taille maximale autorisée est de {{maxSize}}.","svgImageInsertError":"Impossible d\'insérer l\'image SVG. Le balisage SVG semble invalide.","failedToFetchImage":"","invalidSVGString":"SVG invalide.","cannotResolveCollabServer":"Impossible de se connecter au serveur collaboratif. Veuillez recharger la page et réessayer.","importLibraryError":"Impossible de charger la bibliothèque","collabSaveFailed":"Impossible d\'enregistrer dans la base de données en arrière-plan. Si des problèmes persistent, vous devriez enregistrer votre fichier localement pour vous assurer de ne pas perdre votre travail.","collabSaveFailed_sizeExceeded":"Impossible d\'enregistrer dans la base de données en arrière-plan, le tableau semble trop grand. Vous devriez enregistrer le fichier localement pour vous assurer de ne pas perdre votre travail.","brave_measure_text_error":{"line1":"On dirait que vous utilisez le navigateur Brave avec l\'option Bloquer agressivement le fichage activée.","line2":"Cela pourrait entraîner des problèmes avec les Éléments Textuels dans vos dessins.","line3":"Nous recommandons fortement de désactiver cette option. Vous pouvez suivre ces instructions pour savoir comment faire.","line4":"Si désactiver cette option de résout pas le problème d\'affichage des éléments textuels, veuillez ouvrir un ticket sur notre GitHub, ou écrivez-nous sur notre Discord"},"libraryElementTypeError":{"embeddable":"Les éléments intégrés ne peuvent pas être ajoutés à la librairie.","image":"Le support pour l\'ajout d\'images à la librairie arrive bientôt !"}},"toolBar":{"selection":"Sélection","image":"Insérer une image","rectangle":"Rectangle","diamond":"Losange","ellipse":"Ellipse","arrow":"Flèche","line":"Ligne","freedraw":"Dessiner","text":"Texte","library":"Bibliothèque","lock":"Garder l\'outil sélectionné actif après le dessin","penMode":"Mode stylo - évite le toucher","link":"Ajouter/mettre à jour le lien pour une forme sélectionnée","eraser":"Gomme","frame":"Outil de cadre","embeddable":"Intégration Web","laser":"","hand":"Mains (outil de déplacement de la vue)","extraTools":"Plus d\'outils"},"headings":{"canvasActions":"Actions du canevas","selectedShapeActions":"Actions pour la forme sélectionnée","shapes":"Formes"},"hints":{"canvasPanning":"Pour déplacer la zone de dessin, maintenez la molette de la souris enfoncée ou la barre d\'espace tout en faisant glisser, ou utiliser l\'outil main.","linearElement":"Cliquez pour démarrer plusieurs points, faites glisser pour une seule ligne","freeDraw":"Cliquez et faites glissez, relâchez quand vous avez terminé","text":"Astuce : vous pouvez aussi ajouter du texte en double-cliquant n\'importe où avec l\'outil de sélection","embeddable":"Cliquez et glissez pour créer une intégration de site web","text_selected":"Double-cliquez ou appuyez sur ENTRÉE pour modifier le texte","text_editing":"Appuyez sur ÉCHAP ou Ctrl/Cmd+ENTRÉE pour terminer l\'édition","linearElementMulti":"Cliquez sur le dernier point ou appuyez sur Échap ou Entrée pour terminer","lockAngle":"Vous pouvez restreindre l\'angle en maintenant MAJ","resize":"Vous pouvez conserver les proportions en maintenant la touche MAJ pendant le redimensionnement, maintenez la touche ALT pour redimensionner par rapport au centre","resizeImage":"Vous pouvez redimensionner librement en maintenant SHIFT,\\nmaintenez ALT pour redimensionner depuis le centre","rotate":"Vous pouvez restreindre les angles en maintenant MAJ pendant la rotation","lineEditor_info":"Maintenez CtrlOrCmd et Double-cliquez ou appuyez sur CtrlOrCmd + Entrée pour modifier les points","lineEditor_pointSelected":"Appuyer sur Suppr. pour supprimer des points, Ctrl ou Cmd+D pour dupliquer, ou faire glisser pour déplacer","lineEditor_nothingSelected":"Sélectionner un point pour éditer (maintenir la touche MAJ pour en sélectionner plusieurs),\\nou maintenir la touche Alt enfoncée et cliquer pour ajouter de nouveaux points","placeImage":"Cliquez pour placer l\'image, ou cliquez et faites glisser pour définir sa taille manuellement","publishLibrary":"Publier votre propre bibliothèque","bindTextToElement":"Appuyer sur Entrée pour ajouter du texte","deepBoxSelect":"Maintenir Ctrl ou Cmd pour sélectionner dans les groupes et empêcher le déplacement","eraserRevert":"Maintenez Alt enfoncé pour annuler les éléments marqués pour suppression","firefox_clipboard_write":"Cette fonctionnalité devrait pouvoir être activée en définissant l\'option \\"dom.events.asyncClipboard.clipboard.clipboardItem\\" à \\"true\\". Pour modifier les paramètres du navigateur dans Firefox, visitez la page \\"about:config\\".","disableSnapping":"Maintenez CtrlOuCmd pour désactiver l\'aimantation"},"canvasError":{"cannotShowPreview":"Impossible d’afficher l’aperçu","canvasTooBig":"Le canevas est peut-être trop grand.","canvasTooBigTip":"Astuce : essayez de rapprocher un peu les éléments les plus éloignés."},"errorSplash":{"headingMain":"Une erreur est survenue. Essayez ","clearCanvasMessage":"Si le rechargement ne résout pas l\'erreur, essayez ","clearCanvasCaveat":" Cela entraînera une perte du travail ","trackedToSentry":"L\'erreur avec l\'identifiant {{eventId}} a été enregistrée dans notre système.","openIssueMessage":"Nous avons fait très attention à ne pas inclure les informations de votre scène dans l\'erreur. Si votre scène n\'est pas privée, veuillez envisager de poursuivre sur notre Veuillez inclure les informations ci-dessous en les copiant-collant dans le ticket GitHub.","sceneContent":"Contenu de la scène :"},"roomDialog":{"desc_intro":"Vous pouvez inviter des personnes à collaborer avec vous sur votre scène actuelle.","desc_privacy":"Pas d\'inquiétude, la session utilise le chiffrement de bout en bout, donc tout ce que vous dessinez restera privé. Même notre serveur ne pourra voir ce que vous faites.","button_startSession":"Démarrer la session","button_stopSession":"Arrêter la session","desc_inProgressIntro":"La session de collaboration en direct est maintenant en cours.","desc_shareLink":"Partagez ce lien avec les personnes avec lesquelles vous souhaitez collaborer :","desc_exitSession":"Arrêter la session vous déconnectera de la salle, mais vous pourrez continuer à travailler avec la scène, localement. Notez que cela n\'affectera pas les autres personnes, et ils pourront toujours collaborer sur leur version.","shareTitle":"Rejoindre une session de collaboration en direct sur Excalidraw"},"errorDialog":{"title":"Erreur"},"exportDialog":{"disk_title":"Enregistrer sur le disque","disk_details":"Exporter les données de la scène comme un fichier que vous pourrez importer ultérieurement.","disk_button":"Enregistrer comme fichier","link_title":"Lien partageable","link_details":"Exporter comme un lien en lecture seule.","link_button":"Exporter comme lien","excalidrawplus_description":"Enregistrer la scène dans votre espace de travail Excalidraw+.","excalidrawplus_button":"Exporter","excalidrawplus_exportError":"Impossible d\'exporter vers Excalidraw+ pour le moment..."},"helpDialog":{"blog":"Lire notre blog","click":"clic","deepSelect":"Sélection dans les groupes","deepBoxSelect":"Sélectionner dans les groupes, et empêcher le déplacement","curvedArrow":"Flèche courbée","curvedLine":"Ligne courbée","documentation":"Documentation","doubleClick":"double-clic","drag":"glisser","editor":"Éditeur","editLineArrowPoints":"Modifier les points de ligne/flèche","editText":"Modifier le texte / ajouter un libellé","github":"Problème trouvé ? Soumettre","howto":"Suivez nos guides","or":"ou","preventBinding":"Empêcher la liaison de flèche","tools":"Outils","shortcuts":"Raccourcis clavier","textFinish":"Terminer l\'édition (éditeur de texte)","textNewLine":"Ajouter une nouvelle ligne (éditeur de texte)","title":"Aide","view":"Affichage","zoomToFit":"Zoomer pour voir tous les éléments","zoomToSelection":"Zoomer sur la sélection","toggleElementLock":"Verrouiller/déverrouiller la sélection","movePageUpDown":"Déplacer la page vers le haut/bas","movePageLeftRight":"Déplacer la page vers la gauche/droite"},"clearCanvasDialog":{"title":"Effacer la zone de dessin"},"publishDialog":{"title":"Publier la bibliothèque","itemName":"Nom de l’élément","authorName":"Nom de l\'auteur","githubUsername":"Nom d\'utilisateur GitHub","twitterUsername":"Nom d\'utilisateur Twitter","libraryName":"Nom de la bibliothèque","libraryDesc":"Description de la bibliothèque","website":"Site web","placeholder":{"authorName":"Votre nom ou nom d\'utilisateur","libraryName":"Nom de votre bibliothèque","libraryDesc":"Description de votre bibliothèque pour aider les gens à comprendre son usage","githubHandle":"Nom d\'utilisateur GitHub (optionnel), pour que tu puisses modifier la bibliothèque une fois soumise pour vérification","twitterHandle":"Nom d\'utilisateur Twitter (optionnel), pour savoir qui créditer lors de la promotion sur Twitter","website":"Lien vers votre site web personnel ou autre (optionnel)"},"errors":{"required":"Requis","website":"Entrer une URL valide"},"noteDescription":"Soumets ta bibliothèque pour l\'inclure au dépôt de bibliothèque publiquepour permettre son utilisation par autrui dans leurs dessins.","noteGuidelines":"La bibliothèque doit d\'abord être approuvée manuellement. Veuillez lire les lignes directrices avant de la soumettre. Vous aurez besoin d\'un compte GitHub pour communiquer et apporter des modifications si demandé, mais ce n\'est pas obligatoire.","noteLicense":"En soumettant, vous acceptez que la bibliothèque soit publiée sous la Licence MIT, ce qui en gros signifie que tout le monde peut l\'utiliser sans restrictions.","noteItems":"Chaque élément de la bibliothèque doit avoir son propre nom afin qu\'il soit filtrable. Les éléments de bibliothèque suivants seront inclus :","atleastOneLibItem":"Veuillez sélectionner au moins un élément de bibliothèque pour commencer","republishWarning":"Remarque : certains des éléments sélectionnés sont marqués comme étant déjà publiés/soumis. Vous devez uniquement resoumettre des éléments lors de la mise à jour d\'une bibliothèque ou d\'une soumission existante."},"publishSuccessDialog":{"title":"Bibliothèque soumise","content":"Merci {{authorName}}. Votre bibliothèque a été soumise pour examen. Vous pouvez suivre le statutici"},"confirmDialog":{"resetLibrary":"Réinitialiser la bibliothèque","removeItemsFromLib":"Enlever les éléments sélectionnés de la bibliothèque"},"imageExportDialog":{"header":"Exporter l\'image","label":{"withBackground":"Fond","onlySelected":"Uniquement la sélection","darkMode":"Mode sombre","embedScene":"Intégrer la scène","scale":"Échelle","padding":""},"tooltip":{"embedScene":"Les données de la scène seront sauvegardées dans le fichier PNG/SVG exporté afin que la scène puisse être restaurée depuis celui-ci.\\nCela augmentera la taille du fichier exporté."},"title":{"exportToPng":"Exporter en PNG","exportToSvg":"Exporter en SVG","copyPngToClipboard":"Copier le PNG dans le presse-papier"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Copier dans le presse-papier"}},"encrypted":{"tooltip":"Vos dessins sont chiffrés de bout en bout, les serveurs d\'Excalidraw ne les verront jamais.","link":"Article de blog sur le chiffrement de bout en bout dans Excalidraw"},"stats":{"angle":"Angle","element":"Élément","elements":"Éléments","height":"Hauteur","scene":"Scène","selected":"Sélection","storage":"Stockage","title":"Stats pour les nerds","total":"Total","version":"Version","versionCopy":"Cliquer pour copier","versionNotAvailable":"Version non disponible","width":"Largeur"},"toast":{"addedToLibrary":"Ajouté à la bibliothèque","copyStyles":"Styles copiés.","copyToClipboard":"Copié dans le presse-papier.","copyToClipboardAsPng":"{{exportSelection}} copié dans le presse-papier en PNG\\n({{exportColorScheme}})","fileSaved":"Fichier enregistré.","fileSavedToFilename":"Enregistré sous {filename}","canvas":"canevas","selection":"sélection","pasteAsSingleElement":"Utiliser {{shortcut}} pour coller comme un seul élément,\\nou coller dans un éditeur de texte existant","unableToEmbed":"Intégrer cet URL n\'est actuellement pas autorisé. Ouvrez un ticket sur GitHub pour demander son ajout à la liste blanche","unrecognizedLinkFormat":"Le lien que vous avez intégré ne correspond pas au format attendu. Veuillez essayer de coller la chaîne d\'intégration fournie par le site source"},"colors":{"transparent":"Transparent","black":"Noir","white":"Blanc","red":"Rouge","pink":"Rose","grape":"Mauve","violet":"Violet","gray":"Gris","blue":"Bleu","cyan":"Cyan","teal":"Turquoise","green":"Vert","yellow":"Jaune","orange":"Orange","bronze":"Bronze"},"welcomeScreen":{"app":{"center_heading":"Toutes vos données sont sauvegardées en local dans votre navigateur.","center_heading_plus":"Vouliez-vous plutôt aller à Excalidraw+ à la place ?","menuHint":"Exportation, préférences, langues, ..."},"defaults":{"menuHint":"Exportation, préférences et plus...","center_heading":"Diagrammes. Rendus. Simples.","toolbarHint":"Choisissez un outil et commencez à dessiner !","helpHint":"Raccourcis et aide"}},"colorPicker":{"mostUsedCustomColors":"Couleurs personnalisées les plus fréquemment utilisées","colors":"Couleurs","shades":"Nuances","hexCode":"Code hex","noShades":"Aucune nuance disponible pour cette couleur"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Exporter en image","button":"Exporter en image","description":"Exporter les données de la scène comme une image que vous pourrez importer ultérieurement."},"saveToDisk":{"title":"Sauvegarder sur le disque","button":"Sauvegarder sur le disque","description":"Exporter les données de la scène comme un fichier que vous pourrez importer ultérieurement."},"excalidrawPlus":{"title":"Excalidraw+","button":"Exporter vers Excalidraw+","description":"Enregistrer la scène dans votre espace de travail Excalidraw+."}},"modal":{"loadFromFile":{"title":"Charger depuis un fichier","button":"Charger depuis un fichier","description":"Charger depuis un fichier va remplacer votre contenu existant. Vous pouvez d\'abord sauvegarder votre dessin en utilisant l\'une des options ci-dessous."},"shareableLink":{"title":"Charger depuis un lien","button":"Remplacer mon contenu","description":"Charger un dessin externe va remplacer votre contenu existant. Vous pouvez d\'abord sauvegarder votre dessin en utilisant l\'une des options ci-dessous."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/gl-ES-json-861f534b46c0db1fa8db.js b/public/excalidraw/excalidraw-assets-dev/locales/gl-ES-json-861f534b46c0db1fa8db.js
new file mode 100644
index 0000000..d1a40fb
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/gl-ES-json-861f534b46c0db1fa8db.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/gl-ES-json"],{
+
+/***/ "../../locales/gl-ES.json":
+/*!********************************!*\
+ !*** ../../locales/gl-ES.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Pegar","pasteAsPlaintext":"Pegar coma texto sen formato","pasteCharts":"Pegar gráficos","selectAll":"Seleccionar todo","multiSelect":"Engadir elemento á selección","moveCanvas":"Mover o lenzo","cut":"Cortar","copy":"Copiar","copyAsPng":"Copiar no portapapeis como PNG","copyAsSvg":"Copiar no portapapeis como SVG","copyText":"Copia no portapapeis como texto","bringForward":"Traer cara adiante","sendToBack":"Enviar cara atrás","bringToFront":"Traer á fronte","sendBackward":"Enviar ao fondo","delete":"Borrar","copyStyles":"Copiar estilo","pasteStyles":"Pegar estilo","stroke":"Trazo","background":"Fondo","fill":"Recheo","strokeWidth":"Largo do trazo","strokeStyle":"Estilo do trazo","strokeStyle_solid":"Sólido","strokeStyle_dashed":"Liña de trazos","strokeStyle_dotted":"Liña de puntos","sloppiness":"Estilo de trazo","opacity":"Opacidade","textAlign":"Aliñar texto","edges":"Bordos","sharp":"Agudo","round":"Redondo","arrowheads":"Puntas de frecha","arrowhead_none":"Ningunha","arrowhead_arrow":"Frecha","arrowhead_bar":"Barra","arrowhead_dot":"Punto","arrowhead_triangle":"Triángulo","fontSize":"Tamaño da fonte","fontFamily":"Tipo de fonte","addWatermark":"Engadir \\"Feito con Excalidraw\\"","handDrawn":"Debuxado a man","normal":"Normal","code":"Código","small":"Pequeno","medium":"Mediano","large":"Grande","veryLarge":"Moi grande","solid":"Sólido","hachure":"Folleto","zigzag":"Zigzag","crossHatch":"Raiado transversal","thin":"Estreito","bold":"Groso","left":"Esquerda","center":"Centrado","right":"Dereita","extraBold":"Moi groso","architect":"Arquitecto","artist":"Artista","cartoonist":"Caricatura","fileTitle":"Nome do arquivo","colorPicker":"Selector de cor","canvasColors":"Usado en lenzo","canvasBackground":"Fondo do lenzo","drawingCanvas":"Lenzo de debuxo","layers":"Capas","actions":"Accións","language":"Idioma","liveCollaboration":"Colaboración en directo...","duplicateSelection":"Duplicar","untitled":"Sen título","name":"Nome","yourName":"O teu nome","madeWithExcalidraw":"Feito con Excalidraw","group":"Agrupar selección","ungroup":"Desagrupar selección","collaborators":"Colaboradores","showGrid":"Mostrar cuadrícula","addToLibrary":"Engadir á biblioteca","removeFromLibrary":"Eliminar da biblioteca","libraryLoadingMessage":"Cargando biblioteca…","libraries":"Explorar bibliotecas","loadingScene":"Cargando escena…","align":"Aliñamento","alignTop":"Aliñamento superior","alignBottom":"Aliñamento inferior","alignLeft":"Aliñar a esquerda","alignRight":"Aliñar a dereita","centerVertically":"Centrar verticalmente","centerHorizontally":"Centrar horizontalmente","distributeHorizontally":"Distribuír horizontalmente","distributeVertically":"Distribuír verticalmente","flipHorizontal":"Virar horizontalmente","flipVertical":"Virar verticalmente","viewMode":"Modo de visualización","share":"Compartir","showStroke":"Mostrar selector de cores do trazo","showBackground":"Mostrar selector de cores do fondo","toggleTheme":"Alternar tema","personalLib":"Biblioteca Persoal","excalidrawLib":"Biblioteca Excalidraw","decreaseFontSize":"Diminuír tamaño da fonte","increaseFontSize":"Aumentar o tamaño da fonte","unbindText":"Desvincular texto","bindText":"Ligar o texto ao contedor","createContainerFromText":"Envolver o texto nun contedor","link":{"edit":"Editar ligazón","editEmbed":"","create":"Crear ligazón","createEmbed":"","label":"Ligazón","labelEmbed":"","empty":""},"lineEditor":{"edit":"Editar liña","exit":"Saír do editor de liñas"},"elementLock":{"lock":"Bloquear","unlock":"Desbloquear","lockAll":"Bloquear todo","unlockAll":"Desbloquear todo"},"statusPublished":"Publicado","sidebarLock":"Manter a barra lateral aberta","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Aínda non hai elementos engadidos...","hint_emptyLibrary":"Seleccione un elemento no lenzo para engadilo aquí, ou instale unha biblioteca dende o repositorio público, como se detalla a continuación.","hint_emptyPrivateLibrary":"Seleccione un elemento do lenzo para engadilo aquí."},"buttons":{"clearReset":"Limpar o lenzo","exportJSON":"Exportar a arquivo","exportImage":"Exportar imaxe...","export":"Gardar en...","copyToClipboard":"Copiar ao portapapeis","save":"Gardar no ficheiro actual","saveAs":"Gardar como","load":"Abrir","getShareableLink":"Obter unha ligazón que se poida compartir","close":"Pechar","selectLanguage":"Seleccionar idioma","scrollBackToContent":"Volver ao contido","zoomIn":"Ampliar","zoomOut":"Reducir","resetZoom":"Reiniciar zoom","menu":"Menú","done":"Feito","edit":"Editar","undo":"Desfacer","redo":"Refacer","resetLibrary":"Reiniciar biblioteca","createNewRoom":"Crear nova sala","fullScreen":"Pantalla completa","darkMode":"Modo escuro","lightMode":"Modo claro","zenMode":"Modo zen","objectsSnapMode":"","exitZenMode":"Saír do modo zen","cancel":"Cancelar","clear":"Limpar","remove":"Eliminar","embed":"","publishLibrary":"Publicar","submit":"Enviar","confirm":"Confirmar","embeddableInteractionButton":"Faga clic para interactuar"},"alerts":{"clearReset":"Isto limpará todo o lenzo. Estás seguro?","couldNotCreateShareableLink":"Non se puido crear unha ligazón para compartir.","couldNotCreateShareableLinkTooBig":"Non se puido crear a ligazón para compartir: a escena é demasiado grande","couldNotLoadInvalidFile":"Non se puido cargar o ficheiro non válido","importBackendFailed":"A importación dende o backend fallou.","cannotExportEmptyCanvas":"Non se pode exportar un lenzo baleiro.","couldNotCopyToClipboard":"Non se puido copiar ao portapapeis.","decryptFailed":"Non se poideron descifrar os datos.","uploadedSecurly":"A carga foi asegurada con cifrado de extremo a extremo, o que significa que o servidor de Excalidraw e terceiros non poden ler o contido.","loadSceneOverridePrompt":"A carga dun debuxo externo substituirá o contido existente. Desexa continuar?","collabStopOverridePrompt":"Deter a sesión, sobrescribirá o seu debuxo local previamente almacenado. Está seguro?\\n\\n(Se quere manter o seu debuxo local, simplemente peche a lapela do navegador.)","errorAddingToLibrary":"Non se puido engadir o elemento á biblioteca","errorRemovingFromLibrary":"Non se puido eliminar o elemento da biblioteca","confirmAddLibrary":"Isto engadirá {{numShapes}} forma(s) a túa biblioteca. Estás seguro?","imageDoesNotContainScene":"Esta imaxe non parece conter ningún dato da escena. Activou a inserción de escenas durante a exportación?","cannotRestoreFromImage":"Non se puido restaurar a escena dende este arquivo de imaxe","invalidSceneUrl":"Non se puido importar a escena dende a URL proporcionada. Ou ben está malformada ou non contén un JSON con información válida para Excalidraw.","resetLibrary":"Isto limpará a súa biblioteca. Está seguro?","removeItemsFromsLibrary":"Eliminar {{count}} elemento(s) da biblioteca?","invalidEncryptionKey":"A clave de cifrado debe ter 22 caracteres. A colaboración en directo está desactivada.","collabOfflineWarning":"Non hai conexión a Internet dispoñible.\\nOs teus cambios non serán gardados!"},"errors":{"unsupportedFileType":"Tipo de ficheiro non soportado.","imageInsertError":"Non se puido inserir a imaxe. Probe de novo máis tarde...","fileTooBig":"O ficheiro é demasiado grande. O tamaño máximo permitido é {{maxSize}}.","svgImageInsertError":"Non se puido inserir como imaxe SVG. O marcado SVG semella inválido.","failedToFetchImage":"","invalidSVGString":"SVG inválido.","cannotResolveCollabServer":"Non se puido conectar ao servidor de colaboración. Por favor recargue a páxina e probe de novo.","importLibraryError":"Non se puido cargar a biblioteca","collabSaveFailed":"Non se puido gardar na base de datos. Se o problema persiste, deberías gardar o teu arquivo de maneira local para asegurarte de non perdelo teu traballo.","collabSaveFailed_sizeExceeded":"Non se puido gardar na base de datos, o lenzo semella demasiado grande. Deberías gardar o teu arquivo de maneira local para asegurarte de non perdelo teu traballo.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Selección","image":"Inserir imaxe","rectangle":"Rectángulo","diamond":"Diamante","ellipse":"Elipse","arrow":"Frecha","line":"Liña","freedraw":"Debuxar","text":"Texto","library":"Biblioteca","lock":"Manter a ferramenta seleccionada activa despois de debuxar","penMode":"Modo lapis - evitar o contacto","link":"Engadir/ Actualizar ligazón para a forma seleccionada","eraser":"Goma de borrar","frame":"","embeddable":"Inserir na web","laser":"Punteiro láser","hand":"Man (ferramenta de desprazamento)","extraTools":"Máis ferramentas"},"headings":{"canvasActions":"Accións do lenzo","selectedShapeActions":"Accións da forma seleccionada","shapes":"Formas"},"hints":{"canvasPanning":"Para mover o lenzo, manteña pulsada a roda do rato ou a barra de espazo mentres arrastra, ou utilice a ferramenta da man","linearElement":"Faga clic para iniciar varios puntos, arrastre para unha sola liña","freeDraw":"Fai clic e arrastra, solta cando acabes","text":"Consello: tamén podes engadir texto facendo dobre-clic en calquera lugar coa ferramenta de selección","embeddable":"Faga clic e arrastre para crear un sitio web embebido","text_selected":"Dobre-clic ou prema ENTER para editar o texto","text_editing":"Prema Escape ou CtrlOrCmd+ENTER para finalizar a edición","linearElementMulti":"Faga clic no último punto ou prema Escape ou Enter para rematar","lockAngle":"Pode reducir o ángulo mantendo SHIFT","resize":"Pode reducir as proporcións mantendo SHIFT mentres axusta o tamaño,\\nmanteña ALT para axustalo dende o centro","resizeImage":"Pode axustar o tamaño libremente mantendo SHIFT,\\nmanteña ALT para axustalo dende o centro","rotate":"Podes reducir os ángulos mantendo SHIFT mentres os rotas","lineEditor_info":"Manteña pulsado CtrlOrCmd e faga dobre clic ou prema CtrlOrCmd + Enter para editar puntos","lineEditor_pointSelected":"Prema Suprimir para eliminar o(s) punto(s)\\nCtrlOrCmd+D para duplicalos, ou arrastre para movelos","lineEditor_nothingSelected":"Seleccione un punto para editar (manteña pulsado SHIFT para selección múltiple),\\nou manteña pulsado Alt e faga clic para engadir novos puntos","placeImage":"Faga clic para colocar a imaxe, ou faga clic e arrastre para establecer o seu tamaño manualmente","publishLibrary":"Publica a túa propia biblioteca","bindTextToElement":"Prema a tecla enter para engadir texto","deepBoxSelect":"Manteña pulsado CtrlOrCmd para seleccionar en profundidade e evitar o arrastre","eraserRevert":"Manteña pulsado Alt para reverter os elementos marcados para a súa eliminación","firefox_clipboard_write":"Esta función pódese activar establecendo a opción \\"dom.events.asyncClipboard.clipboardItem\\" a \\"true\\". Para cambiar as opcións do navegador en Firefox, visita a páxina \\"about:config\\".","disableSnapping":""},"canvasError":{"cannotShowPreview":"Non se pode mostrar a vista previa","canvasTooBig":"Pode que o lenzo sexa demasiado grande.","canvasTooBigTip":"Consello: Probe a acercar un pouco os elementos máis afastados."},"errorSplash":{"headingMain":"Atopouse un erro. Probe ","clearCanvasMessage":"Se recargar non funcionou, probe ","clearCanvasCaveat":" Isto resultará nunha perda do seu traballo ","trackedToSentry":"O erro con identificador {{eventId}} foi rastrexado no noso sistema.","openIssueMessage":"Fomos moi cautelosos de non incluír a información da súa escena no erro. Se a súa escena non é privada, por favor, considere o seguimento do noso Por favor inclúa a seguinte información copiándoa e pegándoa na issue de Github.","sceneContent":"Contido da escena:"},"roomDialog":{"desc_intro":"Podes invitar xente a colaborar contigo na túa escena actual.","desc_privacy":"Non te preocupes, a sesión usa cifrado de punto a punto, polo que calquera cousa que debuxes mantense privada. Nin tan sequera o noso servidor será capaz de ver o que fas.","button_startSession":"Comezar sesión","button_stopSession":"Rematar sesión","desc_inProgressIntro":"A sesión de colaboración en directo está agora en progreso.","desc_shareLink":"Comparte esta ligazón con calquera que queiras colaborar:","desc_exitSession":"Deter a sesión desconectarao da sala, pero poderá seguir traballando coa escena de maneira local. Teña en conta que isto non afectará a outras persoas, que poderán seguir colaborando na súa versión.","shareTitle":"Únase a unha sesión de colaboración en directo en Excalidraw"},"errorDialog":{"title":"Erro"},"exportDialog":{"disk_title":"Gardar no disco","disk_details":"Exporte os datos da escena a un ficheiro que poderás importar máis tarde.","disk_button":"Gardar nun ficheiro","link_title":"Ligazón para compartir","link_details":"Exportar como unha ligazón de só lectura.","link_button":"Exportar a unha ligazón","excalidrawplus_description":"Garde a escena no seu espazo de traballo en Excalidraw+.","excalidrawplus_button":"Exportar","excalidrawplus_exportError":"Non se puido exportar a Excalidraw+ neste momento..."},"helpDialog":{"blog":"Le o noso blog","click":"clic","deepSelect":"Selección en profundidade","deepBoxSelect":"Selección en profundidade dentro da caixa, evitando o arrastre","curvedArrow":"Frecha curva","curvedLine":"Liña curva","documentation":"Documentación","doubleClick":"dobre-clic","drag":"arrastrar","editor":"Editor","editLineArrowPoints":"","editText":"","github":"Encontrou un problema? Envíeo","howto":"Sigue as nosas normas","or":"ou","preventBinding":"Evitar a unión de frechas","tools":"Ferramentas","shortcuts":"Atallos de teclado","textFinish":"Rematar de editar (editor de texto)","textNewLine":"Engadir unha nova liña (editor de texto)","title":"Axuda","view":"Vista","zoomToFit":"Zoom que se axuste a todos os elementos","zoomToSelection":"Zoom á selección","toggleElementLock":"Bloquear/desbloquear selección","movePageUpDown":"Mover páxina cara enriba/abaixo","movePageLeftRight":"Mover páxina cara a esquerda/dereita"},"clearCanvasDialog":{"title":"Limpar lenzo"},"publishDialog":{"title":"Publicar biblioteca","itemName":"Nome do elemento","authorName":"Nome do autor","githubUsername":"Nome de usuario en Github","twitterUsername":"Nome de usuario en Twitter","libraryName":"Nome da biblioteca","libraryDesc":"Descrición da biblioteca","website":"Páxina web","placeholder":{"authorName":"O seu nome ou nome de usuario","libraryName":"Nome da súa biblioteca","libraryDesc":"Descrición da súa biblioteca para axudar a xente a entender o seu uso","githubHandle":"Nome de usuario de GitHub (opcional), así poderás editar a biblioteca unha vez enviada para a súa revisión","twitterHandle":"Nome de usuario en Twitter(opcional), así sabemos a quen darlle crédito cando se lle de promoción a través de Twitter","website":"Ligazón ao teu sitio web persoal ou a outro sitio (opcional)"},"errors":{"required":"Obrigatorio","website":"Introduza unha URL válida"},"noteDescription":"Envíe a súa biblioteca para que sexa incluída no repositorio público de bibliotecaspara que outra xente a poida usar nos seus debuxos.","noteGuidelines":"A biblioteca necesita ser aprobada manualmente primeiro. Por favor, lea as normas antes de ser enviado. Necesitarás unha conta de GitHub para comunicarte ou facer cambios se se solicitan, pero non é estritamente necesario.","noteLicense":"Ao enviar, estás de acordo con que a biblioteca sexa publicada baixo a Licenza MIT, o cal significa que, en resumo, calquera pode usalo sen restricións.","noteItems":"Cada elemento da biblioteca debe ter o seu nome propio para que se poida filtrar. Os seguintes elementos da biblioteca serán incluídos:","atleastOneLibItem":"Por favor seleccione polo menos un elemento da biblioteca para comezar","republishWarning":"Nota: algúns dos elementos seleccionados están marcados como xa publicados/enviados. Só deberías reenviar elementos cando se actualice unha biblioteca ou envío."},"publishSuccessDialog":{"title":"Biblioteca enviada","content":"Grazas {{authorName}}. A súa biblioteca foi enviada para ser revisada. Pode seguir o estadoaquí"},"confirmDialog":{"resetLibrary":"Restablecer biblioteca","removeItemsFromLib":"Eliminar os elementos seleccionados da biblioteca"},"imageExportDialog":{"header":"Exportar imaxe","label":{"withBackground":"Fondo","onlySelected":"","darkMode":"Modo escuro","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"Exportar a PNG","exportToSvg":"Exportar a SVG","copyPngToClipboard":"Copiar PNG ao portapapeis"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Copiar ao portapapeis"}},"encrypted":{"tooltip":"Os teus debuxos están cifrados de punto a punto, polo que os servidores de Excalidraw nunca os verán.","link":"Entrada do blog acerca do cifrado de punto a punto en Excalidraw"},"stats":{"angle":"Ángulo","element":"Elemento","elements":"Elementos","height":"Alto","scene":"Escena","selected":"Seleccionado","storage":"Almacenamento","title":"Estadísticas para nerds","total":"Total","version":"Versión","versionCopy":"Faga clic para copiar","versionNotAvailable":"Versión non dispoñible","width":"Ancho"},"toast":{"addedToLibrary":"Engadido á biblioteca","copyStyles":"Estilos copiados.","copyToClipboard":"Copiado ao portapapeis.","copyToClipboardAsPng":"Copiar {{exportSelection}} ao portapapeis como PNG\\n({{exportColorScheme}})","fileSaved":"Ficheiro gardado.","fileSavedToFilename":"Gardado en {filename}","canvas":"lenzo","selection":"selección","pasteAsSingleElement":"Usa {{shortcut}} para pegar como un único elemento\\nou pega nun editor de texto existente","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Transparente","black":"Negro","white":"Branco","red":"Vermello","pink":"Rosa","grape":"Uva","violet":"Violeta","gray":"Gris","blue":"Azul","cyan":"","teal":"","green":"Verde","yellow":"Marelo","orange":"Laranxa","bronze":"Bronce"},"welcomeScreen":{"app":{"center_heading":"Toda a información é gardada de maneira local no seu navegador.","center_heading_plus":"Queres ir a Excalidraw+ no seu lugar?","menuHint":"Exportar, preferencias, idiomas, ..."},"defaults":{"menuHint":"Exportar, preferencias, e máis...","center_heading":"Diagramas. Feito. Sinxelo.","toolbarHint":"Escolle unha ferramenta & Comeza a debuxar!","helpHint":"Atallos & axuda"}},"colorPicker":{"mostUsedCustomColors":"","colors":"Cores","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"Exportar como imaxe","button":"Exportar como imaxe","description":""},"saveToDisk":{"title":"Gardar no disco","button":"Gardar no disco","description":""},"excalidrawPlus":{"title":"Excalidraw+","button":"Exportar a Excalidraw+","description":""}},"modal":{"loadFromFile":{"title":"Cargar dende arquivo","button":"Cargar dende arquivo","description":""},"shareableLink":{"title":"Cargar dende un enlace","button":"Substituír o meu contido","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/he-IL-json-504d78736487793ffccd.js b/public/excalidraw/excalidraw-assets-dev/locales/he-IL-json-504d78736487793ffccd.js
new file mode 100644
index 0000000..d71603d
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/he-IL-json-504d78736487793ffccd.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/he-IL-json"],{
+
+/***/ "../../locales/he-IL.json":
+/*!********************************!*\
+ !*** ../../locales/he-IL.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"הדבק","pasteAsPlaintext":"הדבק ללא עיצוב","pasteCharts":"הדבק גרפים","selectAll":"בחר הכל","multiSelect":"הוסף רכיב לבחירה","moveCanvas":"הזז את הקנבס","cut":"גזור","copy":"העתק","copyAsPng":"העתק ללוח כ PNG","copyAsSvg":"העתק ללוח כ SVG","copyText":"העתק ללוח כטקסט","bringForward":"הבא שכבה קדימה","sendToBack":"שלח אחורה","bringToFront":"העבר לחזית","sendBackward":"העבר שכבה אחורה","delete":"מחק","copyStyles":"העתק סגנון","pasteStyles":"הדבק סגנון","stroke":"קו מתאר","background":"רקע","fill":"מילוי","strokeWidth":"עובי קו מתאר","strokeStyle":"סגנון קו המתאר","strokeStyle_solid":"מלא","strokeStyle_dashed":"מקווקו","strokeStyle_dotted":"מנוקד","sloppiness":"רישול","opacity":"אטימות","textAlign":"יישור טקסט","edges":"קצוות","sharp":"חד","round":"עגול","arrowheads":"ראשי חצים","arrowhead_none":"ללא","arrowhead_arrow":"חץ","arrowhead_bar":"קצה אנכי","arrowhead_dot":"נקודה","arrowhead_triangle":"משולש","fontSize":"גודל גופן","fontFamily":"גופן","addWatermark":"הוסף \\"נוצר באמצעות Excalidraw\\"","handDrawn":"ציור יד","normal":"רגיל","code":"קוד","small":"קטן","medium":"בינוני","large":"גדול","veryLarge":"גדול מאוד","solid":"מוצק","hachure":"קווים מקבילים קצרים להצגת כיוון וחדות שיפוע במפה","zigzag":"זיגזג","crossHatch":"קווים מוצלבים שתי וערב","thin":"דק","bold":"מודגש","left":"שמאל","center":"מרכז","right":"ימין","extraBold":"מודגש במיוחד","architect":"ארכיטקט","artist":"אמן","cartoonist":"קריקטוריסט","fileTitle":"שם קובץ","colorPicker":"בוחר צבעים","canvasColors":"בשימוש בקנבס","canvasBackground":"רקע קנבס","drawingCanvas":"קנבס ציור","layers":"שכבות","actions":"פעולות","language":"שפה","liveCollaboration":"התחל שיתוף חי...","duplicateSelection":"שכפל","untitled":"ללא כותרת","name":"שם","yourName":"שמך","madeWithExcalidraw":"נוצר באמצעות Excalidraw","group":"קבץ","ungroup":"פרק קבוצה","collaborators":"שותפים","showGrid":"הצג רשת","addToLibrary":"הוסף לספריה","removeFromLibrary":"הסר מספריה","libraryLoadingMessage":"טוען ספריה…","libraries":"עיין בספריות","loadingScene":"טוען תצוגה…","align":"יישר","alignTop":"יישר למעלה","alignBottom":"יישר למטה","alignLeft":"יישר לשמאל","alignRight":"יישר לימין","centerVertically":"מרכז אנכית","centerHorizontally":"מרכז אופקית","distributeHorizontally":"חלוקה אופקית","distributeVertically":"חלוקה אנכית","flipHorizontal":"הפוך אופקית","flipVertical":"הפוך אנכית","viewMode":"מצב תצוגה","share":"שתף","showStroke":"הצג בוחר צבע מברשת","showBackground":"הצג בוחר צבע רקע","toggleTheme":"שינוי ערכת העיצוב","personalLib":"ספריה פרטית","excalidrawLib":"הספריה של Excalidraw","decreaseFontSize":"הקטן את גודל הגופן","increaseFontSize":"הגדל את גודל הגופן","unbindText":"ביטול קיבוע הטקסט","bindText":"קיבוע הטקסט למיכל","createContainerFromText":"ארוז טקסט במיכל","link":{"edit":"עריכת קישור","editEmbed":"ערוך קישור ושבץ","create":"יצירת קישור","createEmbed":"צור קישור ושבץ","label":"קישור","labelEmbed":"קשר ושבץ","empty":"לא נקבע קישור"},"lineEditor":{"edit":"ערוך קו","exit":"צא מעורך הקו"},"elementLock":{"lock":"נעילה","unlock":"ביטול נעילה","lockAll":"לנעול הכל","unlockAll":"שחרור הכול"},"statusPublished":"פורסם","sidebarLock":"שמור את סרגל הצד פתוח","selectAllElementsInFrame":"בחר את כל האלמנטים במסגרת","removeAllElementsFromFrame":"הסר את כל האלמנטים שבמסגרת","eyeDropper":""},"library":{"noItems":"עוד לא הוספת דברים...","hint_emptyLibrary":"בחר משהו בקנבס כדי להוסיף אותו לכאן, או שתתקין ספריה מהספריה הציבורית מטה.","hint_emptyPrivateLibrary":"בחר משהו בקנבס כדי להוסיף אותו לכאן."},"buttons":{"clearReset":"אפס את הקנבאס","exportJSON":"ייצא לקובץ","exportImage":"ייצוא התמונה...","export":"שמור ל...","copyToClipboard":"העתק ללוח","save":"שמור לקובץ נוכחי","saveAs":"שמירה בשם","load":"פתח","getShareableLink":"קבל קישור לשיתוף","close":"סגור","selectLanguage":"בחר שפה","scrollBackToContent":"גלול בחזרה לתוכן","zoomIn":"הגדל","zoomOut":"הקטן","resetZoom":"איפוס זום","menu":"תפריט","done":"בוצע","edit":"ערוך","undo":"בטל","redo":"בצע מחדש","resetLibrary":"איפוס ספריה","createNewRoom":"צור חדר חדש","fullScreen":"מסך מלא","darkMode":"מצב כהה","lightMode":"מצב בהיר","zenMode":"מצב זן","objectsSnapMode":"","exitZenMode":"צא ממצב זן","cancel":"ביטול","clear":"ניקוי","remove":"הסר","embed":"","publishLibrary":"פרסום","submit":"שליחה","confirm":"אשר","embeddableInteractionButton":""},"alerts":{"clearReset":"פעולה זו תנקה את כל הקנבס. אתה בטוח?","couldNotCreateShareableLink":"יצירת קישור לשיתוף נכשל.","couldNotCreateShareableLinkTooBig":"יצירת קישור לשיתוף נכשל: התצוגה גדולה מדי","couldNotLoadInvalidFile":"טעינת קובץ לא תקין נכשלה","importBackendFailed":"ייבוא מהשרת נכשל.","cannotExportEmptyCanvas":"לא ניתן לייצא קנבאס ריק.","couldNotCopyToClipboard":"לא ניתן היה להעתיק ללוח.","decryptFailed":"פיענוח ההצפנה של המידע נכשל.","uploadedSecurly":"ההעלאה אובטחה באמצעות הצפנה מקצה לקצה, פירוש הדבר שהשרת של Excalidraw וגורמי צד ג׳ לא יכולים לקרוא את התוכן.","loadSceneOverridePrompt":"טעינה של ציור חיצוני תחליף את התוכן הקיים שלך. האם תרצה להמשיך?","collabStopOverridePrompt":"עצירת השיתוף תוביל למחיקת הציור הקודם ששמור מקומית בדפדפן. האם אתה בטוח?\\n\\n(אם תרצה לשמור את הציור המקומי, סגור את הטאב של הדפדפן במקום.)","errorAddingToLibrary":"לא ניתן להוסיף פריט לספרייה","errorRemovingFromLibrary":"לא ניתן להסיר פריט מהספריה","confirmAddLibrary":"זה יוסיף {{numShapes}} צורה(ות) לספריה שלך. האם אתה בטוח?","imageDoesNotContainScene":"נראה שהתמונה לא מכילה מידע על הסצינה. האם אפשרת הטמעת מידע הסצינה בעת השמירה?","cannotRestoreFromImage":"לא הצלחנו לשחזר את הסצנה מקובץ התמונה","invalidSceneUrl":"ייבוא מידע סצנה מהקישור שסופק כשל. או שהוא משובש, או שאינו מכיל מידע של Excalidraw בפורמט JSON.","resetLibrary":"פעולה זו תנקה את כל הספריה שלך. אתה בטוח?","removeItemsFromsLibrary":"מחק {{count}} פריט(ים) מהספריה?","invalidEncryptionKey":"מפתח ההצפנה חייב להיות בן 22 תוים. השיתוף החי מנוטרל.","collabOfflineWarning":"אין חיבור זמין לאינטרנט.\\nהשינויים שלך לא ישמרו!"},"errors":{"unsupportedFileType":"סוג הקובץ אינו נתמך.","imageInsertError":"לא ניתן היה להוסיף את התמונה. אנא נסה שוב מאוחר יותר...","fileTooBig":"הקובץ גדול מדי. הגודל המירבי המותר הינו {{maxSize}}.","svgImageInsertError":"לא ניתן היה להוסיף את תמונת ה-SVG. הסימונים בתוך קובץ ה-SVG עשויים להיות שגויים.","failedToFetchImage":"","invalidSVGString":"SVG שגוי.","cannotResolveCollabServer":"לא הצלחתי להתחבר לשרת השיתוף. אנא רענן את הדף ונסה שוב.","importLibraryError":"לא ניתן היה לטעון את הספריה","collabSaveFailed":"לא הצלחתי להתחבר למסד הנתונים האחורי. אם הבעיה ממשיכה, כדאי שתשמור את הקובץ מקומית כדי לוודא שלא תאבד את העבודה שלך.","collabSaveFailed_sizeExceeded":"לא הצלחתי לשמור למסד הנתונים האחורי, נראה שהקנבס שלך גדול מדי. כדאי שתשמור את הקובץ מקומית כדי לוודא שלא תאבד את העבודה שלך.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"בחירה","image":"הוספת תמונה","rectangle":"מלבן","diamond":"יהלום","ellipse":"אליפסה","arrow":"חץ","line":"קו","freedraw":"צייר","text":"טקסט","library":"ספריה","lock":"השאר את הכלי הנבחר פעיל גם לאחר סיום הציור","penMode":"מצב עט - מנע נגיעה","link":"הוספה/עדכון קישור של הצורה שנבחרה","eraser":"מחק","frame":"","embeddable":"","laser":"","hand":"יד (כלי הזזה)","extraTools":""},"headings":{"canvasActions":"פעולות קנבאס","selectedShapeActions":"פעולות על הצורות שנבחרו","shapes":"צורות"},"hints":{"canvasPanning":"כדי להזיז את הקנבס, החזק את גלגל העכבר לחוץ או את מקש הרווח לחוץ תוך כדי גרירה, או השתמש בכלי היד","linearElement":"לחץ להתחלת מספר נקודות, גרור לקו יחיד","freeDraw":"לחץ וגרור, שחרר כשסיימת","text":"טיפ: אפשר להוסיף טקסט על ידי לחיצה כפולה בכל מקום עם כלי הבחירה","embeddable":"","text_selected":"לחץ לחיצה כפולה או הקש על אנטר לעריכת הטקסט","text_editing":"כדי לסיים את העריכה לחץ על מקש Escape או על Ctrl (Cmd במחשבי אפל) ומקש Enter","linearElementMulti":"הקלק על הנקודה האחרונה או הקש Escape או Enter לסיום","lockAngle":"ניתן להגביל את הזוויות על ידי החזקה של מקש ה- SHIFT","resize":"ניתן להגביל פרופורציות על ידי לחיצה על SHIFT תוך כדי שינוי גודל,\\nהחזק ALT בשביל לשנות גודל ביחס למרכז","resizeImage":"אתה יכול לשנות את הגודל בחופשיות על ידי החזקת מקש SHIFT,\\nהחזק את מקש ALT כדי לבצע שינוי גודל מהמרכז","rotate":"ניתן להגביל זוויות על ידי לחיצה על SHIFT תוך כדי סיבוב","lineEditor_info":"החזק Ctrl / Cmd ובצע לחיצה כפולה או לחץ Ctrl / Cmd + Enter לעריכת נקודות","lineEditor_pointSelected":"לחץ Delete למחיקת נקודה/ות,\\nCtrl / Cmd + D לשכפול, או גרור להזזה","lineEditor_nothingSelected":"בחר נקודה כדי לערוך (החזק SHIFT לבחירת כמה),\\nאו החזק Alt והקלק להוספת נקודות חדשות","placeImage":"הקלק להנחת התמונה, או הקלק וגרור להגדרת הגודל שלו ידנית","publishLibrary":"פרסם ספריה משלך","bindTextToElement":"הקש Enter כדי להוספת טקסט","deepBoxSelect":"החזק Ctrl / Cmd לבחירה עמוקה ולמניעת גרירה","eraserRevert":"החזק Alt להחזרת רכיבים מסומנים למחיקה","firefox_clipboard_write":"יכולות זה ניתנת להפעלה על ידי שינוי הדגל של \\"dom.events.asyncClipboard.clipboardItem\\" למצב \\"true\\". כדי לשנות את הדגל בדפדפן Firefox, בקר בעמוד ״about:config״.","disableSnapping":""},"canvasError":{"cannotShowPreview":"לא ניתן להראות תצוגה מקדימה","canvasTooBig":"הקנבס עלול להיות גדול מדי.","canvasTooBigTip":"טיפ: נסה להזיז את הרכיבים הרחוקים ביותר מעט קרוב יותר האחד לשני."},"errorSplash":{"headingMain":"","clearCanvasMessage":"אם טעינה מחדש לא עובדת, נסה ","clearCanvasCaveat":" זה יגרום לאובדן העבודה ","trackedToSentry":"","openIssueMessage":"","sceneContent":"תוכן הקנבאס:"},"roomDialog":{"desc_intro":"אתה יכול להזמין אנשים לקנבאס הנוכחי שלך לעבודה משותפת.","desc_privacy":"אל דאגה, השיתוף מוצפן מקצה לקצה, כך שכל מה שתצייר ישאר פרטי. אפילו השרתים שלנו לא יוכלו לראות את מה שאתה ממציא.","button_startSession":"התחל שיתוף","button_stopSession":"הפסק שיתוף","desc_inProgressIntro":"שיתוף חי פעיל כרגע.","desc_shareLink":"שתף את הקישור עם כל מי שאתה מעוניין לעבוד אתו:","desc_exitSession":"עצירת השיתוף תנתק אותך מהחדר, אבל עדיין תוכל להמשיך לעבוד על הקנבאס, מקומית. שים לב שזה לא ישפיע על אנשים אחרים, והם עדיין יוכלו לבצע שיתוף עם הגרסה שלהם.","shareTitle":"הצטרף לשיתוף לעבודה משותפת חיה, בזמן אמת, על גבי Excalidraw"},"errorDialog":{"title":"שגיאה"},"exportDialog":{"disk_title":"שמור לכונן","disk_details":"ייצא מידע של הקנבאס לקובץ שתוכל לייבא אחר כך.","disk_button":"שמירה לקובץ","link_title":"קבל קישור לשיתוף","link_details":"ייצוא כקישור לקריאה בלבד.","link_button":"ייצוא לקישור","excalidrawplus_description":"שמור את הקנבאס לסביבת העבודה שלך ב- +Excalidraw.","excalidrawplus_button":"ייצוא","excalidrawplus_exportError":"לא הצלחתי לייצא ל- +Excalidraw כרגע..."},"helpDialog":{"blog":"קרא את הבלוג שלנו","click":"קליק","deepSelect":"בחירה עמוקה","deepBoxSelect":"בחירה עמוקה בתוך קופסה ומניעת גרירה","curvedArrow":"חץ מעוגל","curvedLine":"קו מעוגל","documentation":"תיעוד","doubleClick":"לחיצה כפולה","drag":"גרור","editor":"עורך","editLineArrowPoints":"","editText":"","github":"מצאת בעיה? דווח","howto":"עקוב אחר המדריכים שלנו","or":"או","preventBinding":"למנוע נעיצת חיצים","tools":"כלים","shortcuts":"קיצורי מקלדת","textFinish":"סיים עריכה (עורך טקסט)","textNewLine":"הוסף שורה חדשה (עורך טקסט)","title":"עזרה","view":"תצוגה","zoomToFit":"זום להתאמת כל האלמנטים למסך","zoomToSelection":"התמקד בבחירה","toggleElementLock":"נעילה/ביטול הנעילה של הרכיבים הנבחרים","movePageUpDown":"זוז עמוד למעלה/למטה","movePageLeftRight":"זוז עמוד שמאלה/ימינה"},"clearCanvasDialog":{"title":"ניקוי הקנבס"},"publishDialog":{"title":"פרסם ספריה","itemName":"שם הפריט","authorName":"שם היוצר","githubUsername":"שם המשתמש שלך ב-GitHub","twitterUsername":"שם המשתמש שלך ב-Twitter","libraryName":"שם הספריה","libraryDesc":"תיאור הספריה","website":"אתר","placeholder":{"authorName":"שמך או שם המשתמש שלך","libraryName":"תנו שם לספריה","libraryDesc":"תיאור של הספריה שלך כדי לסייע למשתמשים להבין את השימוש בה","githubHandle":"כינוי GitHub (לא חובה), כדי שתוכל לערוך את הספרית לאחר שנשלחה לבדיקה","twitterHandle":"שם משתמש טוויטר (לא חובה), כדי שנדע למי לתת קרדיט כשאנחנו מפרסמים בטוויטר","website":"קישור לאתר הפרטי שלך או לכל מקום אחר (אופציונאלי)"},"errors":{"required":"נדרש","website":"הזינו כתובת URL תקינה"},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"לכל פריט בסיפריה חייב להיות שם כדי שאפשר יהיה לסנן. הפריטי סיפריה הבאים יהיו כלולים:","atleastOneLibItem":"אנא בחר לפחות פריט אחד מספריה כדי להתחיל","republishWarning":"הערה: חלק מהפריטים שבחרת מסומנים ככאלו שכבר פורסמו/נשלחו. אתה צריך לשלוח פריטים מחדש כאשר אתה מעדכן ספריה או הגשה קיימים."},"publishSuccessDialog":{"title":"הספריה הוגשה","content":"תודה {{authorName}}. הספריה שלך נשלחה לבחינה. תוכל לעקוב אחרי סטטוס הפרסום"},"confirmDialog":{"resetLibrary":"איפוס ספריה","removeItemsFromLib":"הסר את הפריטים הנבחרים מהספריה"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"הציורים שלך מוצפנים מקצה לקצה כך שהשרתים של Excalidraw לא יראו אותם לעולם.","link":"פוסט בבלוג על הצפנה מקצה לקצב ב-Excalidraw"},"stats":{"angle":"זווית","element":"רכיב","elements":"רכיבים","height":"גובה","scene":"תצוגה","selected":"נבחר","storage":"אחסון","title":"סטטיסטיקות לחנונים","total":"סה״כ","version":"גרסה","versionCopy":"לחץ להעתקה","versionNotAvailable":"הגרסה אינה זמינה","width":"רוחב"},"toast":{"addedToLibrary":"נוסף לספריה","copyStyles":"סגנונות הועתקו.","copyToClipboard":"הועתק ללוח.","copyToClipboardAsPng":"{{exportSelection}} הועתקה ללוח כ-PNG\\n({{exportColorScheme}})","fileSaved":"קובץ נשמר.","fileSavedToFilename":"נשמר לקובץ {filename}","canvas":"קנבאס","selection":"בחירה","pasteAsSingleElement":"השתמש ב- {{shortcut}} כדי להדביק כפריט יחיד,\\nאו הדבק לתוך עורך טקסט קיים","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"שקוף","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"כל המידע שלח נשמר מקומית בדפדפן.","center_heading_plus":"אתה רוצה ללכת אל Excalidraw+ במקום?","menuHint":"ייצוא, העדפות, שפות, ..."},"defaults":{"menuHint":"ייצוא, העדפות, ועוד...","center_heading":"איורים. נעשים. פשוטים.","toolbarHint":"בחר כלי & והתחל לצייר!","helpHint":"קיצורים & עזרה"}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/hi-IN-json-82d988431011c330242a.js b/public/excalidraw/excalidraw-assets-dev/locales/hi-IN-json-82d988431011c330242a.js
new file mode 100644
index 0000000..d6417f6
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/hi-IN-json-82d988431011c330242a.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/hi-IN-json"],{
+
+/***/ "../../locales/hi-IN.json":
+/*!********************************!*\
+ !*** ../../locales/hi-IN.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"चिपकाएँ","pasteAsPlaintext":"सादे पाठ के रूप में चिपकाएं","pasteCharts":"चार्ट चिपकाएँ","selectAll":"सभी चुनें","multiSelect":"आकार को चयन में जोड़ें","moveCanvas":"कैनवास को स्थानांतरित करें","cut":"काटें","copy":"प्रतिलिपि","copyAsPng":"क्लिपबोर्ड पर कॉपी करें ,पीएनजी के रूप में","copyAsSvg":"क्लिपबोर्ड पर कॉपी करें,एसवीजी के रूप में","copyText":"लेखन के रूप में पटल पर कॉपी करें","bringForward":"सामने लाएं","sendToBack":"पीछे भेजें","bringToFront":"सामने लाएँ","sendBackward":"पीचे भीजे","delete":"मिटाए","copyStyles":"कॉपी स्टाइल","pasteStyles":"स्टाइल पेस्ट करें","stroke":"रेखा","background":"पृष्ठभूमि","fill":"भरें","strokeWidth":"रेखा की चौड़ाई","strokeStyle":"स्ट्रोक का आकार","strokeStyle_solid":"ठोस","strokeStyle_dashed":"डैश","strokeStyle_dotted":"बिंदीदार","sloppiness":"बेढ़ंगापन","opacity":"अपारदर्शिता","textAlign":"टेक्स्ट संरेखन","edges":"किनारा","sharp":"नुकीला","round":"गोल","arrowheads":"तीर शीर्ष","arrowhead_none":"कोई भी नहीं","arrowhead_arrow":"तीर","arrowhead_bar":"बार","arrowhead_dot":"बिंदु","arrowhead_triangle":"त्रिकोण","fontSize":"फ़ॉन्ट का आकार","fontFamily":"फ़ॉन्ट का परिवार","addWatermark":"ऐड \\"मेड विथ एक्सकैलिडराव\\"","handDrawn":"हाथ से बनाया हुआ","normal":"साधारण","code":"कोड","small":"छोटा","medium":"मध्यम","large":"बड़ा","veryLarge":"बहुत बड़ा","solid":"दृढ़","hachure":"हैशूर","zigzag":"तेढ़ी मेढ़ी","crossHatch":"क्रॉस हैच","thin":"पतला","bold":"मोटा","left":"बाएं","center":"मध्य","right":"दाएँ","extraBold":"बहुत मोटा","architect":"वास्तुकार","artist":"कलाकार","cartoonist":"व्यंग्य चित्रकार","fileTitle":"फ़ाइल का नाम","colorPicker":"रंग चयन","canvasColors":"कॅनवास पर प्रयोगित","canvasBackground":"कैनवास बैकग्राउंड","drawingCanvas":"कैनवास बना रहे हैं","layers":"परतें","actions":"कार्रवाई","language":"भाषा","liveCollaboration":"जीवंत सहयोग...","duplicateSelection":"डुप्लिकेट","untitled":"अशीर्षित","name":"नाम","yourName":"आपका नाम","madeWithExcalidraw":"मेड विथ एक्सकैलिडराव","group":"समूह चयन","ungroup":"समूह चयन असमूहीकृत करें","collaborators":"सहयोगी","showGrid":"ग्रिड दिखाएं","addToLibrary":"लाइब्रेरी से जोड़ें","removeFromLibrary":"लाइब्रेरी से निकालें","libraryLoadingMessage":"लाइब्रेरी खुल रही है","libraries":"लाइब्रेरी ब्राउज़ करें","loadingScene":"दृश्य खुल रहा है","align":"संरेखित करें","alignTop":"ऊपर संरेखित करें","alignBottom":"नीचे संरेखित करें","alignLeft":"बायें संरेखित करें","alignRight":"दायें संरेखित करें","centerVertically":"लंबवत केन्द्रित","centerHorizontally":"क्षैतिज केन्द्रित","distributeHorizontally":"क्षैतिज रूप से वितरित करें","distributeVertically":"खड़ी रूप से वितरित करें","flipHorizontal":"दायें बायें पलटे","flipVertical":"ऊपर नीचे पलटे","viewMode":"अलग अलग देखें","share":"शेयर करें","showStroke":"","showBackground":"पृष्ठभूमि रंग वरक़ दिखाये","toggleTheme":"","personalLib":"","excalidrawLib":"","decreaseFontSize":"आकार घटाइऐ","increaseFontSize":"फ़ॉन्ट आकार बढ़ाएँ","unbindText":"","bindText":"लेखन को कोश से जोड़े","createContainerFromText":"मूलपाठ कंटेनर में मोड के दिखाए","link":{"edit":"","editEmbed":"","create":"","createEmbed":"","label":"","labelEmbed":"","empty":""},"lineEditor":{"edit":"रेखा संपादित करे","exit":"रेखा संपादक के बाहर"},"elementLock":{"lock":"ताले में रखें","unlock":"ताले से बाहर","lockAll":"सब ताले के अंदर रखे","unlockAll":"सब ताले के बाहर निकाले"},"statusPublished":"प्रकाशित","sidebarLock":"साइडबार खुला रखे.","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":"चित्रफलक से रंग चुने"},"library":{"noItems":"अभी तक कोई आइटम जोडा नहीं गया.","hint_emptyLibrary":"यहाँ जोड़ने के लिए पटल से एक वस्तु चुने, अथवा जन कोष से एक संग्रह नीचे स्थापित करें.","hint_emptyPrivateLibrary":"यहाँ जोड़ने के लिए पटल से एक वस्तु चुने."},"buttons":{"clearReset":"कैनवास रीसेट करें","exportJSON":"","exportImage":"प्रतिमा निर्यात करे...","export":"यंहा सुरक्षित करे...","copyToClipboard":"क्लिपबोर्ड पर प्रतिलिपि बनाएँ","save":"","saveAs":"सेव करे इस तरह","load":"खोलें","getShareableLink":"साझा करने योग्य लिंक प्राप्त करें","close":"बंद करें","selectLanguage":"भाषा चुनें","scrollBackToContent":"सामग्री पर वापस स्क्रॉल करें","zoomIn":"बड़ा करें","zoomOut":"छोटा करें","resetZoom":"ज़ूम रीसेट करें","menu":"मेन्यू","done":"समाप्त","edit":"संशोधन करें","undo":"पूर्ववत् करें","redo":"फिर से करें","resetLibrary":"","createNewRoom":"एक नया कमरा बनाएं","fullScreen":"पूरी स्क्रीन","darkMode":"डार्क मोड","lightMode":"लाइट मोड","zenMode":"ज़ेन मोड","objectsSnapMode":"वस्तुओं से पकड़े","exitZenMode":"जेन मोड से बाहर निकलें","cancel":"","clear":"साफ़ करे","remove":"हटाएं","embed":"","publishLibrary":"प्रकाशित करें","submit":"प्रस्तुत करे","confirm":"पुष्टि करें","embeddableInteractionButton":""},"alerts":{"clearReset":"इससे पूरा कैनवास साफ हो जाएगा। क्या आपको यकीन है?","couldNotCreateShareableLink":"साझा करने योग्य लिंक नहीं बनाया जा सका।","couldNotCreateShareableLinkTooBig":"लिंक शेयर नहीं कर सकता: दृश्य बहुत बड़ा","couldNotLoadInvalidFile":"अमान्य फ़ाइल लोड नहीं की जा सकी","importBackendFailed":"बैकएंड से आयात करना विफल रहा।","cannotExportEmptyCanvas":"खाली कैनवास निर्यात नहीं कर सकता।","couldNotCopyToClipboard":"क्लिपबोर्ड पर कॉपी नहीं किया जा सका","decryptFailed":"डेटा को डिक्रिप्ट नहीं किया जा सका।","uploadedSecurly":"अपलोड को एंड-टू-एंड एन्क्रिप्शन के साथ सुरक्षित किया गया है, जिसका मतलब है कि एक्सक्लूसिव सर्वर और थर्ड पार्टी कंटेंट नहीं पढ़ सकते हैं।","loadSceneOverridePrompt":"लोड हो रहा है बाहरी ड्राइंग आपके मौजूदा सामग्री को बदल देगा। क्या आप जारी रखना चाहते हैं?","collabStopOverridePrompt":"चालू सत्र समाप्ति से आपका संग्रहित पूर्व स्थानीय अधिलेखन नष्ट होकर पुनः अधिलेखित होगा, क्या आपको यक़ीन हैं? ( यदी आपको पूर्व स्थापित अधिलेखन सुरक्षित चाहिये तो बस ब्राउज़र टैब बंद करे)","errorAddingToLibrary":"संग्रह में जोडा न जा सका","errorRemovingFromLibrary":"संग्रह से हटाया नहीं जा सका","confirmAddLibrary":"लाइब्रेरी जोड़ें पुष्टि करें आकार संख्या","imageDoesNotContainScene":"ऐसा लगता है कि इस छवि में कोई दृश्य डेटा नहीं है। क्या आपने निर्यात के दौरान दृश्य एम्बेडिंग अनुमतित की है?","cannotRestoreFromImage":"छवि फ़ाइल बहाल दृश्य नहीं है","invalidSceneUrl":"दिये गये युआरेल से दृश्य आयात नहीं किया जा सका. यह या तो अनुचित है, या इसमें उचित Excalidraw JSON डेटा नहीं है।","resetLibrary":"यह पूरा संग्रह रिक्त करेगा. क्या आपको यक़ीन हैं?","removeItemsFromsLibrary":"{{count}} वस्तु(यें) संग्रह से हटायें?","invalidEncryptionKey":"कूटलेखन कुंजी 22 अक्षरों की होनी चाहिये, इसलिये जीवंत सहयोग अक्षम हैं","collabOfflineWarning":"कोई इंटरनेट कनेक्शन उपलब्ध नहीं है।\\nआपके बदलाव सहेजे नहीं जाएंगे!"},"errors":{"unsupportedFileType":"असमर्थित फाइल प्रकार","imageInsertError":"छवि सम्मिलित नहीं की जा सकी. पुनः प्रयत्न करे...","fileTooBig":"फ़ाइल ज़रूरत से ज़्यादा बड़ी हैं. अधिकतम अनुमित परिमाण {{maxSize}} हैं","svgImageInsertError":"एसवीजी छवि सम्मिलित नहीं कर सके, एसवीजी रचना अनुचित हैं","failedToFetchImage":"","invalidSVGString":"अनुचित SVG","cannotResolveCollabServer":"कॉलेब सर्वर से कनेक्शन नहीं हो पा रहा. कृपया पृष्ठ को पुनः लाने का प्रयास करे.","importLibraryError":"संग्रह प्रतिष्ठापित नहीं किया जा सका","collabSaveFailed":"किसी कारण वश अंदरूनी डेटाबेस में सहेजा नहीं जा सका। यदि समस्या बनी रहती है, तो किये काम को खोने न देने के लिये अपनी फ़ाइल को स्थानीय रूप से सहेजे।","collabSaveFailed_sizeExceeded":"लगता है कि पृष्ठ तल काफ़ी बड़ा है, इस्कारण अंदरूनी डेटाबेस में सहेजा नहीं जा सका। किये काम को खोने न देने के लिये अपनी फ़ाइल को स्थानीय रूप से सहेजे।","brave_measure_text_error":{"line1":"लगता है कि आप Brave ब्राउज़र का उपयोग कर रहे और साथ में आक्रामक उँगलियो के छाप का चयन किया हुवा है","line2":"यह आपके चित्रों के पाठ तत्वोंको खंडित कर सकता हैं","line3":"हमें आपसे ठोस आग्रह है की आप सेट्टिंग में इस विकल्प का चयन ना करे. इस अनुक्रम का पालन करके इसका पता लगा सकते हैं","line4":"यदि इस सेटिंग्स को अक्षम करने पर भी पृष्ठ ठीक नहीं दिखता हो तो, हमारे GitHub पर एक मुद्दा प्रस्तुत करे, या हमें डिस्कोर्ड पर लिखित सम्पर्क करें"},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"चयन","image":"छवि सम्मिलित करें","rectangle":"आयात","diamond":"तिर्यग्वर्ग","ellipse":"दीर्घवृत्त","arrow":"तीर","line":"रेखा","freedraw":"चित्रांतित करे","text":"पाठ","library":"लाइब्रेरी","lock":"ड्राइंग के बाद चयनित टूल को सक्रिय रखें","penMode":"पेन का मोड - स्पर्श टाले","link":"","eraser":"रबड़","frame":"","embeddable":"","laser":"लेसर टॉर्च","hand":"हाथ ( खिसकाने का औज़ार)","extraTools":""},"headings":{"canvasActions":"कैनवास क्रिया","selectedShapeActions":"चयनित आकृति क्रियाएं","shapes":"आकृतियाँ"},"hints":{"canvasPanning":"कैनवास को सरकाने के लिए, ड्रैग करते समय माउस व्हील को पकड़े रखे या स्पेसबार को दबाए रखे, अथवा हाथ वाले औज़ार का उपयोग करें","linearElement":"कई बिंदुओं को शुरू करने के लिए क्लिक करें, सिंगल लाइन के लिए खींचें","freeDraw":"क्लिक करें और खींचें। समाप्त करने के लिए, छोड़ो","text":"आप चयन टूल से कहीं भी डबल-क्लिक करके टेक्स्ट जोड़ सकते हैं","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"अंतिम बिंदु पर क्लिक करें या समाप्त होने के लिए एस्केप या एंटर दबाएं","lockAngle":"आप घूर्णन करते समय SHIFT पकड़कर कोणों को मोड़ सकते हैं","resize":"आकार बदलते समय आप SHIFT को पकड़ कर अनुपात में कमी कर सकते हैं,\\nकेंद्र से आकार बदलने के लिए ALT दबाए रखें","resizeImage":"","rotate":"आप घूर्णन करते समय SHIFT पकड़कर कोणों को विवश कर सकते हैं","lineEditor_info":"बिंदुओं को सम्पादित करने के लिए CtrlOrCmd को दबायें रखते हुये डबल क्लिक करे, अथवा CtrlOrCmd + Enter साथ दबाये","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"मिटाने के लिए चुने हुए चीजों को ना चुनने के लिए Alt साथ में दबाए","firefox_clipboard_write":"\\"dom.events.asyncClipboard.clipboardItem\\" फ़्लैग को \\"true\\" पर सेट करके इस सुविधा को संभवतः सक्षम किया जा सकता है। Firefox में ब्राउज़र फ़्लैग बदलने के लिए, \\"about:config\\" पृष्ठ पर जाएँ।","disableSnapping":"स्नैपिंग को निष्क्रिय करने के लिए CtrlOrCmd दबाए रखें"},"canvasError":{"cannotShowPreview":"पूर्वावलोकन नहीं दिखा सकते हैं","canvasTooBig":"कैनवास बहुत बड़ा","canvasTooBigTip":"कैनवास बहुत बड़ा टिप"},"errorSplash":{"headingMain":"एक त्रुटि का सामना करना पड़ा। प्रयत्न ","clearCanvasMessage":"यदि पुनः लोड करना काम नहीं करता है, तो प्रयास करें ","clearCanvasCaveat":" इससे काम का नुकसान होगा ","trackedToSentry":"पहचानकर्ता के साथ त्रुटि {{eventId}} हमारे सिस्टम पर नज़र रखी गई थी।","openIssueMessage":"हम बहुत सतर्क थे कि त्रुटि पर आपकी दृश्य जानकारी शामिल न करें। यदि आपका दृश्य निजी नहीं है, तो कृपया हमारे बारे में विचार करें कृपया GitHub मुद्दे को कॉपी और पेस्ट करके नीचे दी गई जानकारी शामिल करें।","sceneContent":"दृश्य सामग्री:"},"roomDialog":{"desc_intro":"आप अपने वर्तमान दृश्य के लोगों को अपने साथ सहयोग करने के लिए आमंत्रित कर सकते हैं।","desc_privacy":"चिंता न करें, सत्र अंत-से-अंत एन्क्रिप्शन का उपयोग करता है, इसलिए आप जो भी ड्रा करेंगे वह निजी रहेगा। यहां तक कि हमारा सर्वर भी नहीं देख पाएगा कि आप क्या कर रहे हैं।","button_startSession":"सत्र प्रारंभ करें","button_stopSession":"सत्र रुकें","desc_inProgressIntro":"लाइव सहयोग सत्र अब जारी है।","desc_shareLink":"इस लिंक को आप जिस किसी के साथ भी सहयोग करना चाहते हैं, उसके साथ साझा करें","desc_exitSession":"सत्र रोकना आपको रूम से बाहर कर देगा, लेकिन आप स्थानीय स्तर पर दृश्य के साथ काम करना जारी रख पाएंगे। ध्यान दें कि यह अन्य लोगों को प्रभावित नहीं करेगा, और वे अभी भी अपने संस्करण पर सहयोग करने में सक्षम होंगे।","shareTitle":""},"errorDialog":{"title":"गलती"},"exportDialog":{"disk_title":"","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"","excalidrawplus_exportError":""},"helpDialog":{"blog":"हमारा ब्लॉग पढे","click":"क्लिक करें","deepSelect":"","deepBoxSelect":"","curvedArrow":"वक्र तीर","curvedLine":"वक्र रेखा","documentation":"","doubleClick":"","drag":"खींचें","editor":"संपादक","editLineArrowPoints":"रेखा/तीर बिंदु सम्पादित करे","editText":"पाठ्य सम्पादित करे/ लेबल जोड़े","github":"मुद्दा मिला? प्रस्तुत करें","howto":"हमारे गाइड का पालन करें","or":"या","preventBinding":"तीर बंधन रोकें","tools":"औज़ार","shortcuts":"कीबोर्ड के शॉर्टकट्स","textFinish":"","textNewLine":"","title":"मदद","view":"दृश्य","zoomToFit":"सभी तत्वों को फिट करने के लिए ज़ूम करें","zoomToSelection":"चयन तक ज़ूम करे","toggleElementLock":"ताले के अंदर/बाहर चुनाव","movePageUpDown":"पृष्ठ ऊपर/नीचे करे","movePageLeftRight":"पृष्ठ बायी/दायी तरफ करे"},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"","githubUsername":"","twitterUsername":"","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":"मान्य URL प्रविष्ट करें"},"noteDescription":"संग्रह सम्मिलित करने हेतु प्रस्तुत करें सार्वजनिक संग्रहालयअन्य वक्तियों को उनके चित्रकारी में उपयोग के लिये","noteGuidelines":"संग्रह को पहले स्वीकृति आवश्यक कृपया यह पढ़ें दिशा-निर्देश","noteLicense":"जमा करके, आप सहमत हैं कि संग्रहण को MIT लाइसेंस के तहत प्रकाशित किया जाएगा, जिसका संक्षिप्त अर्थ है कि कोई भी बिना किसी प्रतिबंध के उनका उपयोग कर सकता है।","noteItems":"","atleastOneLibItem":"","republishWarning":"टिप्पणी: कुछ चुने हुवे आइटम पहले ही प्रकाशित/प्रस्तुत किए जा चुके हैं। किसी प्रकाशित संग्रह को अद्यतन करते समय या पहले से प्रस्तुत आइटम को पुन्हा प्रस्तुत करते समय, आप बस उसे केवल अद्यतन करें ।"},"publishSuccessDialog":{"title":"","content":"{{authorName}} धन्यवाद. आपका संग्रहण समीक्षा के लिए दर्ज हो चुका है. समीक्षा स्थिति यहाँजान सकते हैं."},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"आपके चित्र अंत-से-अंत एन्क्रिप्टेड हैं, इसलिए एक्सक्लूसिव्रॉव के सर्वर उन्हें कभी नहीं देखेंगे।","link":""},"stats":{"angle":"कोण","element":"एलिमेंट","elements":"एलिमेंट","height":"ऊंचाई","scene":"दृश्य","selected":"चयनित","storage":"संग्रह","title":"बेवकूफ के लिए आँकड़े","total":"कुल","version":"संस्करण","versionCopy":"काॅपी करने के लिए क्लिक करें","versionNotAvailable":"संस्करण उपलब्ध नहीं है","width":"चौड़ाई"},"toast":{"addedToLibrary":"","copyStyles":"काॅपी कीए स्टाइल","copyToClipboard":"क्लिपबोर्ड में कॉपी कीए","copyToClipboardAsPng":"","fileSaved":"","fileSavedToFilename":"","canvas":"","selection":"","pasteAsSingleElement":"एक अवयव के रूप में चिपकाने के लिए {{shortcut}} का उपयोग करें,\\nया किसी मौजूदा पाठ संपादक में चिपकायें","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"काला","white":"सफ़ेद","red":"लाल","pink":"गुलाबी","grape":"अंगूरी","violet":"जामुनी","gray":"गहरा","blue":"नीला","cyan":"आसमानी","teal":"हरा-नीला","green":"हरा","yellow":"पीला","orange":"नारंगी","bronze":"कांस्य"},"welcomeScreen":{"app":{"center_heading":"आपका सर्व डेटा ब्राउज़र के भीतर स्थानिक जगह पे सुरक्षित किया गया.","center_heading_plus":"बजाय आपको Excalidraw+ पर जाना है?","menuHint":"निर्यात, पसंद, भाषायें, ..."},"defaults":{"menuHint":"निर्यात, पसंद, और भी...","center_heading":"चित्रांकन। बनाया गया। सरल।","toolbarHint":"एक औजार चुने और चित्रकारी प्रारंभ करे!","helpHint":"शॉर्ट्कट और सहाय्य"}},"colorPicker":{"mostUsedCustomColors":"अधिकांश उपयोगित रंग","colors":"रंग","shades":"छाया","hexCode":"हेक्स कोड","noShades":"इस रंग की कोई छाया उपलब्ध नहीं हैं"},"overwriteConfirm":{"action":{"exportToImage":{"title":"छवि स्वरूप में निर्यात करे","button":"छवि स्वरूप निर्यात करे","description":"दृष्य डेटा छवि स्वरूप में निर्यात करे, उस स्वरूप से आप उसे पुनः आयात कर सकते हो"},"saveToDisk":{"title":"डिस्क में सम्हाले","button":"डिस्क में सम्हाले","description":"दृष्य डेटा बाहरी फ़ाइल में निर्यात करे, जहाँसे आप उसे पुनः आयात कर सकते हो"},"excalidrawPlus":{"title":"एक्षकालीड्रॉ+","button":"एक्षकालीड्रॉ+ में निर्यात करे","description":"दृष्य को आपके एक्षकालीड्रॉ+ के कर्यस्थल में सम्हाले"}},"modal":{"loadFromFile":{"title":"फ़ाइल से लोड करें:","button":"फ़ाइल से लोड करें:","description":"फ़ाइल से लोड करने पर यह आपके कार्य की जगह लेलेगा आपकी ड्रॉइंग निम्न दर्शित विकल्पो में से एक चुनके और उपयोग करके सम्हाल सकते हैं"},"shareableLink":{"title":"लिंक से लोड करें:","button":"इस जगह प्रतिस्थापित करे","description":"बाहर का चित्र लोड करने पर यह आपके कार्य की जगह लेलेगा आप आपकी ड्रॉइंग पहले निम्न दर्शित विकल्पो में से एक चुनके और उपयोग करके सम्हाल सकते हों."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/hu-HU-json-d4150250980011726fd9.js b/public/excalidraw/excalidraw-assets-dev/locales/hu-HU-json-d4150250980011726fd9.js
new file mode 100644
index 0000000..0c4a2a2
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/hu-HU-json-d4150250980011726fd9.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/hu-HU-json"],{
+
+/***/ "../../locales/hu-HU.json":
+/*!********************************!*\
+ !*** ../../locales/hu-HU.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Beillesztés","pasteAsPlaintext":"","pasteCharts":"Grafikon beillesztése","selectAll":"Összes kijelölése","multiSelect":"Elem hozzáadása a kijelöléshez","moveCanvas":"Vászon mozgatása","cut":"Kivágás","copy":"Másolás","copyAsPng":"Vágólapra másolás mint PNG","copyAsSvg":"Vágólapra másolás mint SVG","copyText":"","bringForward":"Előrébb hozás","sendToBack":"Hátraküldés","bringToFront":"Előrehozás","sendBackward":"Hátrébb küldés","delete":"Törlés","copyStyles":"Stílus másolása","pasteStyles":"Stílus beillesztése","stroke":"Körvonal","background":"Háttér","fill":"Kitöltés","strokeWidth":"Körvonal vastagsága","strokeStyle":"Körvonal stílusa","strokeStyle_solid":"Kitöltött","strokeStyle_dashed":"Szaggatott","strokeStyle_dotted":"Pontozott","sloppiness":"Stílus","opacity":"Áttetszőség","textAlign":"Szöveg igazítása","edges":"Szélek","sharp":"Éles","round":"Kerek","arrowheads":"Nyílhegyek","arrowhead_none":"Nincs","arrowhead_arrow":"Nyíl","arrowhead_bar":"Oszlop","arrowhead_dot":"Pont","arrowhead_triangle":"Háromszög","fontSize":"Betűméret","fontFamily":"Betűkészlet család","addWatermark":"Add hozzá, hogy \\"Excalidraw-val készült\\"","handDrawn":"Kézzel rajzolt","normal":"Normál","code":"Kód","small":"Kicsi","medium":"Közepes","large":"Nagy","veryLarge":"Nagyon nagy","solid":"Kitöltött","hachure":"Vonalkázott","zigzag":"","crossHatch":"Keresztcsíkozott","thin":"Vékony","bold":"Félkövér","left":"Bal","center":"Közép","right":"Jobb","extraBold":"Extra Félkövér","architect":"Tervezői","artist":"Művészi","cartoonist":"Karikatúrás","fileTitle":"Fájlnév","colorPicker":"Színválasztó","canvasColors":"Rajzvászonon használt","canvasBackground":"Vászon háttérszíne","drawingCanvas":"Rajzvászon","layers":"Rétegek","actions":"Műveletek","language":"Nyelv","liveCollaboration":"","duplicateSelection":"Duplikálás","untitled":"Névtelen","name":"Név","yourName":"Neved","madeWithExcalidraw":"Excalidraw-val készült","group":"Csoportosítás","ungroup":"Csoportbontás","collaborators":"Közreműködők","showGrid":"Rács megjelenítése","addToLibrary":"Hozzáadás a könyvtárhoz","removeFromLibrary":"Eltávólítás a könyvtárból","libraryLoadingMessage":"Könyvtár betöltése…","libraries":"Könyvtárak böngészése","loadingScene":"Jelenet betöltése…","align":"Igazítás","alignTop":"Felülre igazítás","alignBottom":"Alulra igazítás","alignLeft":"Balra igazítás","alignRight":"Jobbra igazítás","centerVertically":"Függőlegesen középre igazított","centerHorizontally":"Vízszintesen középre igazított","distributeHorizontally":"Vízszintes elosztás","distributeVertically":"Függőleges elosztás","flipHorizontal":"Vízszintes tükrözés","flipVertical":"Függőleges tükrözés","viewMode":"Nézet","share":"Megosztás","showStroke":"Körvonal színválasztó megjelenítése","showBackground":"Háttérszín-választó megjelenítése","toggleTheme":"Téma váltása","personalLib":"Személyes könyvtár","excalidrawLib":"Excalidraw könyvtár","decreaseFontSize":"Betűméret csökkentése","increaseFontSize":"Betűméret növelése","unbindText":"Szövegkötés feloldása","bindText":"","createContainerFromText":"","link":{"edit":"Hivatkozás szerkesztése","editEmbed":"","create":"Hivatkozás létrehozása","createEmbed":"","label":"Hivatkozás","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"","unlock":"","lockAll":"","unlockAll":""},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"Vászon törlése","exportJSON":"Exportálás fájlba","exportImage":"","export":"","copyToClipboard":"Vágólapra másolás","save":"Mentés az aktuális fájlba","saveAs":"Mentés másként","load":"","getShareableLink":"Megosztható link létrehozása","close":"Bezárás","selectLanguage":"Nyelv kiválasztása","scrollBackToContent":"Visszagörgetés a tartalomhoz","zoomIn":"Nagyítás","zoomOut":"Kicsinyítés","resetZoom":"Nagyítás alaphelyzetbe","menu":"Menü","done":"Kész","edit":"Szerkesztés","undo":"Vissza","redo":"Újra","resetLibrary":"Könyvtár alaphelyzetbe állítása","createNewRoom":"Új szoba létrehozása","fullScreen":"Teljes képernyő","darkMode":"Sötét mód","lightMode":"Világos mód","zenMode":"Letisztult mód","objectsSnapMode":"","exitZenMode":"Kilépés a letisztult módból","cancel":"Mégsem","clear":"Kiűrítés","remove":"Eltávolítás","embed":"","publishLibrary":"Közzététel","submit":"Elküldés","confirm":"Megerősítés","embeddableInteractionButton":""},"alerts":{"clearReset":"Ez a művelet törli a vászont. Biztos benne?","couldNotCreateShareableLink":"Nem sikerült megosztható linket létrehozni.","couldNotCreateShareableLinkTooBig":"Nem sikerült megosztható linket látrehozni: túl nagy a jelenet","couldNotLoadInvalidFile":"Nem sikerült betölteni a helytelen fájlt","importBackendFailed":"Nem sikerült betölteni a szerverről.","cannotExportEmptyCanvas":"Üres vászont nem lehet exportálni.","couldNotCopyToClipboard":"","decryptFailed":"Nem sikerült visszafejteni a titkosított adatot.","uploadedSecurly":"A feltöltést végpontok közötti titkosítással biztosítottuk, ami azt jelenti, hogy egy harmadik fél nem tudja megnézni a tartalmát, beleértve az Excalidraw szervereit is.","loadSceneOverridePrompt":"A betöltött külső rajz felül fogja írnia meglévőt. Szeretnéd folytatni?","collabStopOverridePrompt":"A munkamenet leállítása felül fogja írni az előzőleg helyben tárolt rajzot. Biztosan ezt akarod?\\n(Ha meg akarod tartani a helyben tárolt rajzot, egyszerűen csak zárd be a böngésző fület)","errorAddingToLibrary":"A tétel nem addható hozzá a könyvtárhoz","errorRemovingFromLibrary":"A tétel nem távolítható el a könyvtárból","confirmAddLibrary":"Ez a művelet {{numShapes}} formát fog hozzáadni a könyvtáradhoz. Biztos vagy benne?","imageDoesNotContainScene":"Úgy tűnik, hogy ez a kép nem tartalmaz jelenetadatokat. Engedélyezted a jelenetbeágyazást az exportálás során?","cannotRestoreFromImage":"A jelenet visszaállítása nem sikerült ebből a kép fájlból","invalidSceneUrl":"Nem sikerült importálni a jelenetet a megadott URL-ről. Rossz formátumú, vagy nem tartalmaz érvényes Excalidraw JSON-adatokat.","resetLibrary":"Ezzel törlöd a könyvtárát. biztos vagy ebben?","removeItemsFromsLibrary":"{{count}} elemet törölsz a könyvtárból?","invalidEncryptionKey":"A titkosítási kulcsnak 22 karakterből kell állnia. Az élő együttműködés le van tiltva.","collabOfflineWarning":""},"errors":{"unsupportedFileType":"Nem támogatott fájltípus.","imageInsertError":"Nem sikerült beszúrni a képet. Próbáld újra később...","fileTooBig":"A fájl túl nagy. A megengedett maximális méret {{maxSize}}.","svgImageInsertError":"Nem sikerült beszúrni az SVG-képet. Az SVG szintaktika érvénytelennek tűnik.","failedToFetchImage":"","invalidSVGString":"Érvénytelen SVG.","cannotResolveCollabServer":"","importLibraryError":"","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Kijelölés","image":"Kép beszúrása","rectangle":"Téglalap","diamond":"Rombusz","ellipse":"Ellipszis","arrow":"Nyíl","line":"Vonal","freedraw":"Rajzolás","text":"Szöveg","library":"Könyvtár","lock":"Rajzolás után az aktív eszközt tartsa kijelölve","penMode":"","link":"Hivatkozás hozzáadása/frissítése a kiválasztott alakzathoz","eraser":"","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"Vászon műveletek","selectedShapeActions":"Kijelölt forma műveletei","shapes":"Alakzatok"},"hints":{"canvasPanning":"","linearElement":"Kattintással görbe, az eger húzásával pedig egyenes nyilat rajzolhatsz","freeDraw":"Kattints és húzd, majd engedd el, amikor végeztél","text":"Tipp: A kijelölés eszközzel a dupla kattintás új szöveget hoz létre","embeddable":"","text_selected":"Kattints duplán, vagy nyomj entert a szöveg szerkesztéséhez","text_editing":"Nyomjd meg az Escape vagy a Ctrl/Cmd+ENTER billentyűkombinációt a szerkesztés befejezéséhez","linearElementMulti":"Kattints a következő ív pozíciójára, vagy fejezd be a nyilat az Escape vagy Enter megnyomásával","lockAngle":"A SHIFT billentyű lenyomva tartásával korlátozhatja forgatás szögét","resize":"A SHIFT billentyű lenyomva tartásával az átméretezés megtartja az arányokat,\\naz ALT lenyomva tartásával pedig a középpont egy helyben marad","resizeImage":"A SHIFT billentyű lenyomva tartásával szabadon átméretezheted,\\ntartsd lenyomva az ALT billentyűt a középről való átméretezéshez","rotate":"A SHIFT billentyű lenyomva tartásával korlátozhatja a szögek illesztését","lineEditor_info":"","lineEditor_pointSelected":"Nyomd meg a Törlés gombot a pont(ok) eltávolításához,\\nA Ctrl/Cmd+D a többszörözéshez, vagy húzással mozgathatja","lineEditor_nothingSelected":"Válaszd ki a szerkeszteni kívánt pontot (több kijelöléséhez tartsd lenyomva a SHIFT billentyűt),\\nvagy Alt, és kattintson az új pontok hozzáadásához","placeImage":"Kattints a kép elhelyezéséhez, vagy kattints és méretezd manuálisan","publishLibrary":"Tedd közzé saját könyvtáradat","bindTextToElement":"Nyomd meg az Entert szöveg hozzáadáshoz","deepBoxSelect":"Tartsd lenyomva a Ctrl/Cmd billentyűt a mély kijelöléshez és a húzás megakadályozásához","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"Előnézet nem jeleníthető meg","canvasTooBig":"A vászon talán túl nagy.","canvasTooBigTip":"Tipp: próbáld meg a legtávolabbi elemeket közelebb hozni egy máshoz."},"errorSplash":{"headingMain":"Hiba történt. Próbáld ","clearCanvasMessage":"Ha az újratöltés nem működik, próbáld ","clearCanvasCaveat":" Ezzel az eddigi munka elveszik ","trackedToSentry":"A hibakód azonosítóval {{eventId}} nyomon van követve a rendszerünkben.","openIssueMessage":"Vigyáztunk arra, hogy a jelenthez tartozó információ ne jelenjen meg a hibaüzenetben. Ha a jeleneted nem bizalmas, kérjük add hozzá a Kérjük, másolja be az alábbi információkat a GitHub problémába.","sceneContent":"Jelenet tartalma:"},"roomDialog":{"desc_intro":"Meghívhat embereket a jelenlegi jelenetbe, hogy együttműködjenek önnel.","desc_privacy":"Ne aggódj, a munkamenet végpontok közötti titkosítást használ, tehát bármit rajzolsz, privát marad. Még a szerverünkről se lehet belenézni.","button_startSession":"Munkamenet indítása","button_stopSession":"Munkamenet leállítása","desc_inProgressIntro":"Az élő együttműködési munkamenet folyamatban van.","desc_shareLink":"Ossza meg ezt a linket bárkivel, akivel együtt szeretne működni:","desc_exitSession":"Az munkamenet leállítása kilépteti önt a szobából, de folytathatja a munkát a saját gépén. Vegye figyelembe, hogy ez nem érinti más emberek munkáját és ők továbbra is együttműködhetnek a saját változatukon.","shareTitle":"Csatlakozás egy élő együttműködési munkamenethez az Excalidraw-ban"},"errorDialog":{"title":"Hiba"},"exportDialog":{"disk_title":"Mentés lemezre","disk_details":"Exportálja a jelenetadatokat egy fájlba, amelyből később importálhatja.","disk_button":"Mentés fájlba","link_title":"Megosztható hivatkozás","link_details":"Exportálás csak olvasható hivatkozásként.","link_button":"Exportálás hivatkozásba","excalidrawplus_description":"Mentse el a jelenetet az Excalidraw+ munkaterületére.","excalidrawplus_button":"Exportálás","excalidrawplus_exportError":"Jelenleg nem lehet exportálni az Excalidraw+-ba..."},"helpDialog":{"blog":"Olvasd a blogunkat","click":"kattintás","deepSelect":"Mély kijelölés","deepBoxSelect":"Mély kijelölés a dobozon belül, és a húzás megakadályozása","curvedArrow":"Ívelt nyíl","curvedLine":"Ívelt vonal","documentation":"Dokumentáció","doubleClick":"dupla kattintás","drag":"vonszolás","editor":"Szerkesztő","editLineArrowPoints":"","editText":"","github":"Hibát találtál? Küld be","howto":"Kövesd az útmutatóinkat","or":"vagy","preventBinding":"A nyíl ne ragadjon","tools":"","shortcuts":"Gyorsbillentyűk","textFinish":"Szerkesztés befejezése (szöveg)","textNewLine":"Új sor hozzáadása (szöveg)","title":"Segítség","view":"Nézet","zoomToFit":"Az összes elem látótérbe hozása","zoomToSelection":"Kijelölésre nagyítás","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":"Rajzvászon alaphelyzetbe"},"publishDialog":{"title":"Könyvtár közzététele","itemName":"Tétel neve","authorName":"Szerző neve","githubUsername":"GitHub felhasználónév","twitterUsername":"Twitter felhasználónév","libraryName":"Könyvtár neve","libraryDesc":"Könyvtár leírása","website":"Weboldal","placeholder":{"authorName":"Neved vagy felhasználóneved","libraryName":"A könyvtárad neve","libraryDesc":"A könyvtárad használatát segítő leírás","githubHandle":"GitHub-handle(opcionális), így szerkesztheted a könyvtárat, miután elküldted ellenőrzésre","twitterHandle":"Twitter-felhasználónév (opcionális), így tudjuk, kinek kell jóváírni a Twitteren keresztüli reklámozást","website":"Hivatkozás személyes webhelyedre vagy máshová (nem kötelező)"},"errors":{"required":"Kötelező","website":"Adj meg egy érvényes URL-t"},"noteDescription":"Küld be könyvtáradat, hogy bekerüljön a nyilvános könyvtár tárolóbahogy mások is felhasználhassák a rajzaikban.","noteGuidelines":"A könyvtárat először manuálisan kell jóváhagyni. Kérjük, olvassa el a segédletet benyújtása előtt. Szüksége lesz egy GitHub-fiókra a kommunikációhoz és a módosításokhoz, ha kérik, de ez nem feltétlenül szükséges.","noteLicense":"A beküldéssel elfogadja, hogy a könyvtár a következő alatt kerül közzétételre MIT Licensz ami röviden azt jelenti, hogy bárki korlátozás nélkül használhatja őket.","noteItems":"Minden könyvtárelemnek saját nevével kell rendelkeznie, hogy szűrhető legyen. A következő könyvtári tételek kerülnek bele:","atleastOneLibItem":"A kezdéshez válassz ki legalább egy könyvtári elemet","republishWarning":""},"publishSuccessDialog":{"title":"A könyvtár beküldve","content":"Köszönjük {{authorName}}. Könyvtáradat elküldtük felülvizsgálatra. Nyomon követheted az állapototitt"},"confirmDialog":{"resetLibrary":"Könyvtár alaphelyzetbe állítása","removeItemsFromLib":"A kiválasztott elemek eltávolítása a könyvtárból"},"imageExportDialog":{"header":"Kép exportálása","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"A rajzaidat végpontok közötti titkosítással tároljuk, tehát az Excalidraw szervereiről se tud más belenézni.","link":"Blogbejegyzés a végpontok közötti titkosításról az Excalidraw-ban"},"stats":{"angle":"Szög","element":"Elem","elements":"Elemek","height":"Magasság","scene":"Jelenet","selected":"Kijelölt","storage":"Tárhely","title":"Statisztikák","total":"Összesen","version":"Verzió","versionCopy":"Kattints a másoláshoz","versionNotAvailable":"A verzió nem elérhető","width":"Szélesség"},"toast":{"addedToLibrary":"Könyvtárhoz adva","copyStyles":"Másolt stílusok.","copyToClipboard":"Vágólapra másolva.","copyToClipboardAsPng":"Az {{exportSelection}} PNG formátumban a vágólapra másolva \\n({{exportColorScheme}})","fileSaved":"Fájl elmentve.","fileSavedToFilename":"Mentve mint {filename}","canvas":"rajzvászon","selection":"kijelölés","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Átlátszó","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/id-ID-json-82e300d4fe1e87adba9b.js b/public/excalidraw/excalidraw-assets-dev/locales/id-ID-json-82e300d4fe1e87adba9b.js
new file mode 100644
index 0000000..86d5c94
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/id-ID-json-82e300d4fe1e87adba9b.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/id-ID-json"],{
+
+/***/ "../../locales/id-ID.json":
+/*!********************************!*\
+ !*** ../../locales/id-ID.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Tempel","pasteAsPlaintext":"Tempel sebagai teks biasa","pasteCharts":"Tempel diagram","selectAll":"Pilih semua","multiSelect":"Tambahkan elemen ke pilihan","moveCanvas":"Pindahkan kanvas","cut":"Potong","copy":"Salin","copyAsPng":"Salin ke papan klip sebagai PNG","copyAsSvg":"Salin ke papan klip sebagai SVG","copyText":"Salin ke papan klip sebagai teks","bringForward":"Bawa maju","sendToBack":"Kirim ke belakang","bringToFront":"Bawa ke depan","sendBackward":"Kirim mundur","delete":"Hapus","copyStyles":"Salin gaya","pasteStyles":"Tempelkan gaya","stroke":"Guratan","background":"Latar","fill":"Isian","strokeWidth":"Lebar guratan","strokeStyle":"Gaya guratan","strokeStyle_solid":"Padat","strokeStyle_dashed":"Putus-putus","strokeStyle_dotted":"Titik-titik","sloppiness":"Kecerobohan","opacity":"Keburaman","textAlign":"Perataan teks","edges":"Tepi","sharp":"Tajam","round":"Bulat","arrowheads":"Mata panah","arrowhead_none":"Tidak ada","arrowhead_arrow":"Panah","arrowhead_bar":"Batang","arrowhead_dot":"Titik","arrowhead_triangle":"Segitiga","fontSize":"Ukuran font","fontFamily":"Jenis font","addWatermark":"Tambahkan \\"Dibuat dengan Excalidraw\\"","handDrawn":"Tulisan tangan","normal":"Normal","code":"Kode","small":"Kecil","medium":"Sedang","large":"Besar","veryLarge":"Sangat besar","solid":"Padat","hachure":"Garis-garis","zigzag":"Zigzag","crossHatch":"Asiran silang","thin":"Lembut","bold":"Tebal","left":"Kiri","center":"Tengah","right":"Kanan","extraBold":"Sangat tebal","architect":"Arsitek","artist":"Artis","cartoonist":"Kartunis","fileTitle":"Nama file","colorPicker":"Pilihan Warna","canvasColors":"Digunakan di kanvas","canvasBackground":"Latar Kanvas","drawingCanvas":"Kanvas","layers":"Lapisan","actions":"Aksi","language":"Bahasa","liveCollaboration":"Kolaborasi langsung...","duplicateSelection":"Duplikat","untitled":"Tanpa judul","name":"Nama","yourName":"Nama Anda","madeWithExcalidraw":"Dibuat dengan Excalidraw","group":"Kelompokan pilihan","ungroup":"Pisahkan pilihan","collaborators":"Kolaborator","showGrid":"Tampilkan grid","addToLibrary":"Tambahkan ke pustaka","removeFromLibrary":"Hapus dari pustaka","libraryLoadingMessage":"Memuat pustaka…","libraries":"Telusur pustaka","loadingScene":"Memuat pemandangan…","align":"Perataan","alignTop":"Rata atas","alignBottom":"Rata bawah","alignLeft":"Rata kiri","alignRight":"Rata kanan","centerVertically":"Pusatkan secara vertikal","centerHorizontally":"Pusatkan secara horizontal","distributeHorizontally":"Distribusikan horizontal","distributeVertically":"Distribusikan vertikal","flipHorizontal":"Balikkan horizontal","flipVertical":"Balikkan vertikal","viewMode":"Mode tampilan","share":"Bagikan","showStroke":"Tampilkan garis pengambil warna","showBackground":"Tampilkan latar pengambil warna","toggleTheme":"Ubah tema","personalLib":"Pustaka Pribadi","excalidrawLib":"Pustaka Excalidraw","decreaseFontSize":"Kecilkan ukuran font","increaseFontSize":"Besarkan ukuran font","unbindText":"Lepas teks","bindText":"Kunci teks ke kontainer","createContainerFromText":"Bungkus teks dalam kontainer","link":{"edit":"Edit tautan","editEmbed":"","create":"Buat tautan","createEmbed":"","label":"Tautan","labelEmbed":"","empty":""},"lineEditor":{"edit":"Edit tautan","exit":"Keluar editor garis"},"elementLock":{"lock":"Kunci","unlock":"Lepas","lockAll":"Kunci semua","unlockAll":"Lepas semua"},"statusPublished":"Telah terbit","sidebarLock":"Biarkan sidebar tetap terbuka","selectAllElementsInFrame":"Pilih semua elemen di bingkai","removeAllElementsFromFrame":"Hapus semua elemen dari bingkai","eyeDropper":"Ambil warna dari kanvas"},"library":{"noItems":"Belum ada item yang ditambahkan...","hint_emptyLibrary":"Pilih item pada kanvas untuk menambahkan nya di sini, atau pasang pustaka dari gudang di bawah ini.","hint_emptyPrivateLibrary":"Pilih item pada kanvas untuk menambahkan nya di sini."},"buttons":{"clearReset":"Setel Ulang Kanvas","exportJSON":"Ekspor ke file","exportImage":"Ekspor gambar...","export":"Simpan ke...","copyToClipboard":"Salin ke Papan Klip","save":"Simpan ke file sekarang","saveAs":"Simpan sebagai","load":"Buka","getShareableLink":"Buat Tautan yang Bisa Dibagian","close":"Tutup","selectLanguage":"Pilih bahasa","scrollBackToContent":"Gulir kembali ke konten","zoomIn":"Besarkan","zoomOut":"Kecilkan","resetZoom":"Reset Pembesaran","menu":"Menu","done":"Selesai","edit":"Edit","undo":"Urungkan","redo":"Ulangi","resetLibrary":"Reset pustaka","createNewRoom":"Buat ruang baru","fullScreen":"Layar penuh","darkMode":"Mode gelap","lightMode":"Mode terang","zenMode":"Mode zen","objectsSnapMode":"","exitZenMode":"Keluar dari mode zen","cancel":"Batal","clear":"Hapus","remove":"Hapus","embed":"","publishLibrary":"Terbitkan","submit":"Kirimkan","confirm":"Konfirmasi","embeddableInteractionButton":""},"alerts":{"clearReset":"Ini akan menghapus semua yang ada dikanvas. Apakah kamu yakin ?","couldNotCreateShareableLink":"Tidak bisa membuat tautan yang bisa dibagikan","couldNotCreateShareableLinkTooBig":"Tidak dapat membuat tautan yang dapat dibagikan: pemandangan terlalu besar","couldNotLoadInvalidFile":"Tidak dapat memuat berkas yang tidak valid","importBackendFailed":"Gagal mengimpor dari backend","cannotExportEmptyCanvas":"Tidak bisa mengekspor kanvas kosong","couldNotCopyToClipboard":"Tidak bisa menyalin ke papan klip.","decryptFailed":"Tidak dapat mengdekripsi data.","uploadedSecurly":"Pengunggahan ini telah diamankan menggunakan enkripsi end-to-end, artinya server Excalidraw dan pihak ketiga tidak data membaca nya","loadSceneOverridePrompt":"Memuat gambar external akan mengganti konten Anda yang ada. Apakah Anda ingin melanjutkan?","collabStopOverridePrompt":"Menghentikan sesi akan menimpa gambar Anda yang tersimpan secara lokal. Anda yakin?\\n\\n(Jika Anda ingin menyimpan gambar lokal Anda, gantinya cukup tutup tab browser.)","errorAddingToLibrary":"Tidak dapat menambahkan item ke pustaka","errorRemovingFromLibrary":"Tidak dapat membuang item dari pustaka","confirmAddLibrary":"Ini akan menambahkan {{numShapes}} bentuk ke pustaka Anda. Anda yakin?","imageDoesNotContainScene":"Gambar ini sepertinya tidak terdapat data pemandangan. Sudahkah Anda mengaktifkan penyematan pemandangan ketika ekspor?","cannotRestoreFromImage":"Pemandangan tidak dapat dipulihkan dari file gambar ini","invalidSceneUrl":"Tidak dapat impor pemandangan dari URL. Kemungkinan URL itu rusak atau tidak berisi data JSON Excalidraw yang valid.","resetLibrary":"Ini akan menghapus pustaka Anda. Anda yakin?","removeItemsFromsLibrary":"Hapus {{count}} item dari pustaka?","invalidEncryptionKey":"Sandi enkripsi harus 22 karakter. Kolaborasi langsung dinonaktifkan.","collabOfflineWarning":"Tidak ada koneksi internet.\\nPerubahan tidak akan disimpan!"},"errors":{"unsupportedFileType":"Tipe file tidak didukung.","imageInsertError":"Tidak dapat menyisipkan gambar. Coba lagi nanti...","fileTooBig":"File terlalu besar. Ukuran maksimum yang dibolehkan {{maxSize}}.","svgImageInsertError":"Tidak dapat menyisipkan gambar SVG. Markup SVG sepertinya tidak valid.","failedToFetchImage":"","invalidSVGString":"SVG tidak valid.","cannotResolveCollabServer":"Tidak dapat terhubung ke server kolab. Muat ulang laman dan coba lagi.","importLibraryError":"Tidak dapat memuat pustaka","collabSaveFailed":"Tidak dapat menyimpan ke dalam basis data server. Jika masih berlanjut, Anda sebaiknya simpan berkas Anda secara lokal untuk memastikan pekerjaan Anda tidak hilang.","collabSaveFailed_sizeExceeded":"Tidak dapat menyimpan ke dalam basis data server, tampaknya ukuran kanvas terlalu besar. Anda sebaiknya simpan berkas Anda secara lokal untuk memastikan pekerjaan Anda tidak hilang.","brave_measure_text_error":{"line1":"Sepertinya Anda menggunkan peramban Brave dengan pengaturan Blokir Fingerprinting yang Agresif diaktifkan.","line2":"Ini dapat membuat Elemen Teks dalam gambar mu.","line3":"Kami sangat menyarankan mematikan pengaturan ini. Anda dapat mengikuti langkah-langkah ini untuk melakukannya.","line4":"Jika mematikan pengaturan ini tidak membenarkan tampilan elemen teks, mohon buka\\nisu di GitHub kami, atau chat kami di Discord"},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Pilihan","image":"Sisipkan gambar","rectangle":"Persegi","diamond":"Berlian","ellipse":"Elips","arrow":"Panah","line":"Garis","freedraw":"Gambar","text":"Teks","library":"Pustaka","lock":"Biarkan alat yang dipilih aktif setelah menggambar","penMode":"Mode pena - mencegah sentuhan","link":"Tambah/Perbarui tautan untuk bentuk yang dipilih","eraser":"Penghapus","frame":"Alat bingkai","embeddable":"","laser":"","hand":"Tangan (alat panning)","extraTools":"Alat-alat lain"},"headings":{"canvasActions":"Opsi Kanvas","selectedShapeActions":"Opsi bentuk yang dipilih","shapes":"Bentuk"},"hints":{"canvasPanning":"Untuk memindahkan kanvas, tekan roda mouse atau spacebar sambil menyeret, atau menggunakan alat tangan","linearElement":"Klik untuk memulai banyak poin, seret untuk satu baris","freeDraw":"Klik dan seret, lepaskan jika Anda selesai","text":"Tip: Anda juga dapat menambahkan teks dengan klik ganda di mana saja dengan alat pemilihan","embeddable":"","text_selected":"Klik ganda atau tekan ENTER untuk edit teks","text_editing":"Tekan Escape atau CtrlAtauCmd+ENTER untuk selesai mengedit","linearElementMulti":"Klik pada titik akhir atau tekan Escape atau Enter untuk menyelesaikan","lockAngle":"Anda dapat menjaga sudut dengan menahan SHIFT","resize":"Anda dapat menjaga proposi dengan menekan SHIFT sambil mengubah ukuran,\\ntekan AlT untuk mengubah ukuran dari tengah","resizeImage":"Anda dapat mengubah secara bebas dengan menekan SHIFT,\\nTekan ALT untuk mengubah dari tengah","rotate":"Anda dapat menjaga sudut dengan menahan SHIFT sambil memutar","lineEditor_info":"Tekan Ctrl/Cmd dan Dobel-klik atau tekan Ctrl/Cmd +Enter untuk mengedit poin","lineEditor_pointSelected":"Tekan Delete untuk menghapus titik, Ctrl/Cmd + D untuk menduplikasi, atau seret untuk memindahkan","lineEditor_nothingSelected":"Pilih titik untuk mengedit (tekan SHIFT untuk pilih banyak), atau tekan Alt dan klik untuk tambahkan titik baru","placeImage":"Klik untuk tempatkan gambar, atau klik dan jatuhkan untuk tetapkan ukuran secara manual","publishLibrary":"Terbitkan pustaka Anda","bindTextToElement":"Tekan enter untuk tambahkan teks","deepBoxSelect":"Tekan Ctrl atau Cmd untuk memilih yang di dalam, dan mencegah penggeseran","eraserRevert":"Tahan Alt untuk mengembalikan elemen yang ditandai untuk dihapus","firefox_clipboard_write":"Fitur ini dapat diaktifkan melalui pengaturan flag \\"dom.events.asyncClipboard.clipboardItem\\" ke \\"true\\". Untuk mengganti flag di Firefox, pergi ke laman \\"about:config\\".","disableSnapping":""},"canvasError":{"cannotShowPreview":"Tidak dapat menampilkan pratinjau","canvasTooBig":"Kanvas mungkin terlalu besar.","canvasTooBigTip":"Tip: coba pindahkan elemen-terjauh lebih dekat bersama."},"errorSplash":{"headingMain":"Mengalami sebuah kesalahan. Cobalah ","clearCanvasMessage":"Jika memuat ulang tidak bekerja, cobalah ","clearCanvasCaveat":" Ini akan menghasilkan hilangnya pekerjaan ","trackedToSentry":"Kesalahan dengan pengidentifikasi {{eventId}} dilacak di sistem kami.","openIssueMessage":"Kami sangat berhati-hati untuk tidak menyertakan informasi pemandangan Anda pada kesalahan. Jika pemandangan Anda tidak bersifat pribadi, mohon pertimbangkan menindak lanjut pada Mohon sertakan informasi dibawah ini dengan menyalin dan menempelkan di Github issue.","sceneContent":"Pemandangan konten:"},"roomDialog":{"desc_intro":"Anda dapat mengundang orang ke pemandangan Anda saat ini untuk berkolaborasi dengan Anda.","desc_privacy":"Jangan khawatir, sesi menggunakan enkripsi end-to-end, sehingga apa pun yang Anda gambar akan tetap bersifat pribadi. Bahkan server kami tidak dapat melihat apa yang Anda lakukan.","button_startSession":"Mulai sesi","button_stopSession":"Hentikan sesi","desc_inProgressIntro":"Sesi kolaborasi sedang berlangsung sekarang.","desc_shareLink":"Bagikan tautan ini dengan siapa pun yang Anda inginkan untuk kolaborasi bersama:","desc_exitSession":"Menghentikan sesi akan memutuskan hubungan Anda dari ruangan, tetapi Anda dapat melanjutkan bekerja dengan pemandangan Anda secara lokal. Perhatikan bahwa ini tidak memengaruhi orang lain, dan mereka masih dapat berkolaborasi pada versi mereka.","shareTitle":"Gabung sesi kolaborasi langsung di Excalidraw"},"errorDialog":{"title":"Kesalahan"},"exportDialog":{"disk_title":"Simpan ke disk","disk_details":"Ekspor data pemandangan ke file yang mana Anda dapat impor nanti.","disk_button":"Simpan ke file","link_title":"Tautan","link_details":"Ekspor sebagai tautan yang hanya dibaca.","link_button":"Ekspor ke tautan","excalidrawplus_description":"Simpan pemandangan ke ruang kerja Excalidraw+ Anda.","excalidrawplus_button":"Ekspor","excalidrawplus_exportError":"Tidak dapat ekspor ke Excalidraw+ saat ini..."},"helpDialog":{"blog":"Baca blog kami","click":"klik","deepSelect":"Pilih dalam","deepBoxSelect":"Pilih dalam kotak, dan cegah penggeseran","curvedArrow":"Panah lengkung","curvedLine":"Garis lengkung","documentation":"Dokumentasi","doubleClick":"klik-ganda","drag":"seret","editor":"Editor","editLineArrowPoints":"Edit titik garis/panah","editText":"Edit teks / tambah label","github":"Menemukan masalah? Kirimkan","howto":"Ikuti panduan kami","or":"atau","preventBinding":"Cegah pengikatan panah","tools":"Alat","shortcuts":"Pintasan keyboard","textFinish":"Selesai mengedit (editor teks)","textNewLine":"Tambahkan garis baru (editor teks)","title":"Bantuan","view":"Tampilan","zoomToFit":"Perbesar agar sesuai dengan semua elemen","zoomToSelection":"Perbesar ke seleksi","toggleElementLock":"Kunci/lepas seleksi","movePageUpDown":"Pindah halaman keatas/kebawah","movePageLeftRight":"Pindah halaman kebawah/keatas"},"clearCanvasDialog":{"title":"Hapus kanvas"},"publishDialog":{"title":"Terbitkan pustaka","itemName":"Nama item","authorName":"Nama pembuat","githubUsername":"Nama pengguna github","twitterUsername":"Nama pengguna Twitter","libraryName":"Nama Pustaka","libraryDesc":"Deskripsi pustaka","website":"Situs Web","placeholder":{"authorName":"Nama atau nama pengguna Anda","libraryName":"Nama dari pustaka Anda","libraryDesc":"Deskripsi pustaka Anda untuk membantu orang mengerti penggunaannya","githubHandle":"Akun GitHub (opsional), jadi Anda dapat mengubah pustaka ketika diserahkan untuk review","twitterHandle":"Nama pengguna Twitter (opsional), jadi kami tahu siapa dipuji ketika mempromosikannya melalui Twitter","website":"Hubungkan ke situs personal Anda atau lainnya (opsional)"},"errors":{"required":"Dibutuhkan","website":"Masukkan URL valid"},"noteDescription":"Kirimkan pustaka Anda untuk disertakan di repositori pustaka publikuntuk orang lain menggunakannya dalam gambar mereka.","noteGuidelines":"Pustaka butuh disetujui secara manual terlebih dahulu. Baca pedoman sebelum mengirim. Anda butuh akun GitHub untuk berkomunikasi dan membuat perubahan jika dibutuhkan, tetapi tidak wajib dibutukan.","noteLicense":"Dengan mengkirimkannya, Anda setuju pustaka akan diterbitkan dibawah Lisensi MIT, yang artinya siapa pun dapat menggunakannya tanpa batasan.","noteItems":"Setiap item pustaka harus memiliki nama, sehingga bisa disortir. Item pustaka di bawah ini akan dimasukan:","atleastOneLibItem":"Pilih setidaknya satu item pustaka untuk mulai","republishWarning":"Catatan: beberapa item yang dipilih telah ditandai sebagai sudah dipublikasikan/diserahkan. Anda hanya dapat menyerahkan kembali item-item ketika memperbarui pustaka atau pengumpulan."},"publishSuccessDialog":{"title":"Pustaka telah dikirm","content":"Terima kasih {{authorName}}. pustaka Anda telah diserahkan untuk ditinjau ulang. Anda dapat cek statusnyadi sini"},"confirmDialog":{"resetLibrary":"Reset pustaka","removeItemsFromLib":"Hapus item yang dipilih dari pustaka"},"imageExportDialog":{"header":"Ekspor gambar","label":{"withBackground":"Latar","onlySelected":"Hanya yang dipilih","darkMode":"Mode gelap","embedScene":"Sematkan pemandangan","scale":"Skala","padding":"Lapisan"},"tooltip":{"embedScene":"Data pemandangan akan disimpan dalam file PNG/SVG yang diekspor sehingga pemandangan itu dapat dipulihkan darinya.\\nAkan membesarkan ukuran file yang diekspor."},"title":{"exportToPng":"Ekspor ke PNG","exportToSvg":"Ekspor ke SVG","copyPngToClipboard":"Salin PNG ke papan klip"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Salin ke papan klip"}},"encrypted":{"tooltip":"Gambar anda terenkripsi end-to-end sehingga server Excalidraw tidak akan pernah dapat melihatnya.","link":"Pos blog tentang enkripsi ujung ke ujung di Excalidraw"},"stats":{"angle":"Sudut","element":"Elemen","elements":"Elemen","height":"Tinggi","scene":"Pemandangan","selected":"Terpilih","storage":"Penyimpanan","title":"Statistik untuk nerd","total":"Total","version":"Versi","versionCopy":"Klik untuk salin","versionNotAvailable":"Versi tidak tersedia","width":"Lebar"},"toast":{"addedToLibrary":"Tambahkan ke pustaka","copyStyles":"Gaya tersalin.","copyToClipboard":"Tersalin ke papan klip.","copyToClipboardAsPng":"Tersalin {{exportSelection}} ke clipboard sebagai PNG\\n({{exportColorScheme}})","fileSaved":"File tersimpan.","fileSavedToFilename":"Disimpan ke {filename}","canvas":"kanvas","selection":"pilihan","pasteAsSingleElement":"Gunakan {{shortcut}} untuk menempelkan sebagai satu elemen,\\natau tempelkan ke teks editor yang ada","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Transparan","black":"Hitam","white":"Putih","red":"Merah","pink":"Pink","grape":"Ungu","violet":"Violet","gray":"Abu-abu","blue":"Biru","cyan":"Cyan","teal":"Teal","green":"Hijau","yellow":"Kuning","orange":"Jingga","bronze":"Tembaga"},"welcomeScreen":{"app":{"center_heading":"Semua data Anda disimpan secara lokal di peramban Anda.","center_heading_plus":"Apa Anda ingin berpindah ke Excalidraw+?","menuHint":"Ekspor, preferensi, bahasa, ..."},"defaults":{"menuHint":"Ekspor, preferensi, dan selebihnya...","center_heading":"Diagram. Menjadi. Mudah.","toolbarHint":"Pilih alat & mulai menggambar!","helpHint":"Pintasan & bantuan"}},"colorPicker":{"mostUsedCustomColors":"Warna yang sering dipakai","colors":"Warna","shades":"Nuansa","hexCode":"Kode hexa","noShades":"Tidak ada nuansa untuk warna ini"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Ekspor sebagai gambar","button":"Ekspor sebagai gambar","description":"Ekspor data pemandangan sebagai gambar yang dapat anda impor nanti."},"saveToDisk":{"title":"Simpan ke disk","button":"Simpan ke disk","description":"Ekspor data pemandangan ke file yang dapat Anda dapat impor nanti."},"excalidrawPlus":{"title":"Excalidraw+","button":"Ekspor ke Excalidraw+","description":"Simpan pemandangan ke ruang kerja Excalidraw+ Anda."}},"modal":{"loadFromFile":{"title":"Muat dari file","button":"Muat dari file","description":"Memuat dari file yang akan menggantikan konten Anda sekarang. Anda dapat mencadangkan gambar anda dulu menggunakan opsi-opsi ini."},"shareableLink":{"title":"Muat dari link","button":"Ganti konten saya","description":"Memuat dari file yang akan menggantikan konten Anda sekarang. Anda dapat mencadangkan gambar anda dulu menggunakan opsi-opsi ini."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/it-IT-json-6ecc9aec005faab90f41.js b/public/excalidraw/excalidraw-assets-dev/locales/it-IT-json-6ecc9aec005faab90f41.js
new file mode 100644
index 0000000..3cc98d7
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/it-IT-json-6ecc9aec005faab90f41.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/it-IT-json"],{
+
+/***/ "../../locales/it-IT.json":
+/*!********************************!*\
+ !*** ../../locales/it-IT.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Incolla","pasteAsPlaintext":"Incolla come testo normale","pasteCharts":"Incolla grafici","selectAll":"Seleziona tutto","multiSelect":"Aggiungi elemento alla selezione","moveCanvas":"Sposta tela","cut":"Taglia","copy":"Copia","copyAsPng":"Copia negli appunti come PNG","copyAsSvg":"Copia negli appunti come SVG","copyText":"Copia negli appunti come testo","bringForward":"Porta avanti","sendToBack":"Manda in fondo","bringToFront":"Porta in cima","sendBackward":"Manda dietro","delete":"Elimina","copyStyles":"Copia stili","pasteStyles":"Incolla stili","stroke":"Tratto","background":"Sfondo","fill":"Riempimento","strokeWidth":"Spessore del tratto","strokeStyle":"Stile del tratto","strokeStyle_solid":"Pieno","strokeStyle_dashed":"Tratteggiato","strokeStyle_dotted":"Punteggiato","sloppiness":"Imprecisione","opacity":"Opacità","textAlign":"Allineamento del testo","edges":"Bordi","sharp":"Acuto","round":"Rotondo","arrowheads":"Punta della freccia","arrowhead_none":"Nessuno","arrowhead_arrow":"Freccia","arrowhead_bar":"Barra","arrowhead_dot":"Punto","arrowhead_triangle":"Triangolo","fontSize":"Dimensione carattere","fontFamily":"Carattere","addWatermark":"Aggiungi \\"Creato con Excalidraw\\"","handDrawn":"A mano libera","normal":"Normale","code":"Codice","small":"Piccolo","medium":"Medio","large":"Grande","veryLarge":"Molto grande","solid":"Pieno","hachure":"Tratteggio obliquo","zigzag":"Zig zag","crossHatch":"Tratteggio incrociato","thin":"Sottile","bold":"Grassetto","left":"Sinistra","center":"Centro","right":"Destra","extraBold":"Extra Grassetto","architect":"Architetto","artist":"Artista","cartoonist":"Fumettista","fileTitle":"Nome del file","colorPicker":"Selettore colore","canvasColors":"Usato su tela","canvasBackground":"Sfondo tela","drawingCanvas":"Area di disegno","layers":"Livelli","actions":"Azioni","language":"Lingua","liveCollaboration":"Collaborazione dal vivo...","duplicateSelection":"Duplica","untitled":"Senza titolo","name":"Nome","yourName":"Il vostro nome","madeWithExcalidraw":"Creato con Excalidraw","group":"Crea gruppo da selezione","ungroup":"Dividi gruppo da selezione","collaborators":"Collaboratori","showGrid":"Visualizza griglia","addToLibrary":"Aggiungi alla libreria","removeFromLibrary":"Rimuovi dalla libreria","libraryLoadingMessage":"Caricamento libreria…","libraries":"Sfoglia librerie","loadingScene":"Caricamento della scena…","align":"Allinea","alignTop":"Allinea in alto","alignBottom":"Allinea in basso","alignLeft":"Allinea a sinistra","alignRight":"Allinea a destra","centerVertically":"Centra Verticalmente","centerHorizontally":"Centra orizzontalmente","distributeHorizontally":"Distribuisci orizzontalmente","distributeVertically":"Distribuisci verticalmente","flipHorizontal":"Capovolgi orizzontalmente","flipVertical":"Capovolgi verticalmente","viewMode":"Modalità visualizzazione","share":"Condividi","showStroke":"Mostra selettore colore del tratto","showBackground":"Mostra selettore colore di sfondo","toggleTheme":"Cambia tema","personalLib":"Libreria Personale","excalidrawLib":"Libreria di Excalidraw","decreaseFontSize":"Riduci dimensione dei caratteri","increaseFontSize":"Aumenta la dimensione dei caratteri","unbindText":"Scollega testo","bindText":"Associa il testo al container","createContainerFromText":"Avvolgi il testo in un container","link":{"edit":"Modifica link","editEmbed":"Modifica collegamento e incorpora","create":"Crea link","createEmbed":"Crea collegamento e incorpora","label":"Link","labelEmbed":"Collega & incorpora","empty":"Nessun collegamento impostato"},"lineEditor":{"edit":"Modifica linea","exit":"Esci dall\'editor di linea"},"elementLock":{"lock":"Blocca","unlock":"Sblocca","lockAll":"Blocca tutto","unlockAll":"Sblocca tutto"},"statusPublished":"Pubblicato","sidebarLock":"Mantieni aperta la barra laterale","selectAllElementsInFrame":"Seleziona tutti gli elementi nel riquadro","removeAllElementsFromFrame":"Rimuovi tutti gli elementi dal riquadro","eyeDropper":"Scegli il colore della tela"},"library":{"noItems":"Nessun elemento ancora aggiunto...","hint_emptyLibrary":"Seleziona un elemento sulla tela per aggiungerlo qui, o installa una libreria dal repository pubblico qui sotto.","hint_emptyPrivateLibrary":"Seleziona un elemento sulla tela per aggiungerlo qui."},"buttons":{"clearReset":"Svuota la tela","exportJSON":"Esporta su file","exportImage":"Esporta immagine...","export":"Salva in...","copyToClipboard":"Copia negli appunti","save":"Salva sul file corrente","saveAs":"Salva con nome","load":"Apri","getShareableLink":"Ottieni link condivisibile","close":"Chiudi","selectLanguage":"Seleziona lingua","scrollBackToContent":"Scorri indietro fino al contenuto","zoomIn":"Aumenta ingrandimento","zoomOut":"Riduci ingrandimento","resetZoom":"Ripristina ingrandimento","menu":"Menù","done":"Fatto","edit":"Modifica","undo":"Annulla","redo":"Ripeti","resetLibrary":"Ripristina libreria","createNewRoom":"Crea nuova stanza","fullScreen":"Schermo intero","darkMode":"Tema scuro","lightMode":"Tema chiaro","zenMode":"Modalità Zen","objectsSnapMode":"Aggancia agli oggetti","exitZenMode":"Uscire dalla modalità zen","cancel":"Annulla","clear":"Cancella","remove":"Rimuovi","embed":"Attiva/disattiva incorporamento","publishLibrary":"Pubblica","submit":"Invia","confirm":"Conferma","embeddableInteractionButton":"Clicca per interagire"},"alerts":{"clearReset":"Questa azione cancellerà l\'intera tela. Sei sicuro?","couldNotCreateShareableLink":"Non riesco a creare un link condivisibile.","couldNotCreateShareableLinkTooBig":"Impossibile creare il link condivisibile: la scena è troppo grande","couldNotLoadInvalidFile":"Impossibile caricare un file no valido","importBackendFailed":"Importazione dal server fallita.","cannotExportEmptyCanvas":"Non è possibile esportare una tela vuota.","couldNotCopyToClipboard":"Impossibile copiare negli appunti.","decryptFailed":"Impossibile decriptare i dati.","uploadedSecurly":"L\'upload è stato protetto con la crittografia end-to-end, il che significa che il server Excalidraw e terze parti non possono leggere il contenuto.","loadSceneOverridePrompt":"Se carichi questo disegno esterno, sostituirà quello che hai. Vuoi continuare?","collabStopOverridePrompt":"Interrompere la sessione sovrascriverà il precedente disegno memorizzato localmente. Sei sicuro?\\n\\n(Se vuoi mantenere il tuo disegno locale, chiudi semplicemente la scheda del browser.)","errorAddingToLibrary":"Impossibile aggiungere l\'elemento alla libreria","errorRemovingFromLibrary":"Impossibile rimuovere l\'elemento dalla libreria","confirmAddLibrary":"Questo aggiungerà {{numShapes}} forma(e) alla tua libreria. Sei sicuro?","imageDoesNotContainScene":"Questa immagine pare non contenere alcuna scena. Avevi incluso la scena durante l\'esportazione?","cannotRestoreFromImage":"Impossibile ripristinare la scena da questo file immagine","invalidSceneUrl":"Impossibile importare la scena dall\'URL fornito. Potrebbe essere malformato o non contenere dati JSON Excalidraw validi.","resetLibrary":"Questa azione cancellerà l\'intera libreria. Sei sicuro?","removeItemsFromsLibrary":"Eliminare {{count}} elementi dalla libreria?","invalidEncryptionKey":"La chiave di cifratura deve essere composta da 22 caratteri. La collaborazione live è disabilitata.","collabOfflineWarning":"Nessuna connessione internet disponibile.\\nLe tue modifiche non verranno salvate!"},"errors":{"unsupportedFileType":"Tipo di file non supportato.","imageInsertError":"Non è stato possibile inserire l\'immagine. Riprova più tardi...","fileTooBig":"Il file è troppo grande. La dimensione massima consentita è {{maxSize}}.","svgImageInsertError":"Impossibile inserire l\'immagine SVG. Il markup SVG non sembra corretto.","failedToFetchImage":"","invalidSVGString":"SVG non valido.","cannotResolveCollabServer":"Impossibile connettersi al server di collab. Ricarica la pagina e riprova.","importLibraryError":"Impossibile caricare la libreria","collabSaveFailed":"Impossibile salvare nel database di backend. Se i problemi persistono, dovresti salvare il tuo file localmente per assicurarti di non perdere il tuo lavoro.","collabSaveFailed_sizeExceeded":"Impossibile salvare nel database di backend, la tela sembra essere troppo grande. Dovresti salvare il file localmente per assicurarti di non perdere il tuo lavoro.","brave_measure_text_error":{"line1":"Sembra che tu stia utilizzando il browser Brave con l\'impostazione Blocco aggressivo delle impronte digitali abilitata.","line2":"Ciò potrebbe causare la rottura degli Elementi di testo nei tuoi disegni.","line3":"Consigliamo vivamente di disabilitare questa impostazione. Puoi seguire questi passaggi su come farlo.","line4":"Se la disattivazione di questa impostazione non risolve la visualizzazione degli elementi di testo, apri un problema sul nostro GitHub o scrivici su Discord"},"libraryElementTypeError":{"embeddable":"Gli elementi incorporabili non possono essere aggiunti alla libreria.","image":"Il supporto per l\'aggiunta d\'immagini alla libreria verrà aggiunto a breve!"}},"toolBar":{"selection":"Selezione","image":"Inserisci immagine","rectangle":"Rettangolo","diamond":"Rombo","ellipse":"Ellisse","arrow":"Freccia","line":"Linea","freedraw":"Disegno","text":"Testo","library":"Libreria","lock":"Mantieni lo strumento selezionato attivo dopo aver disegnato","penMode":"Modalità penna - previene il tocco","link":"Aggiungi/ aggiorna il link per una forma selezionata","eraser":"Gomma","frame":"Strumento riquadro","embeddable":"Incorporamento Web","laser":"Puntatore laser","hand":"Mano (strumento di panoramica)","extraTools":"Altri strumenti"},"headings":{"canvasActions":"Azioni sulla Tela","selectedShapeActions":"Impostazioni della forma selezionata","shapes":"Forme"},"hints":{"canvasPanning":"Per spostare la tela, tieni premuta la rotellina del mouse o la barra spaziatrice mentre trascini oppure usa lo strumento mano","linearElement":"Clicca per iniziare una linea in più punti, trascina per singola linea","freeDraw":"Clicca e trascina, rilascia quando avrai finito","text":"Suggerimento: puoi anche aggiungere del testo facendo doppio clic ovunque con lo strumento di selezione","embeddable":"Fare click e trascina per creare un incorporamento web","text_selected":"Fai doppio click o premi INVIO per modificare il testo","text_editing":"Premi ESC o CtrlOCmd+INVIO per completare le modifiche","linearElementMulti":"Clicca sull\'ultimo punto o premi Esc o Invio per finire","lockAngle":"Puoi limitare l\'angolo tenendo premuto SHIFT","resize":"Per vincolare le proporzioni, tieni premuto MAIUSC durante il ridimensionamento;\\nper ridimensionare dal centro, tieni premuto ALT","resizeImage":"Puoi ridimensionare liberamente tenendo premuto SHIFT,\\ntieni premuto ALT per ridimensionare dal centro","rotate":"Puoi mantenere gli angoli tenendo premuto SHIFT durante la rotazione","lineEditor_info":"Tieni premuto Ctrl o Cmd e doppio clic oppure premi Ctrl o Cmd + Invio per modificare i punti","lineEditor_pointSelected":"Premi Elimina per rimuovere il punto(i),\\nCtrlOCmd+D per duplicare o trascinare per spostare","lineEditor_nothingSelected":"Seleziona un punto da modificare (tieni premuto MAIUSC per selezionare più punti),\\noppure tieni premuto Alt e fai clic per aggiungere nuovi punti","placeImage":"Fai click per posizionare l\'immagine, o click e trascina per impostarne la dimensione manualmente","publishLibrary":"Pubblica la tua libreria","bindTextToElement":"Premi invio per aggiungere il testo","deepBoxSelect":"Tieni premuto CtrlOCmd per selezionare in profondità e per impedire il trascinamento","eraserRevert":"Tieni premuto Alt per ripristinare gli elementi contrassegnati per l\'eliminazione","firefox_clipboard_write":"Questa funzione può essere abilitata impostando il flag \\"dom.events.asyncClipboard.clipboardItem\\" su \\"true\\". Per modificare i flag del browser in Firefox, visitare la pagina \\"about:config\\".","disableSnapping":"Tieni premuto Ctrl o Cmd per disabilitare lo snap"},"canvasError":{"cannotShowPreview":"Impossibile visualizzare l\'anteprima","canvasTooBig":"La tela potrebbe essere troppo grande.","canvasTooBigTip":"Suggerimento: prova a spostare gli elementi più lontani più vicini tra loro."},"errorSplash":{"headingMain":"Si è verificato un errore. Provare ","clearCanvasMessage":"Se ricaricare non funziona, prova ","clearCanvasCaveat":" Questo risulterà nella perdita del lavoro ","trackedToSentry":"L\'errore con identificativo {{eventId}} è stato tracciato nel nostro sistema.","openIssueMessage":"Siamo stati molto cauti nel non includere informazioni della scena nell\'errore. Se la tua scena non è privata, ti preghiamo di considerare la sua inclusione nel nostro Per favore includi le informazioni riportate qui sotto copiandole e incollandole nella issue di GitHub.","sceneContent":"Contenuto della scena:"},"roomDialog":{"desc_intro":"Puoi invitare persone nella tua scena attuale per collaborare con te.","desc_privacy":"Non preoccuparti, la sessione utilizza la crittografia end-to-end, quindi qualsiasi cosa disegni rimarrà privata. Nemmeno il nostro server sarà in grado di vedere cosa hai creato.","button_startSession":"Avvia sessione","button_stopSession":"Termina sessione","desc_inProgressIntro":"La sessione di collaborazione è attualmente in corso.","desc_shareLink":"Condividi questo link con chiunque desideri collaborare:","desc_exitSession":"Interrompere la sessione scollegherà la tua stanza ma potrai continuare a lavorare con la scena, localmente. Tieni presente che questo non influirà sulle altre persone, e che saranno ancora in grado di collaborare alla loro versione.","shareTitle":"Partecipa a una sessione di collaborazione live su Excalidraw"},"errorDialog":{"title":"Errore"},"exportDialog":{"disk_title":"Salva su disco","disk_details":"Esporta i dati della scena su file, dal quale potrai importare in seguito.","disk_button":"Salva su file","link_title":"Link condivisibile","link_details":"Esporta come link di sola lettura.","link_button":"Esporta come Link","excalidrawplus_description":"Salva la scena nel tuo spazio di lavoro Excalidraw+.","excalidrawplus_button":"Esporta","excalidrawplus_exportError":"Non è stato possibile esportare su Excalidraw+ al questo momento..."},"helpDialog":{"blog":"Leggi il nostro blog","click":"click","deepSelect":"Selezione profonda","deepBoxSelect":"Seleziona in profondità all\'interno della casella e previene il trascinamento","curvedArrow":"Freccia curva","curvedLine":"Linea curva","documentation":"Documentazione","doubleClick":"doppio-click","drag":"trascina","editor":"Editor","editLineArrowPoints":"Modifica punti linea/freccia","editText":"Modifica testo / aggiungi etichetta","github":"Trovato un problema? Segnalalo","howto":"Segui le nostre guide","or":"oppure","preventBinding":"Impedisci legame della freccia","tools":"Stumenti","shortcuts":"Scorciatoie da tastiera","textFinish":"Completa la modifica (editor di testo)","textNewLine":"Aggiungi nuova riga (editor di testo)","title":"Guida","view":"Vista","zoomToFit":"Adatta zoom per mostrare tutti gli elementi","zoomToSelection":"Zoom alla selezione","toggleElementLock":"Blocca/sblocca selezione","movePageUpDown":"Sposta la pagina su/giù","movePageLeftRight":"Sposta la pagina a sinistra/destra"},"clearCanvasDialog":{"title":"Svuota la tela"},"publishDialog":{"title":"Pubblica la libreria","itemName":"Nome dell\'elemento","authorName":"Nome dell\'autore","githubUsername":"Nome utente di GitHub","twitterUsername":"Nome utente di Twitter","libraryName":"Nome della libreria","libraryDesc":"Descrizione della libreria","website":"Sito Web","placeholder":{"authorName":"Il tuo nome o nome utente","libraryName":"Nome della tua libreria","libraryDesc":"Descrizione della tua libreria per aiutare le persone a comprenderne lo scopo","githubHandle":"Handle di GitHub (opzionale), così che tu possa modificare la libreria una volta inviata per la revisione","twitterHandle":"Nome utente di Twitter (opzionale), così che sappiamo chi accreditare promuovendo su Twitter","website":"Link al tuo sito web personale o altro (opzionale)"},"errors":{"required":"Obbligatorio","website":"Inserisci un URL valido"},"noteDescription":"Invia la tua libreria da includere nella repository della libreria pubblicaperché sia usata da altri nei loro disegni.","noteGuidelines":"La libreria dev\'esser prima approvata manualmente. Sei pregato di leggere le linee guida prima di inviarla. Necessiterai di un profilo di GitHub per comunicare ed effettuare modifiche se richiesto, ma non è strettamente necessario.","noteLicense":"Inviando, acconsenti che la libreria sarà pubblicata sotto la Licenza MIT, che in breve significa che chiunque possa usarla senza restrizioni.","noteItems":"Ogni elemento della libreria deve avere il proprio nome, così che sia filtrabile. Gli elementi della seguente libreria saranno inclusi:","atleastOneLibItem":"Sei pregato di selezionare almeno un elemento della libreria per iniziare","republishWarning":"Nota: alcuni degli elementi selezionati sono contrassegnati come già pubblicati/presentati. È necessario reinviare gli elementi solo quando si aggiorna una libreria o una presentazione esistente."},"publishSuccessDialog":{"title":"Libreria inviata","content":"Grazie {{authorName}}. La tua libreria è stata inviata per la revisione. Puoi monitorarne lo statoqui"},"confirmDialog":{"resetLibrary":"Ripristina la libreria","removeItemsFromLib":"Rimuovi gli elementi selezionati dalla libreria"},"imageExportDialog":{"header":"Esporta immagine","label":{"withBackground":"Sfondo","onlySelected":"Solo selezionato","darkMode":"Tema scuro","embedScene":"Includi scena","scale":"Scala","padding":"Rientro"},"tooltip":{"embedScene":"I dati della scena saranno salvati nel file PNG/SVG esportato in modo che la scena possa essere ripristinata da esso.\\nQuesto aumenterà la dimensione del file esportato."},"title":{"exportToPng":"Esporta come PNG","exportToSvg":"Esporta come SVG","copyPngToClipboard":"Copia PNG negli appunti"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Copia negli appunti"}},"encrypted":{"tooltip":"I tuoi disegni sono crittografati end-to-end in modo che i server di Excalidraw non li possano mai vedere.","link":"Articolo del blog sulla crittografia end-to-end di Excalidraw"},"stats":{"angle":"Angolo","element":"Elemento","elements":"Elementi","height":"Altezza","scene":"Scena","selected":"Selezionato","storage":"Memoria","title":"Statistiche per nerd","total":"Totale","version":"Versione","versionCopy":"Clicca per copiare","versionNotAvailable":"Versione non disponibile","width":"Larghezza"},"toast":{"addedToLibrary":"Aggiunto alla libreria","copyStyles":"Stili copiati.","copyToClipboard":"Copiato negli appunti.","copyToClipboardAsPng":"{{exportSelection}} copiato negli appunti come PNG\\n({{exportColorScheme}})","fileSaved":"File salvato.","fileSavedToFilename":"Salvato in {filename}","canvas":"tela","selection":"selezione","pasteAsSingleElement":"Usa {{shortcut}} per incollare come un singolo elemento,\\no incollare in un editor di testo esistente","unableToEmbed":"Incorporare questo url non è permesso. Crea una issue su GitHub per richiedere che l\'url sia autorizzato","unrecognizedLinkFormat":"Il link che hai incorporato non corrisponde al formato previsto. Prova a incollare la stringa \'embed\' fornita dal sito di origine"},"colors":{"transparent":"Trasparente","black":"Nero","white":"Bianco","red":"Rosso","pink":"Rosa","grape":"Uva","violet":"Viola","gray":"Grigio","blue":"Blu","cyan":"Ciano","teal":"Verde acqua","green":"Verde","yellow":"Giallo","orange":"Arancio","bronze":"Bronzo"},"welcomeScreen":{"app":{"center_heading":"Tutti i tuoi dati sono salvati localmente nel browser.","center_heading_plus":"Volevi invece andare su Excalidraw+?","menuHint":"Esporta, preferenze, lingue, ..."},"defaults":{"menuHint":"Esporta, preferenze, e altro...","center_heading":"Diagrammi. Fatto. Semplice.","toolbarHint":"Scegli uno strumento & Inizia a disegnare!","helpHint":"Scorciatoie & aiuto"}},"colorPicker":{"mostUsedCustomColors":"Colori personalizzati più utilizzati","colors":"Colori","shades":"Sfumature","hexCode":"Codice esadecimale","noShades":"Nessuna sfumatura disponibile per questo colore"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Esporta come immagine","button":"Esporta come immagine","description":"Esporta i dati della scena come immagine, che potrai importare in seguito."},"saveToDisk":{"title":"Salva su disco","button":"Salva su disco","description":"Esporta i dati della scena su file, che potrai importare in seguito."},"excalidrawPlus":{"title":"Excalidraw+","button":"Esporta su Excalidraw+","description":"Salva la scena sul tuo spazio di lavoro Excalidraw+."}},"modal":{"loadFromFile":{"title":"Carica da file","button":"Carica da file","description":"Il caricamento da file sostituirà il contenuto esistente. Puoi salvare il tuo disegno prima usando una delle opzioni qui sotto."},"shareableLink":{"title":"Carica da link","button":"Sostituisci il mio contenuto","description":"Il caricamento da file sostituirà il contenuto esistente. Puoi salvare il tuo disegno prima usando una delle opzioni qui sotto."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/ja-JP-json-3c6a065f0f1303b297fa.js b/public/excalidraw/excalidraw-assets-dev/locales/ja-JP-json-3c6a065f0f1303b297fa.js
new file mode 100644
index 0000000..4f90e71
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/ja-JP-json-3c6a065f0f1303b297fa.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/ja-JP-json"],{
+
+/***/ "../../locales/ja-JP.json":
+/*!********************************!*\
+ !*** ../../locales/ja-JP.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"貼り付け","pasteAsPlaintext":"書式なしテキストとして貼り付け","pasteCharts":"チャートの貼り付け","selectAll":"すべて選択","multiSelect":"複数選択","moveCanvas":"キャンバスを移動","cut":"切り取り","copy":"コピー","copyAsPng":"PNGとしてクリップボードへコピー","copyAsSvg":"SVGとしてクリップボードへコピー","copyText":"テキストとしてクリップボードにコピー","bringForward":"前面に移動","sendToBack":"最背面に移動","bringToFront":"最前面に移動","sendBackward":"背面に移動","delete":"削除","copyStyles":"スタイルのコピー","pasteStyles":"スタイルの貼り付け","stroke":"線","background":"背景","fill":"塗りつぶし","strokeWidth":"線の太さ","strokeStyle":"線の種類","strokeStyle_solid":"実線","strokeStyle_dashed":"破線","strokeStyle_dotted":"点線","sloppiness":"ばらつき加減","opacity":"透明度","textAlign":"文字の配置","edges":"角","sharp":"四角","round":"丸","arrowheads":"線の終点","arrowhead_none":"なし","arrowhead_arrow":"矢印","arrowhead_bar":"バー","arrowhead_dot":"ドット","arrowhead_triangle":"三角","fontSize":"フォントの大きさ","fontFamily":"フォントの種類","addWatermark":"\\"Made with Excalidraw\\"と表示","handDrawn":"手描き風","normal":"普通","code":"コード","small":"小","medium":"中","large":"大","veryLarge":"特大","solid":"ベタ塗り","hachure":"斜線","zigzag":"ジグザグ","crossHatch":"網掛け","thin":"細","bold":"太字","left":"左寄せ","center":"中央寄せ","right":"右寄せ","extraBold":"極太","architect":"正確","artist":"アート","cartoonist":"漫画風","fileTitle":"ファイル名","colorPicker":"色選択","canvasColors":"キャンバス上で使用","canvasBackground":"キャンバスの背景","drawingCanvas":"キャンバスの描画","layers":"レイヤー","actions":"操作","language":"言語","liveCollaboration":"共同編集...","duplicateSelection":"複製","untitled":"無題","name":"名前","yourName":"あなたの名前","madeWithExcalidraw":"Excalidrawで作成","group":"グループ化","ungroup":"グループ化を解除","collaborators":"共同編集者","showGrid":"グリッドを表示","addToLibrary":"ライブラリに追加","removeFromLibrary":"ライブラリから削除","libraryLoadingMessage":"ライブラリを読み込み中…","libraries":"ライブラリを参照する","loadingScene":"シーンを読み込み中…","align":"配置","alignTop":"上揃え","alignBottom":"下揃え","alignLeft":"左揃え","alignRight":"右揃え","centerVertically":"縦方向に中央揃え","centerHorizontally":"横方向に中央揃え","distributeHorizontally":"水平方向に分散配置","distributeVertically":"垂直方向に分散配置","flipHorizontal":"水平方向に反転","flipVertical":"垂直方向に反転","viewMode":"閲覧モード","share":"共有","showStroke":"ストロークカラーピッカーを表示","showBackground":"背景色ピッカーを表示","toggleTheme":"テーマの切り替え","personalLib":"個人ライブラリ","excalidrawLib":"Excalidrawライブラリ","decreaseFontSize":"フォントサイズを縮小","increaseFontSize":"フォントサイズを拡大","unbindText":"テキストのバインド解除","bindText":"テキストをコンテナにバインド","createContainerFromText":"コンテナ内でテキストを折り返す","link":{"edit":"リンクを編集","editEmbed":"リンクの編集と埋め込み","create":"リンクを作成","createEmbed":"リンクの作成と埋め込み","label":"リンク","labelEmbed":"リンクと埋め込み","empty":"リンクが設定されていません"},"lineEditor":{"edit":"行を編集","exit":"行エディタを終了"},"elementLock":{"lock":"ロック","unlock":"ロック解除","lockAll":"すべてロック","unlockAll":"すべてのロックを解除"},"statusPublished":"公開済み","sidebarLock":"サイドバーを開いたままにする","selectAllElementsInFrame":"フレーム内のすべての要素を選択","removeAllElementsFromFrame":"フレーム内のすべての要素を削除","eyeDropper":"キャンバスから色を選択"},"library":{"noItems":"まだアイテムが追加されていません…","hint_emptyLibrary":"キャンバス上のアイテムを選択してここに追加するか、以下の公開リポジトリからライブラリをインストールしてください。","hint_emptyPrivateLibrary":"キャンバス上のアイテムを選択すると、ここに追加されます。"},"buttons":{"clearReset":"キャンバスのリセット","exportJSON":"ファイルへエクスポート","exportImage":"画像のエクスポート...","export":"名前を付けて保存...","copyToClipboard":"クリップボードにコピー","save":"現在のファイルに保存","saveAs":"名前を付けて保存","load":"開く","getShareableLink":"共有URLの取得","close":"閉じる","selectLanguage":"言語の選択","scrollBackToContent":"コンテンツまでスクロールで戻る","zoomIn":"拡大","zoomOut":"縮小","resetZoom":"拡大/縮小をリセット","menu":"メニュー","done":"完了","edit":"編集","undo":"元に戻す","redo":"やり直し","resetLibrary":"ライブラリをリセット","createNewRoom":"新しい部屋を作成する","fullScreen":"フルスクリーン","darkMode":"ダークモード","lightMode":"ライトモード","zenMode":"Zenモード","objectsSnapMode":"","exitZenMode":"集中モードをやめる","cancel":"キャンセル","clear":"消去","remove":"削除","embed":"埋め込みの切り替え","publishLibrary":"公開","submit":"送信","confirm":"確認","embeddableInteractionButton":""},"alerts":{"clearReset":"この操作によってキャンバス全体が消えます。よろしいですか?","couldNotCreateShareableLink":"共有URLを作成できませんでした。","couldNotCreateShareableLinkTooBig":"共有可能なリンクを作成できませんでした: シーンが大きすぎます","couldNotLoadInvalidFile":"無効なファイルを読み込めませんでした。","importBackendFailed":"サーバーからの読み込みに失敗しました。","cannotExportEmptyCanvas":"空のキャンバスはエクスポートできません。","couldNotCopyToClipboard":"クリップボードにコピーできませんでした。","decryptFailed":"データを復号できませんでした。","uploadedSecurly":"データのアップロードはエンドツーエンド暗号化によって保護されています。Excalidrawサーバーと第三者はデータの内容を見ることができません。","loadSceneOverridePrompt":"外部図面を読み込むと、既存のコンテンツが置き換わります。続行しますか?","collabStopOverridePrompt":"セッションを停止すると、ローカルに保存されている図が上書きされます。 本当によろしいですか?\\n\\n(ローカルの図を保持したい場合は、セッションを停止せずにブラウザタブを閉じてください。)","errorAddingToLibrary":"アイテムをライブラリに追加できませんでした","errorRemovingFromLibrary":"ライブラリからアイテムを削除できませんでした","confirmAddLibrary":"{{numShapes}} 個の図形をライブラリに追加します。よろしいですか?","imageDoesNotContainScene":"この画像にはシーンデータが含まれていないようです。エクスポート時にシーンの埋め込みを有効にしましたか?","cannotRestoreFromImage":"このイメージファイルからシーンを復元できませんでした","invalidSceneUrl":"指定された URL からシーンをインポートできませんでした。不正な形式であるか、有効な Excalidraw JSON データが含まれていません。","resetLibrary":"ライブラリを消去します。本当によろしいですか?","removeItemsFromsLibrary":"{{count}} 個のアイテムをライブラリから削除しますか?","invalidEncryptionKey":"暗号化キーは22文字でなければなりません。ライブコラボレーションは無効化されています。","collabOfflineWarning":"インターネットに接続されていません。\\n変更は保存されません!"},"errors":{"unsupportedFileType":"サポートされていないファイル形式です。","imageInsertError":"画像を挿入できませんでした。後でもう一度お試しください...","fileTooBig":"ファイルが大きすぎます。許可される最大サイズは {{maxSize}} です。","svgImageInsertError":"SVGイメージを挿入できませんでした。SVGマークアップは無効に見えます。","failedToFetchImage":"","invalidSVGString":"無効なSVGです。","cannotResolveCollabServer":"コラボレーションサーバに接続できませんでした。ページを再読み込みして、もう一度お試しください。","importLibraryError":"ライブラリを読み込めませんでした。","collabSaveFailed":"バックエンドデータベースに保存できませんでした。問題が解決しない場合は、作業を失わないようにローカルにファイルを保存してください。","collabSaveFailed_sizeExceeded":"キャンバスが大きすぎるため、バックエンドデータベースに保存できませんでした。問題が解決しない場合は、作業を失わないようにローカルにファイルを保存してください。","brave_measure_text_error":{"line1":"Aggressly Block Fingerprinting の設定が有効なBraveブラウザを使用しているようです。","line2":"これにより、図面の テキスト要素 が壊れる可能性があります。","line3":"この設定を無効にすることを強く推奨します。 設定手順 をこちらから確認できます。","line4":"この設定を無効にすると、テキスト要素の表示が修正されません。 GitHub で Issue を開くか、 Discord にご記入ください"},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"選択","image":"画像を挿入","rectangle":"矩形","diamond":"ひし形","ellipse":"楕円","arrow":"矢印","line":"直線","freedraw":"描画","text":"テキスト","library":"ライブラリ","lock":"描画後も使用中のツールを選択したままにする","penMode":"ペンモード - タッチ防止","link":"選択した図形のリンクを追加/更新","eraser":"消しゴム","frame":"フレームツール","embeddable":"Web埋め込み","laser":"","hand":"手 (パンニングツール)","extraTools":"その他のツール"},"headings":{"canvasActions":"キャンバス操作","selectedShapeActions":"選択された図形に対する操作","shapes":"図形"},"hints":{"canvasPanning":"キャンバスを移動するには、マウスホイールまたはスペースバーを押しながらドラッグするか、手ツールを使用します","linearElement":"クリックすると複数の頂点からなる曲線を開始、ドラッグすると直線","freeDraw":"クリックしてドラッグします。離すと終了します","text":"ヒント: 選択ツールを使用して任意の場所をダブルクリックしてテキストを追加することもできます","embeddable":"","text_selected":"テキストを編集するには、ダブルクリックまたはEnterキーを押します","text_editing":"Esc キーまたは CtrlOrCmd+ENTER キーを押して編集を終了します","linearElementMulti":"最後のポイントをクリックするか、エスケープまたはEnterを押して終了します","lockAngle":"SHIFTを押したままにすると、角度を制限することができます","resize":"サイズを変更中にSHIFTを押すと縦横比を固定できます。Altを押すと中央からサイズを変更できます","resizeImage":"SHIFTを長押しすると自由にサイズを変更できます。\\n中央からサイズを変更するにはALTを長押しします","rotate":"回転中にSHIFT キーを押すと角度を制限することができます","lineEditor_info":"CtrlOrCmd を押したままダブルクリックするか、CtrlOrCmd + Enter を押して点を編集します","lineEditor_pointSelected":"Deleteキーを押すと点を削除、CtrlOrCmd+Dで複製、マウスドラッグで移動","lineEditor_nothingSelected":"編集する点を選択(SHIFTを押したままで複数選択)、\\nAltキーを押しながらクリックすると新しい点を追加","placeImage":"クリックして画像を配置するか、クリックしてドラッグしてサイズを手動で設定します","publishLibrary":"自分のライブラリを公開","bindTextToElement":"Enterを押してテキストを追加","deepBoxSelect":"CtrlOrCmd を押し続けることでドラッグを抑止し、深い選択を行います","eraserRevert":"Alt を押し続けることで削除マークされた要素を元に戻す","firefox_clipboard_write":"この機能は、\\"dom.events.asyncClipboard.clipboardItem\\" フラグを \\"true\\" に設定することで有効になる可能性があります。Firefox でブラウザーの設定を変更するには、\\"about:config\\" ページを参照してください。","disableSnapping":""},"canvasError":{"cannotShowPreview":"プレビューを表示できません","canvasTooBig":"キャンバスが大きすぎます。","canvasTooBigTip":"ヒント: 最も遠い要素をもう少し近づけてみてください。"},"errorSplash":{"headingMain":"エラーが発生しました。もう一度やり直してください。 ","clearCanvasMessage":"再読み込みがうまくいかない場合は、 ","clearCanvasCaveat":" これにより作業が失われます ","trackedToSentry":"識別子のエラー {{eventId}} が我々のシステムで追跡されました。","openIssueMessage":"エラーに関するシーン情報を含めないように非常に慎重に設定しました。もしあなたのシーンがプライベートでない場合は、私たちのフォローアップを検討してください。 GitHub のIssueに以下の情報をコピーして貼り付けてください。","sceneContent":"シーンの内容:"},"roomDialog":{"desc_intro":"他の人を編集中のあなたの画面に招待して共同編集することができます。","desc_privacy":"このセッションはエンドツーエンド暗号化されており、描画内容は保護されています。運営サーバーからも内容は見えません。","button_startSession":"セッションを開始する","button_stopSession":"セッションを終了する","desc_inProgressIntro":"共同編集セッションが有効になっています。","desc_shareLink":"下記URLを共同編集したい人に共有してください:","desc_exitSession":"セッションを終了するとあなたはルームから切断されますが、ローカルで作業を続けることができます。セッションを終了しても他のメンバには影響はなく、引き続き共同作業を行うことができます。","shareTitle":"Excalidrawの共同編集セッションに参加する"},"errorDialog":{"title":"エラー"},"exportDialog":{"disk_title":"ディスクに保存","disk_details":"シーンデータを後からインポートできるファイルにエクスポートします。","disk_button":"ファイルへ保存","link_title":"共有可能なリンク","link_details":"読み取り専用リンクとしてエクスポート","link_button":"リンクとしてエクスポート","excalidrawplus_description":"Excalidraw+ ワークスペースにシーンを保存します。","excalidrawplus_button":"エクスポート","excalidrawplus_exportError":"Excalidraw+ にエクスポートできませんでした..."},"helpDialog":{"blog":"公式ブログを読む","click":"クリック","deepSelect":"深い選択","deepBoxSelect":"ボックス内の深い選択、およびドラッグの抑止","curvedArrow":"カーブした矢印","curvedLine":"曲線","documentation":"ドキュメント","doubleClick":"ダブルクリック","drag":"ドラッグ","editor":"エディタ","editLineArrowPoints":"","editText":"テキストの編集 / ラベルの追加","github":"不具合報告はこちら","howto":"ヘルプ・マニュアル","or":"または","preventBinding":"矢印を結合しない","tools":"ツール","shortcuts":"キーボードショートカット","textFinish":"編集を終了 (テキストエディタ)","textNewLine":"新しい行を追加 (テキスト)","title":"ヘルプ","view":"表示","zoomToFit":"すべての要素が収まるようにズーム","zoomToSelection":"選択要素にズーム","toggleElementLock":"選択したアイテムをロック/ロック解除","movePageUpDown":"ページを上下に移動","movePageLeftRight":"ページを左右に移動"},"clearCanvasDialog":{"title":"キャンバスを消去"},"publishDialog":{"title":"ライブラリを公開","itemName":"アイテム名","authorName":"作成者名","githubUsername":"GitHub ユーザ名","twitterUsername":"Twitter ユーザ名","libraryName":"ライブラリ名","libraryDesc":"ライブラリの説明","website":"Webサイト","placeholder":{"authorName":"お名前またはユーザー名","libraryName":"あなたのライブラリ名","libraryDesc":"ライブラリの使い方を理解するための説明","githubHandle":"GitHubハンドル(任意)。一度レビューのために送信されると、ライブラリを編集できます","twitterHandle":"Twitterのユーザー名 (任意)。Twitterでプロモーションする際にクレジットする人を知っておくためのものです","website":"個人のウェブサイトまたは他のサイトへのリンク (任意)"},"errors":{"required":"必須項目","website":"有効な URL を入力してください"},"noteDescription":"以下に含めるライブラリを提出してください 公開ライブラリのリポジトリ他の人が作図に使えるようにするためです","noteGuidelines":"最初にライブラリを手動で承認する必要があります。次をお読みください ガイドライン 送信する前に、GitHubアカウントが必要になりますが、必須ではありません。","noteLicense":"提出することにより、ライブラリが次の下で公開されることに同意します: MIT ライセンス つまり誰でも制限なく使えるということです","noteItems":"各ライブラリ項目は、フィルタリングのために独自の名前を持つ必要があります。以下のライブラリアイテムが含まれます:","atleastOneLibItem":"開始するには少なくとも1つのライブラリ項目を選択してください","republishWarning":"注意: 選択された項目の中には、すでに公開/投稿済みと表示されているものがあります。既存のライブラリや投稿を更新する場合のみ、アイテムを再投稿してください。"},"publishSuccessDialog":{"title":"ライブラリを送信しました","content":"{{authorName}} さん、ありがとうございます。あなたのライブラリはレビューのために提出されました。状況を追跡できます。こちら"},"confirmDialog":{"resetLibrary":"ライブラリをリセット","removeItemsFromLib":"選択したアイテムをライブラリから削除"},"imageExportDialog":{"header":"画像をエクスポート","label":{"withBackground":"背景","onlySelected":"","darkMode":"ダークモード","embedScene":"","scale":"スケール","padding":"余白"},"tooltip":{"embedScene":""},"title":{"exportToPng":"PNG にエクスポート","exportToSvg":"SVG にエクスポート","copyPngToClipboard":"クリップボードにPNGをコピー"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"クリップボードにコピー"}},"encrypted":{"tooltip":"描画内容はエンドツーエンド暗号化が施されており、Excalidrawサーバーが内容を見ることはできません。","link":"Excalidrawのエンドツーエンド暗号化に関するブログ記事"},"stats":{"angle":"角度","element":"要素","elements":"要素","height":"高さ","scene":"シーン","selected":"選択済み","storage":"ストレージ","title":"詳細統計情報","total":"合計","version":"バージョン","versionCopy":"クリックしてコピー","versionNotAvailable":"利用できないバージョン","width":"幅"},"toast":{"addedToLibrary":"ライブラリに追加しました","copyStyles":"スタイルをコピーしました。","copyToClipboard":"クリップボードにコピー","copyToClipboardAsPng":"{{exportSelection}} を PNG 形式でクリップボードにコピーしました\\n({{exportColorScheme}})","fileSaved":"ファイルを保存しました","fileSavedToFilename":"{filename} に保存しました","canvas":"キャンバス","selection":"選択","pasteAsSingleElement":"{{shortcut}} を使用して単一の要素として貼り付けるか、\\n既存のテキストエディタに貼り付け","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"透明","black":"黒","white":"白","red":"赤","pink":"ピンク","grape":"グレープ","violet":"バイオレット","gray":"灰色","blue":"青","cyan":"シアン","teal":"ティール","green":"緑","yellow":"黄","orange":"オレンジ","bronze":"ブロンズ"},"welcomeScreen":{"app":{"center_heading":"すべてのデータはブラウザにローカル保存されます。","center_heading_plus":"代わりにExcalidraw+を開きますか?","menuHint":"エクスポート、設定、言語..."},"defaults":{"menuHint":"エクスポート、設定、その他...","center_heading":"ダイアグラムを簡単に。","toolbarHint":"ツールを選んで描き始めよう!","helpHint":"ショートカットとヘルプ"}},"colorPicker":{"mostUsedCustomColors":"最も使用されているカスタム色","colors":"色","shades":"影","hexCode":"Hexコード","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"画像としてエクスポート","button":"画像としてエクスポート","description":""},"saveToDisk":{"title":"ディスクに保存","button":"ディスクに保存","description":""},"excalidrawPlus":{"title":"Excalidraw+","button":"Excalidraw+にエクスポート","description":"Excalidraw+ ワークスペースにシーンを保存します。"}},"modal":{"loadFromFile":{"title":"ファイルからロード","button":"ファイルからロード","description":""},"shareableLink":{"title":"リンクからロード","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/kaa-json-983a9ccc652aa01980f3.js b/public/excalidraw/excalidraw-assets-dev/locales/kaa-json-983a9ccc652aa01980f3.js
new file mode 100644
index 0000000..aa3adff
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/kaa-json-983a9ccc652aa01980f3.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/kaa-json"],{
+
+/***/ "../../locales/kaa.json":
+/*!******************************!*\
+ !*** ../../locales/kaa.json ***!
+ \******************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Qoyıw","pasteAsPlaintext":"Ápiwayı tekst retinde qoyıw","pasteCharts":"Diagrammalardı qoyıw","selectAll":"Barlıǵın tańlaw","multiSelect":"","moveCanvas":"","cut":"Qıyıw","copy":"Kóshirip alıw","copyAsPng":"Almasıw buferine PNG retinde kóshirip alıw","copyAsSvg":"","copyText":"","bringForward":"","sendToBack":"","bringToFront":"","sendBackward":"","delete":"Óshiriw","copyStyles":"","pasteStyles":"","stroke":"Jiyek","background":"Fon","fill":"","strokeWidth":"","strokeStyle":"","strokeStyle_solid":"","strokeStyle_dashed":"","strokeStyle_dotted":"","sloppiness":"","opacity":"","textAlign":"","edges":"Qırlar","sharp":"","round":"","arrowheads":"","arrowhead_none":"","arrowhead_arrow":"Jebe","arrowhead_bar":"","arrowhead_dot":"Noqat","arrowhead_triangle":"","fontSize":"Shrift ólshemi","fontFamily":"","addWatermark":"","handDrawn":"","normal":"","code":"Kod","small":"","medium":"","large":"Úlken","veryLarge":"Júdá úlken","solid":"","hachure":"","zigzag":"Zigzag","crossHatch":"","thin":"Jińishke","bold":"Qalıń","left":"","center":"","right":"","extraBold":"","architect":"","artist":"","cartoonist":"","fileTitle":"Fayl ataması","colorPicker":"","canvasColors":"","canvasBackground":"","drawingCanvas":"","layers":"","actions":"Háreketler","language":"Til","liveCollaboration":"","duplicateSelection":"Nusqa","untitled":"Atamasız","name":"Ataması","yourName":"Atıńız","madeWithExcalidraw":"Excalidraw járdeminde islengen","group":"","ungroup":"","collaborators":"Qatnasıwshılar","showGrid":"","addToLibrary":"Kitapxanaǵa qosıw","removeFromLibrary":"Kitapxanadan alıp taslaw","libraryLoadingMessage":"Kitapxana júklenbekte…","libraries":"Kitapxanalardı kóriw","loadingScene":"Saxna júklenbekte…","align":"","alignTop":"","alignBottom":"","alignLeft":"","alignRight":"","centerVertically":"","centerHorizontally":"","distributeHorizontally":"","distributeVertically":"","flipHorizontal":"","flipVertical":"","viewMode":"Kóriw rejimi","share":"Bólisiw","showStroke":"","showBackground":"","toggleTheme":"Temanı ózgertiw","personalLib":"Jeke kitapxana","excalidrawLib":"Excalidraw kitapxanası","decreaseFontSize":"Shrift ólshemin kishireytiw","increaseFontSize":"Shrift ólshemin úlkeytiw","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"Siltemeni ózgertiw","editEmbed":"","create":"Siltemeni jaratıw","createEmbed":"","label":"Silteme","labelEmbed":"","empty":""},"lineEditor":{"edit":"Qatardı ózgertiw","exit":"Qatardı ózgertiw redaktorınan shıǵıw"},"elementLock":{"lock":"Qulıplaw","unlock":"Qulıptan shıǵarıw","lockAll":"Barlıǵın qulıplaw","unlockAll":"Barlıǵın qulıptan shıǵarıw"},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"","exportJSON":"","exportImage":"Súwretti eksportlaw...","export":"Retinde saqlaw...","copyToClipboard":"Almasıw buferine kóshirip alındı","save":"Ámeldegi faylǵa saqlaw","saveAs":"Retinde saqlaw","load":"Ashıw","getShareableLink":"","close":"Jabıw","selectLanguage":"Tildi tańlaw","scrollBackToContent":"","zoomIn":"","zoomOut":"","resetZoom":"","menu":"Menyu","done":"Tayın","edit":"Ózgertiw","undo":"","redo":"","resetLibrary":"","createNewRoom":"","fullScreen":"Tolıq ekran","darkMode":"Qarańǵı tema","lightMode":"Jaqtı tema","zenMode":"","objectsSnapMode":"","exitZenMode":"","cancel":"Biykarlaw","clear":"Tazalaw","remove":"Óshiriw","embed":"","publishLibrary":"","submit":"Jiberiw","confirm":"Tastıyıqlaw","embeddableInteractionButton":""},"alerts":{"clearReset":"","couldNotCreateShareableLink":"","couldNotCreateShareableLinkTooBig":"","couldNotLoadInvalidFile":"","importBackendFailed":"","cannotExportEmptyCanvas":"","couldNotCopyToClipboard":"Almasıw buferine kóshirip alıw ámelge aspadı.","decryptFailed":"","uploadedSecurly":"","loadSceneOverridePrompt":"","collabStopOverridePrompt":"","errorAddingToLibrary":"","errorRemovingFromLibrary":"","confirmAddLibrary":"","imageDoesNotContainScene":"","cannotRestoreFromImage":"","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"","invalidEncryptionKey":"","collabOfflineWarning":""},"errors":{"unsupportedFileType":"","imageInsertError":"","fileTooBig":"","svgImageInsertError":"","failedToFetchImage":"","invalidSVGString":"Jaramsız SVG.","cannotResolveCollabServer":"","importLibraryError":"Kitapxananı júklew ámelge aspadı","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"","image":"Súwret qoyıw","rectangle":"Tórt múyeshlik","diamond":"","ellipse":"","arrow":"","line":"Sızıq","freedraw":"Sızıw","text":"Tekst","library":"Kitapxana","lock":"","penMode":"","link":"","eraser":"Óshirgish","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"","selectedShapeActions":"","shapes":"Figuralar"},"hints":{"canvasPanning":"","linearElement":"","freeDraw":"","text":"","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"","lockAngle":"","resize":"","resizeImage":"","rotate":"","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"Tekst qosıw ushın Enter túymesin basıń","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"","canvasTooBig":"","canvasTooBigTip":""},"errorSplash":{"headingMain":"","clearCanvasMessage":"","clearCanvasCaveat":"","trackedToSentry":"","openIssueMessage":"","sceneContent":""},"roomDialog":{"desc_intro":"","desc_privacy":"","button_startSession":"","button_stopSession":"","desc_inProgressIntro":"","desc_shareLink":"","desc_exitSession":"","shareTitle":""},"errorDialog":{"title":"Qátelik"},"exportDialog":{"disk_title":"Diskke saqlaw","disk_details":"","disk_button":"Faylǵa saqlaw","link_title":"","link_details":"","link_button":"Siltemege eksportlaw","excalidrawplus_description":"","excalidrawplus_button":"Eksportlaw","excalidrawplus_exportError":""},"helpDialog":{"blog":"Biziń blogtı oqıń","click":"basıw","deepSelect":"","deepBoxSelect":"","curvedArrow":"","curvedLine":"","documentation":"Hújjetshilik","doubleClick":"","drag":"","editor":"Redaktor","editLineArrowPoints":"","editText":"","github":"","howto":"","or":"yamasa","preventBinding":"","tools":"Ásbaplar","shortcuts":"","textFinish":"","textNewLine":"","title":"Járdem","view":"Kóriw","zoomToFit":"","zoomToSelection":"","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"Avtor atı","githubUsername":"GitHub paydalanıwshı atı","twitterUsername":"Twitter paydalanıwshı atı","libraryName":"Kitapxana ataması","libraryDesc":"","website":"Veb-sayt","placeholder":{"authorName":"Atıńız yamasa paydalanıwshı atı","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"Kitapxananı qayta ornatıw","removeItemsFromLib":""},"imageExportDialog":{"header":"Súwretti eksportlaw","label":{"withBackground":"Fon","onlySelected":"","darkMode":"Qarańǵı tema","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Almasıw buferine kóshirip alıw"}},"encrypted":{"tooltip":"","link":""},"stats":{"angle":"","element":"Element","elements":"Elementler","height":"","scene":"Saxna","selected":"Tańlandı","storage":"","title":"","total":"","version":"Versiya","versionCopy":"Kóshirip alıw ushın basıń","versionNotAvailable":"","width":""},"toast":{"addedToLibrary":"Kitapxanaǵa qosıldı","copyStyles":"","copyToClipboard":"Almasıw buferine kóshirip alındı.","copyToClipboardAsPng":"","fileSaved":"Fayl saqlandı.","fileSavedToFilename":"{filename} saqlandı","canvas":"","selection":"","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"Qara","white":"Aq","red":"Qızıl","pink":"Qızǵılt","grape":"","violet":"Qızǵılt kók","gray":"","blue":"Kók","cyan":"Kók aspan","teal":"Piruza","green":"Jasıl","yellow":"Sarı","orange":"Qızǵılt sarı","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":"Eksportlaw, sazlawlar, tiller, ..."},"defaults":{"menuHint":"Eksportlaw, sazlawlar hám basqa...","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"Reńler","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"Súwret retinde eksportlaw","button":"Súwret retinde eksportlaw","description":""},"saveToDisk":{"title":"Diskke saqlaw","button":"Diskke saqlaw","description":""},"excalidrawPlus":{"title":"Excalidraw+","button":"","description":""}},"modal":{"loadFromFile":{"title":"Fayldan júklew","button":"Fayldan júklew","description":""},"shareableLink":{"title":"Siltemeden júklew","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/kab-KAB-json-cac3cf66f1db5c1a6e19.js b/public/excalidraw/excalidraw-assets-dev/locales/kab-KAB-json-cac3cf66f1db5c1a6e19.js
new file mode 100644
index 0000000..27f6484
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/kab-KAB-json-cac3cf66f1db5c1a6e19.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/kab-KAB-json"],{
+
+/***/ "../../locales/kab-KAB.json":
+/*!**********************************!*\
+ !*** ../../locales/kab-KAB.json ***!
+ \**********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Senṭeḍ","pasteAsPlaintext":"","pasteCharts":"Senṭeḍ udlifen","selectAll":"Fren akk","multiSelect":"Rnu aferdis ɣer tefrayt","moveCanvas":"Smutti taɣzut n usuneɣ","cut":"Gzem","copy":"Nɣel","copyAsPng":"Nɣel ɣer tecfawit am PNG","copyAsSvg":"Nɣel ɣer tecfawit am SVG","copyText":"Nɣel ɣer tecfawit am uḍris","bringForward":"Awi ɣer sdat","sendToBack":"Awi s agilal","bringToFront":"Err ɣer deffir","sendBackward":"Awi ɣer deffir","delete":"Kkes","copyStyles":"Nɣel iɣunab","pasteStyles":"Senṭeḍ iɣunab","stroke":"Azizdew","background":"Agilal","fill":"Taččart","strokeWidth":"Tehri n yizirig","strokeStyle":"Aɣanib n tizirig","strokeStyle_solid":"Aččuran","strokeStyle_dashed":"S tjerriḍin","strokeStyle_dotted":"S tenqiḍin","sloppiness":"Astehzi","opacity":"Tiḍullest","textAlign":"Areyyec n uḍris","edges":"Leryuf","sharp":"Yemsed","round":"Imdewer","arrowheads":"Ixfawen n tenccabt","arrowhead_none":"Ulac","arrowhead_arrow":"Taneccabt","arrowhead_bar":"Afeggag","arrowhead_dot":"Tanqiḍt","arrowhead_triangle":"Akerdis","fontSize":"Tiddi n tsefsit","fontFamily":"Tawacult n tsefsiyin","addWatermark":"Seddu \\"Yettwaxdem s Excalidraw\\"","handDrawn":"Asuneɣ s ufus","normal":"Amagnu","code":"Tangalt","small":"Meẓẓi","medium":"Alemmas","large":"Ameqran","veryLarge":"Meqqer aṭas","solid":"Aččuran","hachure":"Azerreg","zigzag":"","crossHatch":"Azerreg anmidag","thin":"Arqaq","bold":"Azuran","left":"Azelmaḍ","center":"Talemmast","right":"Ayfus","extraBold":"Azuran aṭas","architect":"Amasdag","artist":"Anaẓur","cartoonist":"Amefɣul","fileTitle":"Isem n ufaylu","colorPicker":"Amafran n yini","canvasColors":"Yettwaseqdec di teɣzut n usuneɣ","canvasBackground":"Agilal n teɣzut n usuneɣ","drawingCanvas":"Taɣzut n usuneɣ","layers":"Tissiyin","actions":"Tigawin","language":"Tutlayt","liveCollaboration":"Amɛiwen s srid...","duplicateSelection":"Sisleg","untitled":"War azwel","name":"Isem","yourName":"Isem-ik (im)","madeWithExcalidraw":"Yettwaxdem s Excalidraw","group":"Segrew tafrayt","ungroup":"Kkess asegrew i tefrayt","collaborators":"Imɛiwnen","showGrid":"Beqqeḍ aferrug","addToLibrary":"Rnu ɣer temkarḍit","removeFromLibrary":"Kkes si temkarḍit","libraryLoadingMessage":"Asali n temkarḍit…","libraries":"Snirem timkarḍiyin","loadingScene":"Asali n usayes…","align":"Reyyec","alignTop":"Areyyec uksawen","alignBottom":"Areyyec ukessar","alignLeft":"Reyyec s azelmaḍ","alignRight":"Areyyec s ayfus","centerVertically":"Di tlemmast s ibeddi","centerHorizontally":"Di tlemmast s uglawi","distributeHorizontally":"Freq s uglawi","distributeVertically":"Freq s yibeddi","flipHorizontal":"Tuttya taglawant","flipVertical":"Tuttya tubdidt","viewMode":"Askar n tmuɣli","share":"Bḍu","showStroke":"Beqqeḍ amelqaḍ n yini n yizirig","showBackground":"Beqqeḍ amelqaḍ n yini n ugilal","toggleTheme":"Snifel asentel","personalLib":"Tamkarḍit tudmawant","excalidrawLib":"Tamkarḍit n Excalidraw","decreaseFontSize":"Senqes tiddi n tsefsit","increaseFontSize":"Sali tiddi n tsefsit","unbindText":"Serreḥ iweḍris","bindText":"Arez aḍris s anagbar","createContainerFromText":"","link":{"edit":"Ẓreg aseɣwen","editEmbed":"","create":"Snulfu-d aseɣwen","createEmbed":"","label":"Aseɣwen","labelEmbed":"","empty":""},"lineEditor":{"edit":"Ẓreg izirig","exit":"Ffeɣ seg umaẓrag n yizirig"},"elementLock":{"lock":"Sekkeṛ","unlock":"Serreḥ","lockAll":"Sekkeṛ akk","unlockAll":"Serreḥ akk"},"statusPublished":"Yeffeɣ-d","sidebarLock":"Eǧǧ afeggag n yidis yeldi","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Ulac iferdisen yettwarnan yakan...","hint_emptyLibrary":"Fren aferdis di teɣzut nusuneɣ akken at-ternuḍ dagi, neɣ sbedd tamkarḍit seg usarsay azayez, ukessar-agi.","hint_emptyPrivateLibrary":"Fren aferdis di teɣzut nusuneɣ akken at-ternuḍ dagi."},"buttons":{"clearReset":"Ales awennez n teɣzut n usuneɣ","exportJSON":"Sifeḍ afaylu","exportImage":"Sifeḍ tugna...","export":"Sekles di...","copyToClipboard":"Nɣel ɣer tecfawit","save":"Sekles deg ufaylu amiran","saveAs":"Sekles am","load":"Ldi","getShareableLink":"Awi-d aseɣwen n beṭṭu","close":"Mdel","selectLanguage":"Fren tutlayt","scrollBackToContent":"Uɣal s agbur","zoomIn":"Simɣur","zoomOut":"Simẓi","resetZoom":"Ales awennez n usemɣer","menu":"Umuɣ","done":"Ifukk","edit":"Ẓreg","undo":"Sefsex","redo":"Err-d","resetLibrary":"Ales awennez n temkarḍit","createNewRoom":"Snulfu-d taxxamt tamaynutt","fullScreen":"Agdil aččuran","darkMode":"Askar imsulles","lightMode":"Askar afaw","zenMode":"Askar Zen","objectsSnapMode":"","exitZenMode":"Ffeɣ seg uskar Zen","cancel":"Sefsex","clear":"Sfeḍ","remove":"Kkes","embed":"","publishLibrary":"Ẓreg","submit":"Azen","confirm":"Sentem","embeddableInteractionButton":""},"alerts":{"clearReset":"Ayagi ad isfeḍ akk taɣzut n usuneɣ. Tetḥeqqeḍ?","couldNotCreateShareableLink":"D awezɣi asnulfu n useɣwen n beṭṭu.","couldNotCreateShareableLinkTooBig":"D awezɣi asnulfu n useɣwen n beṭṭu. Asayes ɣezzif aṭas","couldNotLoadInvalidFile":"D awezɣi asali n ufaylu armeɣtu","importBackendFailed":"Takterḍ seg uɣawas n deffir ur teddi ara.","cannotExportEmptyCanvas":"D awezɣi asifeḍ n teɣzut n usuneɣ tilemt.","couldNotCopyToClipboard":"Ulamek anɣal ɣer tecfawit.","decryptFailed":"D awezɣi tukksa n uwgelhen i yisefka.","uploadedSecurly":"Asili yettwasɣelles s uwgelhen ixef s ixef, ayagi yebɣa ad d-yini belli aqeddac n Excalidraw akked medden ur zmiren ara ad ɣren agbur.","loadSceneOverridePrompt":"Asali n wunuɣ uffiɣ ad isemselsi agbur-inek (m) yellan. Tebɣiḍ ad tkemmeleḍ?","collabStopOverridePrompt":"Aḥbas n tɣimit ad yesefsex unuɣ-inek (m) yettwaḥerzen yakan s wudem adigan. Tetḥeqqeḍ?\\n(Ma tebɣiḍ ad teǧǧeḍ unuɣ-inek (m) adigan, mdel iccer n yiminig, deg umḍiq.)","errorAddingToLibrary":"Ulamek ara yettwarnu uferdis ɣer temkarḍit","errorRemovingFromLibrary":"Ulamek ara yettwakkes uferdis si temkarḍit","confirmAddLibrary":"Ayagi adirnu talɣa (win) {{numShapes}} ɣer temkarḍit-inek (m). Tetḥeqqeḍ?","imageDoesNotContainScene":"Tugna-agi tettban-d ur tesɛi ara isefka n usayes. Tesremdeḍ aseddu n usayes deg usifeḍ?","cannotRestoreFromImage":"Asayes ulamek ara d-yettwarr seg ufaylu-agi n tugna","invalidSceneUrl":"Ulamek taktert n usayes seg URL i d-ittunefken. Ahat mačči d tameɣtut neɣ ur tegbir ara isefka JSON n Excalidraw.","resetLibrary":"Ayagi ad isfeḍ tamkarḍit-inek•m. Tetḥeqqeḍ?","removeItemsFromsLibrary":"Ad tekkseḍ {{count}} n uferdis (en) si temkarḍit?","invalidEncryptionKey":"Tasarut n uwgelhen isefk ad tesɛu 22 n yiekkilen. Amɛiwen srid yensa.","collabOfflineWarning":"Ulac tuqqna n internet.\\nIbedilen-ik ur ttwaklasen ara!"},"errors":{"unsupportedFileType":"Anaw n ufaylu ur yettwasefrak ara.","imageInsertError":"D awezɣi tugra n tugna. Eɛreḍ tikkelt-nniḍen ardeqqal...","fileTooBig":"Afaylu meqqer aṭas. Tiddi tafellayt yurgen d {{maxSize}}.","svgImageInsertError":"D awezɣi tugra n tugna SVG. Acraḍ SVG yettban-d d armeɣtu.","failedToFetchImage":"","invalidSVGString":"SVG armeɣtu.","cannotResolveCollabServer":"Ulamek tuqqna s aqeddac n umyalel. Ma ulac uɣilif ales asali n usebter sakin eɛreḍ tikkelt-nniḍen.","importLibraryError":"Ur d-ssalay ara tamkarḍit","collabSaveFailed":"Ulamek asekles deg uzadur n yisefka deg ugilal. Ma ikemmel wugur, isefk ad teskelseḍ afaylu s wudem adigan akken ad tetḥeqqeḍ ur tesruḥuyeḍ ara amahil-inek•inem.","collabSaveFailed_sizeExceeded":"Ulamek asekles deg uzadur n yisefka deg ugilal, taɣzut n usuneɣ tettban-d temqer aṭas. Isefk ad teskelseḍ afaylu s wudem adigan akken ad tetḥeqqeḍ ur tesruḥuyeḍ ara amahil-inek•inem.","brave_measure_text_error":{"line1":"","line2":"Ayagi yezmer ad d-iglu s truẓi nIferdisen n uḍrisdeg wunuɣen-inek.","line3":"Ad k-nsemter ad tsexsiḍ aɣewwar-agi. Tzemreḍ ad tḍefreḍisurifen-agi ɣef wamek ara txedmeḍ.","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Tafrayt","image":"Ger tugna","rectangle":"Asrem","diamond":"Ameɣṛun","ellipse":"Taglayt","arrow":"Taneccabt","line":"Izirig","freedraw":"Suneɣ","text":"Aḍris","library":"Tamkarḍit","lock":"Eǧǧ afecku n tefrayt yermed mbaɛd asuneɣ","penMode":"Askar n yimru - gdel tanalit","link":"Rnu/leqqem aseɣwen i talɣa yettwafernen","eraser":"Sfeḍ","frame":"","embeddable":"","laser":"","hand":"Afus (afecku n usmutti n tmuɣli)","extraTools":""},"headings":{"canvasActions":"Tigawin n teɣzut n usuneɣ","selectedShapeActions":"Tigawin n talɣa yettwafernen","shapes":"Talɣiwin"},"hints":{"canvasPanning":"Akken ad tesmuttiḍ taɣzut n usuneɣ, ṭṭef ṛṛuda n umumed, neɣ seqdec afecku Afus","linearElement":"Ssit akken ad tebduḍ aṭas n tenqiḍin, zuɣer i yiwen n yizirig","freeDraw":"Ssit yerna zuɣer, serreḥ ticki tfukeḍ","text":"Tixidest: tzemreḍ daɣen ad ternuḍ aḍris s usiti snat n tikkal anida tebɣiḍ s ufecku n tefrayt","embeddable":"","text_selected":"Ssit snat n tikkal neɣ ssed taqeffalt Kcem akken ad tẓergeḍ aḍris","text_editing":"Ssit Escape neɣ CtrlOrCmd+ENTER akken ad tfakkeḍ asiẓreg","linearElementMulti":"Ssit ɣef tenqiḍt taneggarut neɣ ssed taqeffalt Escape neɣ taqeffalt Kcem akken ad tfakkeḍ","lockAngle":"Tzemreḍ ad tḥettmeḍ tiɣmert s tuṭṭfa n tqeffalt SHIFT","resize":"Tzemreḍ ad tḥettemeḍ assaɣ s tuṭṭfa n tqeffalt SHIFT mi ara tettbeddileḍ tiddi,\\nma teṭṭfeḍ ALT abeddel n tiddi ad yili si tlemmast","resizeImage":"Tzemreḍ ad talseḍ tiddi s tilelli s tuṭṭfa n SHIFT,\\nṭṭef ALT akken ad talseḍ tiddi si tlemmast","rotate":"Tzemreḍ ad tḥettemeḍ tiɣemmar s tuṭṭfa n SHIFT di tuzzya","lineEditor_info":"Ssed ɣef CtrlOrCmd yerna ssit snat n tikkal neɣ ssed ɣef CtrlOrCmd + Kcem akken ad tẓergeḍ tineqqiḍin","lineEditor_pointSelected":"Ssed taqeffalt kkes akken ad tekkseḍ tanqiḍ (tinqiḍin),\\nCtrlOrCmd+D akken ad tsiselgeḍ, neɣ zuɣer akken ad tesmuttiḍ","lineEditor_nothingSelected":"Fren tanqiḍt akken ad tẓergeḍ (ṭṭef SHIFT akken ad tferneḍ aṭas),\\nneɣ ṭṭef Alt akken ad ternuḍ tinqiḍin timaynutin","placeImage":"Ssit akken ad tserseḍ tugna, neɣ ssit u zuɣer akken ad tesbaduḍ tiddi-ines s ufus","publishLibrary":"Siẓreg tamkarḍit-inek•inem","bindTextToElement":"Ssed ɣef kcem akken ad ternuḍ aḍris","deepBoxSelect":"Ṭṭef CtrlOrCmd akken ad tferneḍ s telqey, yerna ad trewleḍ i uzuɣer","eraserRevert":"Ssed Alt akken ad tsefsxeḍ iferdisen yettwacerḍen i tukksa","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"Ulamek abeqqeḍ n teskant","canvasTooBig":"Taɣzut n usuneɣ tezmer ad tili temeqqer aṭas.","canvasTooBigTip":"Tixidest: eɛreḍ ad tesqerbeḍ ciṭ iferdisen yembaɛaden."},"errorSplash":{"headingMain":"Teḍra-d tuccḍa. Eɛreḍ ","clearCanvasMessage":"Ma yella tulsa n usali ur tefri ara ugur, eɛreḍ ","clearCanvasCaveat":" Ayagi ad d-iglu s usṛuḥu n umahil ","trackedToSentry":"Tuccḍa akked umesmagi {{eventId}} tettwasekles deg unagraw-nneɣ.","openIssueMessage":"Nḥuder aṭas akken ur nseddu ara talɣut n usayes-inek (m) di tuccḍa. Ma yella asayes-inek (m) mačči d amaẓlay, ttxil-k (m) xemmem ad ḍefreḍ Ma ulac uɣilif seddu talɣut ukessar-agi s wenɣal akked usenṭeḍ di GitHub issue.","sceneContent":"Agbur n usayes:"},"roomDialog":{"desc_intro":"Tzemreḍ ad d-teɛerḍeḍ medden ɣer usayes-inek (m) amiran akken ad ttekkin yid-k.","desc_privacy":"Ur tqelliq ara, tiɣimit tsseqdac awgelhen ixef s ixef, dɣa ayen ara tsunɣeḍ ad iqqim d amaẓlay. Ula d aqeddac-nneɣ ur yezmir ara ad iwali acu txeddemeḍ.","button_startSession":"Bdu tiɣimit","button_stopSession":"Ḥbes tiɣimit","desc_inProgressIntro":"Tiɣimit n umɛawen s srid tetteddu akka tura.","desc_shareLink":"Bḍu aseɣwen-agi akked medden ukud tebɣiḍ ad temɛawaneḍ:","desc_exitSession":"Aḥbas n tɣimit ad k (m) yesenser si texxamt, maca ad tizmireḍ ad tkemmeleḍ amahil s usayes, s wudem adigan. Ẓer belli ayagi ur yettḥaz ara imdanen-nniḍen, yerna ad izmiren ad kemmelen ad mɛawanen di tsuffeɣt-nnsen.","shareTitle":"Rnu ɣer tɣimit n umɛiwen s srid n Excalidraw"},"errorDialog":{"title":"Tuccḍa"},"exportDialog":{"disk_title":"Sekles deg uḍebsi","disk_details":"Sekles isefka n usayes deg ufaylu ansi ara tizmireḍ ad d-tketreḍ areḍqal.","disk_button":"Sekles deg ufaylu","link_title":"Aseɣwen n beṭṭu","link_details":"Sifeḍ am useɣwen n tɣuri kan.","link_button":"Sifeḍ deg useɣwen","excalidrawplus_description":"Sekles asayes-inek•inem di tallunt n umahil Excalidraw+.","excalidrawplus_button":"Sifeḍ","excalidrawplus_exportError":"Ulamek asifeḍ ɣer Excalidraw+ akka tura..."},"helpDialog":{"blog":"Ɣeṛ ablug-nneɣ","click":"ssit","deepSelect":"Afran s telqey","deepBoxSelect":"Afran s telqey s tnaka, yerna ad tyrewleḍ i uzuɣer","curvedArrow":"Taneccabt izelgen","curvedLine":"Izirig izelgen","documentation":"Tasemlit","doubleClick":"ssit snat n tikkal","drag":"zuɣer","editor":"Amaẓrag","editLineArrowPoints":"Ẓreg tinqiḍin n yizirig/taneccabt","editText":"Ẓreg aḍris/rnu tabzimt","github":"Tufiḍ-d ugur? Azen-aɣ-d","howto":"Ḍfer imniren-nneɣ","or":"neɣ","preventBinding":"Seḥbes tuqqna n tneccabin","tools":"Ifecka","shortcuts":"Inegzumen n unasiw","textFinish":"Fak asiẓreg (amaẓrag n uḍris)","textNewLine":"Rnu ajerriḍ amaynut (amaẓrag n uḍris)","title":"Tallelt","view":"Tamuɣli","zoomToFit":"Simɣur akken ad twliḍ akk iferdisen","zoomToSelection":"Simɣur ɣer tefrayt","toggleElementLock":"Sekkeṛ/kkes asekker i tefrayt","movePageUpDown":"Smutti asebter d asawen/akessar","movePageLeftRight":"Smutti asebter s azelmaḍ/ayfus"},"clearCanvasDialog":{"title":"Sfeḍ taɣzut n usuneɣ"},"publishDialog":{"title":"Suffeɣ-d tamkarḍit","itemName":"Isem n uferdis","authorName":"Isem n umeskar","githubUsername":"Isem n useqdac n GitHub","twitterUsername":"Isem n useqdac n Twitter","libraryName":"Isem n temkarḍit","libraryDesc":"Aglam n temkarḍit","website":"Asmel n web","placeholder":{"authorName":"Isem neɣ isem n useqdac inek•inem","libraryName":"Isem n temkarḍit-inek•inem","libraryDesc":"Aglam n temkarḍit-inek•inem akken ad tɛiwneḍ medden ad fehmen aseqdec-inec","githubHandle":"Isem n useqdac n GitHub ( d anefrunan) akken ad tizmireḍ ad tisẓrigeḍ tamkarḍit ticki tuzneḍ-tt i uselken","twitterHandle":"Isem n useqdac n Twitter (d anefrunan) akken ad nẓer anwa ara nsenmer deg udellel di Twitter","website":"Aseɣwen ɣer usmel-inek•inem neɣ wayeḍ (d anefrunan)"},"errors":{"required":"Yettwasra","website":"Sekcem URL ameɣtu"},"noteDescription":"Azen tamkarḍit-inek•inem akken ad teddu di akaram azayez n temkarḍiti yimdanen-nniḍen ara isqedcen deg wunuɣen-nnsen.","noteGuidelines":"Tamkarḍit teḥwaǧ ad tettwaqbel s ufus qbel. Ma ulac uɣilif ɣer iwellihen send ad tazneḍ. Tesriḍ amiḍan n GitHub akken ad tmmeslayeḍ yerna ad tgeḍ ibeddilen ma yelaq, maca mačči d ayen yettwaḥetmen.","noteLicense":"Mi tuzneḍ ad tqebleḍ akken tamkarḍit ad d-teffeɣ s Turagt MIT, ayen yebɣan ad d-yini belli yal yiwen izmer ad ten-iseqdec war tilist.","noteItems":"Yal aferdis n temkarḍit isefk ad isɛu isem-is i yiman-is akken ad yili wamek ara yettusizdeg. Iferdisen-agi n temkarḍit ad ddun:","atleastOneLibItem":"Ma ulac uɣilif fern ma drus yiwen n uferdis n temkarḍit akken ad tebduḍ","republishWarning":"Tamawt: kra n yiferdisen yettwafernen ttwacerḍen ffeɣen-d/ttwaznen. Isefk ad talseḍ tuzzna n yiferdisen anagar mi ara tleqqemeḍ tamkarḍit neɣ tuzzna yellan."},"publishSuccessDialog":{"title":"Tamkarḍit tettwazen","content":"Tanemmirt-ik•im {{authorName}}. Tamkarḍit-inek•inem tettwazen i weselken. Tzemreḍ ad tḍefreḍ aẓayerdagi"},"confirmDialog":{"resetLibrary":"Ales awennez n temkarḍit","removeItemsFromLib":"Kkes iferdisen yettafernen si temkarḍit"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"Unuɣen-inek (m) ttuwgelhnen seg yixef s ixef dɣa iqeddacen n Excalidraw werǧin ad ten-walin. ","link":"Amagrad ɣef uwgelhen ixef s ixef di Excalidraw"},"stats":{"angle":"Tiɣmeṛt","element":"Aferdis","elements":"Iferdisen","height":"Tattayt","scene":"Asayes","selected":"Yettwafren","storage":"Aḥraz","title":"","total":"Aɣrud","version":"Alqem","versionCopy":"Sit ad tneɣleḍ","versionNotAvailable":"Ur inuḥ ulqem","width":"Tehri"},"toast":{"addedToLibrary":"Yettwarna ɣer temkarḍit","copyStyles":"Iɣunab yettwaneɣlen.","copyToClipboard":"Yettwaɣel ɣer tecfawit.","copyToClipboardAsPng":"{{exportSelection}} yettwanɣel ɣer tecfawit am PNG\\n({{exportColorScheme}})","fileSaved":"Afaylu yettwasekles.","fileSavedToFilename":"Yettwasekles di {filename}","canvas":"taɣzut n usuneɣ","selection":"tafrayt","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Afrawan","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"Akk isefka-inek•inem ttwakelsen s wudem adigan deg yiminig-inek•inem.","center_heading_plus":"Tebɣiḍ ad tedduḍ ɣer Excalidraw+ deg umḍiq?","menuHint":"Asifeḍ, ismenyifen, tutlayin, ..."},"defaults":{"menuHint":"Asifeḍ, ismenyifen, d wayen-nniḍen...","center_heading":"","toolbarHint":"Fren afecku tebduḍ asuneɣ!","helpHint":"Inegzumen akked tallelt"}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/kk-KZ-json-e9dd81c22419efd44478.js b/public/excalidraw/excalidraw-assets-dev/locales/kk-KZ-json-e9dd81c22419efd44478.js
new file mode 100644
index 0000000..3eb43f7
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/kk-KZ-json-e9dd81c22419efd44478.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/kk-KZ-json"],{
+
+/***/ "../../locales/kk-KZ.json":
+/*!********************************!*\
+ !*** ../../locales/kk-KZ.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Қою","pasteAsPlaintext":"","pasteCharts":"Диаграммаларды қою","selectAll":"Бәрін таңдау","multiSelect":"","moveCanvas":"","cut":"Қию","copy":"Көшіру","copyAsPng":"","copyAsSvg":"","copyText":"","bringForward":"","sendToBack":"","bringToFront":"","sendBackward":"","delete":"Жою","copyStyles":"Стильдерді көшіру","pasteStyles":"Стильдерді қою","stroke":"","background":"","fill":"","strokeWidth":"","strokeStyle":"","strokeStyle_solid":"","strokeStyle_dashed":"","strokeStyle_dotted":"","sloppiness":"","opacity":"","textAlign":"","edges":"","sharp":"","round":"","arrowheads":"Нұсқар ұштары","arrowhead_none":"Жоқ","arrowhead_arrow":"Нұсқар","arrowhead_bar":"Тосқауыл","arrowhead_dot":"Нүкте","arrowhead_triangle":"","fontSize":"Қаріп өлшемі","fontFamily":"Қаріп тобы","addWatermark":"","handDrawn":"","normal":"Қалыпты","code":"","small":"Кіші","medium":"Орта","large":"Үлкен","veryLarge":"Өте үлкен","solid":"","hachure":"","zigzag":"","crossHatch":"","thin":"","bold":"","left":"Солға","center":"Ортаға","right":"Оңға","extraBold":"","architect":"","artist":"","cartoonist":"","fileTitle":"Файл атауы","colorPicker":"","canvasColors":"","canvasBackground":"","drawingCanvas":"","layers":"","actions":"","language":"Тіл","liveCollaboration":"","duplicateSelection":"Көшірме","untitled":"Атауысыз","name":"","yourName":"","madeWithExcalidraw":"","group":"","ungroup":"","collaborators":"","showGrid":"","addToLibrary":"","removeFromLibrary":"","libraryLoadingMessage":"","libraries":"","loadingScene":"","align":"","alignTop":"","alignBottom":"","alignLeft":"","alignRight":"","centerVertically":"","centerHorizontally":"","distributeHorizontally":"","distributeVertically":"","flipHorizontal":"","flipVertical":"","viewMode":"","share":"","showStroke":"","showBackground":"","toggleTheme":"","personalLib":"","excalidrawLib":"","decreaseFontSize":"","increaseFontSize":"","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"","editEmbed":"","create":"","createEmbed":"","label":"","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"","unlock":"","lockAll":"","unlockAll":""},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"","exportJSON":"","exportImage":"","export":"","copyToClipboard":"","save":"","saveAs":"","load":"","getShareableLink":"","close":"Жабу","selectLanguage":"Тілді таңдау","scrollBackToContent":"","zoomIn":"","zoomOut":"","resetZoom":"","menu":"Mәзір","done":"Дайын","edit":"","undo":"","redo":"","resetLibrary":"","createNewRoom":"","fullScreen":"","darkMode":"","lightMode":"","zenMode":"","objectsSnapMode":"","exitZenMode":"","cancel":"","clear":"","remove":"","embed":"","publishLibrary":"","submit":"","confirm":"","embeddableInteractionButton":""},"alerts":{"clearReset":"","couldNotCreateShareableLink":"","couldNotCreateShareableLinkTooBig":"","couldNotLoadInvalidFile":"","importBackendFailed":"","cannotExportEmptyCanvas":"","couldNotCopyToClipboard":"","decryptFailed":"","uploadedSecurly":"","loadSceneOverridePrompt":"","collabStopOverridePrompt":"","errorAddingToLibrary":"","errorRemovingFromLibrary":"","confirmAddLibrary":"","imageDoesNotContainScene":"","cannotRestoreFromImage":"","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"","invalidEncryptionKey":"","collabOfflineWarning":""},"errors":{"unsupportedFileType":"","imageInsertError":"Суретті жүктеу мүмкін болмады. Кейінірек қайталап көріңіз...","fileTooBig":"Файл өте үлкен. Максималды рұқсат етілген көлем {{maxSize}}.","svgImageInsertError":"","failedToFetchImage":"","invalidSVGString":"","cannotResolveCollabServer":"","importLibraryError":"","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"","image":"Суретті қою","rectangle":"","diamond":"","ellipse":"","arrow":"Нұсқар","line":"","freedraw":"","text":"Мәтін","library":"","lock":"","penMode":"","link":"","eraser":"","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"","selectedShapeActions":"","shapes":""},"hints":{"canvasPanning":"","linearElement":"","freeDraw":"","text":"","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"","lockAngle":"","resize":"","resizeImage":"","rotate":"","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"","canvasTooBig":"","canvasTooBigTip":""},"errorSplash":{"headingMain":"","clearCanvasMessage":"","clearCanvasCaveat":"","trackedToSentry":"","openIssueMessage":"","sceneContent":""},"roomDialog":{"desc_intro":"","desc_privacy":"","button_startSession":"","button_stopSession":"","desc_inProgressIntro":"","desc_shareLink":"","desc_exitSession":"","shareTitle":""},"errorDialog":{"title":"Қате"},"exportDialog":{"disk_title":"","disk_details":"Сахна деректерін кейін қайта импорттауға болатын файлға экспорттаңыз.","disk_button":"Файлға сақтау","link_title":"Ортақ сілтеме","link_details":"Тек оқуға арналған сілтеме ретінде экспорттау.","link_button":"Сілтемеге экспорттау","excalidrawplus_description":"Сахнаны өзіңіздің Excalidraw+ жұмыс кеңістігінде сақтаңыз.","excalidrawplus_button":"Экспорт","excalidrawplus_exportError":"Қазіргі уақытта Excalidraw+ үшін экспорттау мүмкін емес..."},"helpDialog":{"blog":"Біздің блогты оқу","click":"шерту","deepSelect":"","deepBoxSelect":"","curvedArrow":"Майысқан нұсқар","curvedLine":"Майысқан сызық","documentation":"Құжаттама","doubleClick":"қос шерту","drag":"апару","editor":"Өңдеу","editLineArrowPoints":"","editText":"","github":"Қате таптыңыз ба? Жолдаңыз","howto":"Біздің нұсқаулықтарды орындаңыз","or":"немесе","preventBinding":"Нұсқарды байланыстыруға жол бермеу","tools":"","shortcuts":"Пернетақта пәрмендері","textFinish":"Өңдеуді аяқтау (мәтіндік редактор)","textNewLine":"Жаңа жолға көшу (мәтіндік редактор)","title":"Көмек","view":"Көру","zoomToFit":"Барлық элементтердің көлеміне сәйкес үлкейту","zoomToSelection":"Таңдалғанды үлкейту","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"","githubUsername":"","twitterUsername":"","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"Сіздің сызбаларыңыз өтпелі шифрлеу арқылы шифрланған, сондықтан Excalidraw серверлері оларды ешқашан көрмейді.","link":"Excalidraw қолданатын өтпелі шифрлеу туралы блог жазбасы"},"stats":{"angle":"Бұрыш","element":"Элемент","elements":"Элементтер","height":"Биіктігі","scene":"Сахна","selected":"Таңдалды","storage":"Сақтау көлемі","title":"","total":"Барлығы","version":"Нұсқа","versionCopy":"Көшіру үшін басыңыз","versionNotAvailable":"Бұл нұсқа қолжетімсіз","width":"Ені"},"toast":{"addedToLibrary":"","copyStyles":"Стильдер көшірілді.","copyToClipboard":"","copyToClipboardAsPng":"","fileSaved":"Файл сақталды.","fileSavedToFilename":"{filename} сақталды","canvas":"","selection":"таңдау","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/km-KH-json-be77acee611d96d88dda.js b/public/excalidraw/excalidraw-assets-dev/locales/km-KH-json-be77acee611d96d88dda.js
new file mode 100644
index 0000000..03c1ed1
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/km-KH-json-be77acee611d96d88dda.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/km-KH-json"],{
+
+/***/ "../../locales/km-KH.json":
+/*!********************************!*\
+ !*** ../../locales/km-KH.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"បិទភ្ជាប់","pasteAsPlaintext":"បិទភ្ជាប់ជាអត្ថបទធម្មតា","pasteCharts":"បិទភ្ជាប់តារាង","selectAll":"ជ្រើសរើសទាំងអស់","multiSelect":"បន្ថែមធាតុទៅលើការជ្រើសរើស","moveCanvas":"ផ្លាស់ទីបាវ","cut":"កាត់","copy":"ចម្លង","copyAsPng":"ចម្លងទៅក្តារតម្បៀតខ្ទាស់ជា PNG","copyAsSvg":"ចម្លងទៅក្តារតម្បៀតខ្ទាស់ជា SVG","copyText":"ចម្លងទៅក្តារតម្បៀតខ្ទាស់ជាអត្ថបទ","bringForward":"នាំយកទៅលើ","sendToBack":"នាំយកទៅក្រោយបង្អស់","bringToFront":"នាំយកទៅលើបង្អស់","sendBackward":"នាំយកទៅក្រោយ","delete":"លុប","copyStyles":"ចម្លងរចនាប័ទ្ម","pasteStyles":"បិទភ្ជាប់រចនាប័ទ្ម","stroke":"ខ្វាច់","background":"ផ្ទៃខាងក្រោយ","fill":"បំពេញ","strokeWidth":"ទទឹងខ្វាច់","strokeStyle":"រចនាប័ទ្មរបស់ខ្វាច់","strokeStyle_solid":"តាន់","strokeStyle_dashed":"ដាច់ៗ","strokeStyle_dotted":"ចំណុចៗ","sloppiness":"រចនាប័ទ្មបន្ទាត់","opacity":"ភាពច្បាស់","textAlign":"តម្រឹមអត្ថបទ","edges":"គែម","sharp":"មុត","round":"រាងមូល","arrowheads":"ក្បាលព្រួញ","arrowhead_none":"គ្មាន","arrowhead_arrow":"ព្រួញ","arrowhead_bar":"របារ","arrowhead_dot":"ចំណុច","arrowhead_triangle":"ត្រីកោណ","fontSize":"ទំហំពុម្ពអក្សរ","fontFamily":"ក្រុមពុម្ពអក្សរ","addWatermark":"បន្ថែមវ៉ាត់ធើម៉ាក \\"Made with Excalidraw\\"","handDrawn":"គូរដោយដៃ","normal":"ធម្មតា","code":"កូដ","small":"តូច","medium":"មធ្យម","large":"ធំ","veryLarge":"ធំខ្លាំង","solid":"តាន់","hachure":"Hachure","zigzag":"Zigzag","crossHatch":"បន្ទាត់ឆ្នូតៗ","thin":"ស្តើង","bold":"ដឹត","left":"ខាងឆ្វេង","center":"កណ្ដាល","right":"នៅខាងស្ដាំ","extraBold":"ដិតបន្ថែម","architect":"ស្ថាបត្យករ","artist":"សិល្បៈករ","cartoonist":"អ្នកគំនូរជីវចល","fileTitle":"ឈ្មោះឯកសារ","colorPicker":"ឧបករណ៍ជ្រើសពណ៌","canvasColors":"ប្រើលើបាវ","canvasBackground":"ផ្ទៃខាងក្រោយបាវ","drawingCanvas":"តំបន់គំនូរ","layers":"ស្រទាប់","actions":"សកម្មភាព","language":"ភាសា","liveCollaboration":"សហការគ្នាផ្ទាល់...","duplicateSelection":"ចម្លង","untitled":"គ្មានឈ្មោះ","name":"ឈ្មោះ","yourName":"ឈ្មោះរបស់អ្នក","madeWithExcalidraw":"បង្កើតជាមួយ Excalidraw","group":"ការជ្រើសរើសជាក្រុម","ungroup":"បំបែកក្រុមការជ្រើសរើសជាក្រុម","collaborators":"អ្នកសហការ","showGrid":"បង្ហាញក្រឡាចត្រង្គ","addToLibrary":"បន្ថែមទៅបណ្ណាល័យ","removeFromLibrary":"លុបចេញពីបណ្ណាល័យ","libraryLoadingMessage":"កំពុងផ្ទុកបណ្ណាល័យ...","libraries":"រកមើលបណ្ណាល័យ","loadingScene":"កំពុងផ្ទុកស៊ីន...","align":"តម្រឹម","alignTop":"តម្រឹមផ្នែកខាងលើ","alignBottom":"តម្រឹមផ្នែកខាងក្រោម","alignLeft":"តម្រឹមឆ្វេង","alignRight":"តម្រឹមស្តាំ","centerVertically":"កណ្តាលបញ្ឈរ","centerHorizontally":"កណ្តាលផ្ដេក","distributeHorizontally":"ចែកចាយផ្ដេក","distributeVertically":"ចែកចាយបញ្ឈរ","flipHorizontal":"ត្រឡប់ដោយផ្ដេក","flipVertical":"ត្រឡប់ដោយបញ្ឈរ","viewMode":"ម៉ូដបង្ហាញ","share":"ចែករំលែក","showStroke":"បង្ហាញឧបករណ៍ជ្រើសរើសពណ៌ខ្វាច់","showBackground":"បង្ហាញឧបករណ៍ជ្រើសរើសពណ៌ផ្ទៃខាងក្រោយ","toggleTheme":"បិទ/បើកប្រធានបទ","personalLib":"បណ្ណាល័យផ្ទាល់ខ្លួន","excalidrawLib":"បណ្ណាល័យ Excalidraw","decreaseFontSize":"បន្ថយទំហំពុម្ពអក្សរ","increaseFontSize":"បង្កើនទំហំពុម្ពអក្សរ","unbindText":"ស្រាយអត្ថបទ","bindText":"ភ្ជាប់អត្ថបទទៅប្រអប់","createContainerFromText":"រុំអត្ថបទក្នុងប្រអប់មួយ","link":{"edit":"កែតំណភ្ជាប់","editEmbed":"","create":"បង្កើតតំណភ្ជាប់","createEmbed":"","label":"តំណ","labelEmbed":"","empty":""},"lineEditor":{"edit":"កែសម្រួលបន្ទាត់","exit":"ចាកចេញពីការកែសម្រួលបន្ទាត់"},"elementLock":{"lock":"ចាក់សោ","unlock":"ដោះសោ","lockAll":"ចាក់សោទាំងអស់","unlockAll":"ដោះសោទាំងអស់"},"statusPublished":"ត្រូវបានបោះពុម្ពផ្សាយ","sidebarLock":"ទុករបារចំហៀងបើក","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"មិនទាន់មានធាតុបន្ថែមទេ...","hint_emptyLibrary":"ជ្រើសរើសធាតុនៅលើបាវដើម្បីបន្ថែមវានៅទីនេះ ឬដំឡើងបណ្ណាល័យពីឃ្លាំងសាធារណៈខាងក្រោម។","hint_emptyPrivateLibrary":"ជ្រើសរើសធាតុនៅលើបាវដើម្បីបន្ថែមវានៅទីនេះ"},"buttons":{"clearReset":"កំណត់បាវឡើងវិញ","exportJSON":"នាំចេញជាឯកសារ","exportImage":"នាំរូបភាពចេញ","export":"រក្សាទុកនៅ...","copyToClipboard":"ចម្លងទៅក្តារតម្បៀតខ្ទាស់","save":"រក្សាទុកទៅឯកសារបច្ចុប្បន្ន","saveAs":"រក្សាទុកជា","load":"បើក","getShareableLink":"យកតំណដែលអាចចែករំលែកបាន","close":"បិទ","selectLanguage":"រើសភាសា","scrollBackToContent":"រំកិលត្រឡប់ទៅមាតិកាវិញ","zoomIn":"ពង្រីក","zoomOut":"បង្រួម","resetZoom":"កំណត់ការពង្រីកឡើងវិញ","menu":"ម៉ឺនុយ","done":"រួចរាល់","edit":"កែ","undo":"ត្រឡប់វិញ","redo":"ធ្វើវិញ","resetLibrary":"កំណត់បណ្ណាល័យឡើងវិញ","createNewRoom":"បង្កើតបន្ទប់ថ្មី","fullScreen":"ពេញអេក្រង់","darkMode":"ម៉ូដងងឹត","lightMode":"ម៉ូដភ្លឺ","zenMode":"ម៉ូត Zen","objectsSnapMode":"","exitZenMode":"ចេញពី zen ម៉ូត","cancel":"បោះបង់","clear":"សម្អាត","remove":"ដកចេញ","embed":"","publishLibrary":"បោះពុម្ពផ្សាយ","submit":"ដាក់ស្នើ","confirm":"បញ្ជាក់","embeddableInteractionButton":""},"alerts":{"clearReset":"វានឹងសម្អាតបាវទាំងមូល។ តើអ្នកប្រាកដឬអត់?","couldNotCreateShareableLink":"មិនអាចបង្កើតតំណដែលអាចចែករំលែកបានទេ។","couldNotCreateShareableLinkTooBig":"មិនអាចបង្កើតតំណដែលអាចចែករំលែកបាន៖ ស៊ីនធំពេក","couldNotLoadInvalidFile":"មិនអាចផ្ទុកឯកសារមិនត្រឹមត្រូវបានទេ។","importBackendFailed":"ការនាំចូលពីម៉ាស៊ីនមេបានបរាជ័យ។","cannotExportEmptyCanvas":"មិនអាចនាំចេញបាវទទេបានទេ។","couldNotCopyToClipboard":"មិនអាចចម្លងទៅក្ដារតម្បៀតខ្ទាស់បានទេ។","decryptFailed":"មិនអាចឌិគ្រីបទិន្នន័យបានទេ។","uploadedSecurly":"ការបង្ហោះត្រូវបានការពារដោយការអ៊ិនគ្រីបពីចុងដល់ចប់ មានន័យថា ទាំងម៉ាស៊ីនមេរបស់ Excalidraw ឬភាគីទីបីមិនអាចអានខ្លឹមសារបានទេ។","loadSceneOverridePrompt":"ការផ្ទុកគំនូរខាងក្រៅនឹងជំនួសមាតិកាដែលមានស្រាប់របស់អ្នក។ តើអ្នកចង់បន្តទេ?","collabStopOverridePrompt":"ការបញ្ឈប់សម័យនឹងសរសេរជាន់លើគំនូរដែលបានរក្សាទុកនៅលើកុំព្យូទ័ររបស់អ្នកពីមុន។ តើអ្នកប្រាកដឬអត់?\\n\\n(ប្រសិនបើអ្នកចង់រក្សាគំនូរដែលនៅលើកុំព្យូទ័ររបស់អ្នក គ្រាន់តែបិទផ្ទាំងកម្មវិធីរុករក។)","errorAddingToLibrary":"មិនអាចបន្ថែមធាតុទៅបណ្ណាល័យបានទេ","errorRemovingFromLibrary":"មិនអាចលុបធាតុចេញពីបណ្ណាល័យបានទេ","confirmAddLibrary":"វានឹងបន្ថែមរូបរាង {{numShapes}} ទៅបណ្ណាល័យរបស់អ្នក។ តើអ្នកប្រាកដឬអត់?","imageDoesNotContainScene":"រូបភាពនេះហាក់ដូចជាមិនមានទិន្នន័យស៊ីនណាមួយទេ។ តើអ្នកបានបើកការបង្កប់ស៊ីននៅពេលនាំចេញទេ?","cannotRestoreFromImage":"មិនអាចស្ដារស៊ីនពីឯកសាររូបភាពនេះបានទេ","invalidSceneUrl":"មិនអាចនាំចូលស៊ីនពី URL ដែលបានផ្តល់ឱ្យទេ។ វាមានទម្រង់ខុស ឬមិនមានទិន្នន័យ Excalidraw JSON ដែលត្រឹមត្រូវ។","resetLibrary":"វានឹងសម្អាតបាវទាំងមូល។ តើអ្នកប្រាកដឬអត់?","removeItemsFromsLibrary":"តើអ្នកប្រាកដថាចង់លុប {{count}} ធាតុចេញពីបណ្ណាល័យទេ?","invalidEncryptionKey":"សោអ៊ីនគ្រីបត្រូវតែមាន 22 តួអក្សរ។ ការសហការផ្ទាល់ត្រូវបានបិទ។","collabOfflineWarning":"គ្មានការតភ្ជាប់អ៊ីនធឺណិត។\\nការផ្លាស់ប្តូររបស់អ្នកនឹងមិនត្រូវបានរក្សាទុកទេ!"},"errors":{"unsupportedFileType":"ប្រភេទឯកសារមិនត្រូវបានគាំទ្រទេ។","imageInsertError":"មិនអាចបញ្ចូលរូបភាពបានទេ។ សូមព្យាយាមម្តងទៀតនៅពេលក្រោយ……","fileTooBig":"ឯកសារធំពេក។ ទំហំអតិបរមាដែលអនុញ្ញាតគឺ {{maxSize}}។","svgImageInsertError":"មិនអាចបញ្ចូលរូបភាព SVG បានទេ។ ស្លាក SVG ហាក់ដូចជាមិនត្រឹមត្រូវ។","failedToFetchImage":"","invalidSVGString":"SVG មិនត្រឹមត្រូវ។","cannotResolveCollabServer":"មិនអាចភ្ជាប់ទៅម៉ាស៊ីនមេសហការផ្ទាល់បានទេ។ សូមផ្ទុកទំព័រឡើងវិញ ហើយព្យាយាមម្តងទៀត។","importLibraryError":"មិនអាចផ្ទុកបណ្ណាល័យបានទេ។","collabSaveFailed":"មិនអាចរក្សាទុកទៅម៉ាស៊ីនមេបានទេ។ ប្រសិនបើបញ្ហានៅតែបន្តកើតមាន អ្នកគួរតែរក្សាទុកឯកសាររបស់អ្នកនៅលើកុំព្យូទ័ររបស់អ្នកសិន ដើម្បីធានាថាការងាររបស់អ្នកមិនបាត់បង់។","collabSaveFailed_sizeExceeded":"មិនអាចរក្សាទុកទៅម៉ាស៊ីនមេបានទេ, ផ្ទាំងបាវហាក់ដូចជាធំពេក។ អ្នកគួរតែរក្សាទុកឯកសាររបស់អ្នកនៅលើកុំព្យូទ័ររបស់អ្នកសិន ដើម្បីធានាថាការងាររបស់អ្នកមិនបាត់បង់។","brave_measure_text_error":{"line1":"អ្នកហាក់ដូចជាកំពុងប្រើប្រាស់កម្មវិធីរុករកតាមអ៊ីនធឺណិត Brave ជាមួយនឹងការកំណត់ ការពារស្នាមម្រាមដៃយ៉ាងធ្ងន់ធ្ងរ ត្រូវបានបើក។","line2":"វាអាចបណ្តាលឱ្យមានការបំបែក ធាតុអត្ថបទ នៅក្នុងគំនូររបស់អ្នក។","line3":"យើងណែនាំយ៉ាងមុតមាំឱ្យបិទការកំណត់នេះ។ អ្នកអាចអនុវត្តតាម ជំហានទាំងនេះ ដើម្បីបិទការកំណត់នេះ។","line4":"ប្រសិនបើការបិទការកំណត់នេះមិនបានជួសជុលការបង្ហាញធាតុអត្ថបទទេ សូមដាក់ issue នៅលើ GitHub ឬរាយការណ៍នៅលើ Discord របស់យើង"},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"ការជ្រើសរើស","image":"បញ្ចូលរូបភាព","rectangle":"ចតុកោណកែង","diamond":"ពេជ្រ","ellipse":"ពងក្រពើ","arrow":"ព្រួញ","line":"បន្ទាត់","freedraw":"គូរ","text":"អត្ថបទ","library":"បណ្ណាល័យ","lock":"រក្សារឧបករណ៍ដែលបានជ្រើសរើសបន្ទាប់ពីគូររួច","penMode":"របៀបប៊ិច - ជៀសវាងការប៉ះ","link":"បន្ថែម/ធ្វើបច្ចុប្បន្នភាពតំណភ្ជាប់សម្រាប់រូបរាងដែលបានជ្រើសរើស","eraser":"ជ័រលុប","frame":"","embeddable":"","laser":"","hand":"ដៃ (panning tool)","extraTools":""},"headings":{"canvasActions":"សកម្មភាពបាវ","selectedShapeActions":"សកម្មភាពរបស់រាងដែលបានជ្រើសរើស","shapes":"រាង"},"hints":{"canvasPanning":"ដើម្បីផ្លាស់ទីបាវ សូមសង្កត់កង់កណ្ដុរឬគ្រាប់ចុចspacebarខណៈពេលកំពុងអូស ឬប្រើឧបករណ៍ដៃ។","linearElement":"ចុចដើម្បីបង្កើតចំណុចច្រើន អូសដើម្បីបង្កើតបន្ទាត់មួយ","freeDraw":"ចុចហើយអូស លែងពេលរួចរាល់","text":"គន្លឹះ៖ អ្នកក៏អាចបន្ថែមអត្ថបទដោយចុចពីរដងនៅកន្លែងណាមួយដោយប្រើឧបករណ៍ជ្រើសរើស","embeddable":"","text_selected":"ចុចពីរដង ឬចុច ENTER ដើម្បីកែសម្រួលអត្ថបទ","text_editing":"ចុច Escape ឬ CtrlOrCmd +ENTER ដើម្បីបញ្ចប់ការកែសម្រួល","linearElementMulti":"ចុចលើចំណុចចុងក្រោយ ឬចុច Esc/Enter ដើម្បីបញ្ចប់","lockAngle":"អ្នកអាចសង្កត់ Shift ដើម្បីកំណត់មុំ","resize":"អ្នកអាចសង្កត់ SHIFT ដើម្បីបងំ្ខឲមានសមាមាត្រ ខណៈពេលដែលប្តូរទំហំ\\nសង្កត់ ALT ដើម្បីប្តូរទំហំពីកណ្តាល","resizeImage":"អ្នកអាចប្តូរទំហំរូបភាពដោយសេរីដោយសង្កត់ SHIFT,\\nសង្កត់ ALT ដើម្បីប្តូរទំហំពីកណ្តាល","rotate":"អ្នកអាចសង្កត់ Shift ខណៈពេលកំពុងបង្វិល ដើម្បីកម្រិតមុំ","lineEditor_info":"សង្កត់ CtrlOrCmd ហើយចុចពីរដង ឬចុច CtrlOrCmd + Enter ដើម្បីកែសម្រួលចំណុច","lineEditor_pointSelected":"ចុច Delete ដើម្បីលុបចំណុច(ច្រើន)\\nCtrlOrCmd+D ដើម្បីចម្លង, ឬអូសដើម្បីផ្លាស់ទី","lineEditor_nothingSelected":"ជ្រើសរើសចំណុចដែលត្រូវកែសម្រួល (សង្កត់ SHIFT ដើម្បីជ្រើសរើសច្រើនចំណុច)\\nឬ សង្កត់ Alt ហើយចុចដើម្បីបន្ថែមចំណុចថ្មី។","placeImage":"ចុចដើម្បីដាក់រូបភាព ឬចុចហើយអូសដើម្បីកំណត់ទំហំរបស់រូបភាពដោយដៃ","publishLibrary":"បោះពុម្ពផ្សាយបណ្ណាល័យផ្ទាល់ខ្លួនរបស់អ្នក","bindTextToElement":"ចុច Enter ដើម្បីបន្ថែមអត្ថបទ","deepBoxSelect":"សង្កត់ CtrlOrCmd ដើម្បីជ្រើសរើសយ៉ាងជ្រៅ និងជៀសវាងការអូស","eraserRevert":"សង្កត់ Alt ដើម្បីដកការជ្រើសរើសធាតុដែលត្រូវបានសម្គាល់សម្រាប់ការលុប","firefox_clipboard_write":"បើកមុខងារនេះដោយកំណត់ទង់ \\"dom.events.asyncClipboard.clipboardItem\\" ទៅ \\"true\\" \\nដើម្បីផ្លាស់ប្តូរទង់កម្មវិធីរុករកនៅក្នុង Firefox សូមចូលទៅកាន់ទំព័រ \\"about:config\\"។","disableSnapping":""},"canvasError":{"cannotShowPreview":"មិនអាចបង្ហាញការមើលជាមុនបាន","canvasTooBig":"បាវអាចមានទំហំធំពេក។","canvasTooBigTip":"គន្លឹះ៖ ព្យាយាមផ្លាស់ទីធាតុដែលឆ្ងាយបំផុតឱ្យទៅជិតគ្នាបន្តិច។"},"errorSplash":{"headingMain":"បានជួបប្រទះកំហុសមួយ។ សូមព្យាយាម ។","clearCanvasMessage":"ប្រសិនបើការផ្ទុកឡើងវិញមិនអាចដោះស្រាយកំហុសបានទេ សូមសាកល្បង ","clearCanvasCaveat":" នេះនឹងបណ្តាលឱ្យបាត់បង់ការងារ ","trackedToSentry":"កំហុសជាមួយលេខសម្គាល់ {{eventId}} ត្រូវបានតាមដាននៅលើប្រព័ន្ធរបស់យើង។","openIssueMessage":"យើងមានការប្រុងប្រយ័ត្នខ្លាំងណាស់ក្នុងការមិនបញ្ចូលព័ត៌មានរបស់ស៊ីនរបស់អ្នកទៅលើកំហុស។ ប្រសិនបើស៊ីនរបស់អ្នកមិនមានលក្ខណៈឯកជនទេ សូមពិចារណាបន្តទៅកាន់ សូមបញ្ចូលព័ត៌មានខាងក្រោមដោយចម្លង និងបិទភ្ជាប់វាទៅក្នុងបញ្ហារបស់ GitHub។","sceneContent":"មាតិកាបាវ៖"},"roomDialog":{"desc_intro":"អ្នកអាចអញ្ជើញអ្នកដទៃឱ្យសហការជាមួយអ្នកនៅលើស៊ីនបច្ចុប្បន្ន។","desc_privacy":"កុំបារម្ភ វគ្គប្រើការអ៊ិនគ្រីបពីចុងដល់ចប់ ដូច្នេះអ្វីដែលអ្នកគូរនឹងនៅតែជាឯកជន។ សូម្បីតែម៉ាស៊ីនមេរបស់យើងក៏នឹងមិនអាចមើលឃើញអ្វីដែលអ្នកកំពុងធ្វើដែរ។","button_startSession":"ចាប់ផ្តើមវគ្គ","button_stopSession":"បញ្ឈប់វគ្គ","desc_inProgressIntro":"វគ្គសហការផ្ទាល់ឥឡូវនេះកំពុងដំណើរការ។","desc_shareLink":"ចែករំលែកតំណនេះជាមួយអ្នកដែលអ្នកចង់សហការជាមួយ៖","desc_exitSession":"ការបញ្ឈប់វគ្គនេះនឹងផ្តាច់អ្នកចេញពីបន្ទប់ ប៉ុន្តែអ្នកនឹងនៅតែអាចបន្តប្រើបាវនៅលើកុំព្យូទ័ររបស់អ្នក។ សូមចំណាំថាវានឹងមិនប៉ះពាល់ដល់អ្នកប្រើប្រាស់ផ្សេងទៀតទេ ហើយពួកគេនឹងនៅតែអាចបន្តសហការលើកំណែរបស់ពួកគេ។","shareTitle":"ចូលរួមវគ្គសហការផ្ទាល់នៅលើ Excalidraw"},"errorDialog":{"title":"មានកំហុស"},"exportDialog":{"disk_title":"រក្សាទុកទៅថាស","disk_details":"នាំចេញទិន្នន័យរបស់ស៊ីនជាឯកសារដែលអ្នកអាចនាំចូលនៅពេលក្រោយ។","disk_button":"រក្សាទុកក្នុងឯកសារ","link_title":"តំណដែលអាចចែករំលែកបាន","link_details":"នាំចេញជាតំណបានតែមើលឬអាន។","link_button":"នាំចេញជាតំណ","excalidrawplus_description":"រក្សាទុកស៊ីនទៅកន្លែងធ្វើការ Excalidraw+ របស់អ្នក។","excalidrawplus_button":"នាំចេញ","excalidrawplus_exportError":"មិនអាចនាំចេញទៅ Excalidraw+ បានទេនៅពេលនេះ..."},"helpDialog":{"blog":"អានប្លក់របស់យើង","click":"ចុច","deepSelect":"ការជ្រើសរើសជាក្រុម","deepBoxSelect":"ជ្រើសរើសជាក្រុម និង ជៀសវាងការអូសទាញផ្លាស់ទី","curvedArrow":"ព្រួញកោង","curvedLine":"ព្រួញកោង","documentation":"ឯកសារ","doubleClick":"ចុចពីរដង","drag":"អូស","editor":"កម្មវិធីនិពន្ធ","editLineArrowPoints":"កែសម្រួលចំណុចនៃបន្ទាត់ ឬព្រួញ","editText":"បន្ថែម ឬកែសម្រួលអត្ថបទ","github":"រកឃើញបញ្ហា? ដាក់ស្នើ","howto":"ឯកសារជំនួយ","or":"ឬ","preventBinding":"ទប់ស្កាត់ការចងព្រួញ","tools":"ឧបករណ៍","shortcuts":"ផ្លូវកាត់ក្តារចុច","textFinish":"បញ្ចប់ការកែសម្រួល (កម្មវិធីនិពន្ធអត្ថបទ)","textNewLine":"ចុះបន្ទាត់ (កម្មវិធីនិពន្ធអត្ថបទ)","title":"ជំនួយ","view":"បង្ហាញ","zoomToFit":"ធ្វើមាត្រដ្ឋានឱ្យសមនឹងធាតុទាំងអស់។","zoomToSelection":"ពង្រីកទៅការជ្រើសរើស","toggleElementLock":"ចាក់សោ/ដោះសោការជ្រើសរើស","movePageUpDown":"ផ្លាស់ទីទំព័រឡើងលើ/ចុះក្រោម","movePageLeftRight":"ផ្លាស់ទីទំព័រទៅឆ្វេង/ស្ដាំ"},"clearCanvasDialog":{"title":"សម្អាតបាវ"},"publishDialog":{"title":"បោះពុម្ពបណ្ណាល័យ","itemName":"ឈ្មោះធាតុ","authorName":"ឈ្មោះអ្នកនិពន្ធ","githubUsername":"ឈ្មោះអ្នកប្រើ GitHub","twitterUsername":"ឈ្មោះអ្នកប្រើ Twitter","libraryName":"ឈ្មោះបណ្ណាល័យ","libraryDesc":"ការពិពណ៌នាអំពីបណ្ណាល័យ","website":"គេហទំព័រ","placeholder":{"authorName":"ឈ្មោះរបស់អ្នក ឬឈ្មោះអ្នកប្រើប្រាស់","libraryName":"ឈ្មោះបណ្ណាល័យរបស់អ្នក","libraryDesc":"ការពិពណ៌នាអំពីបណ្ណាល័យរបស់អ្នក នឹងអនុញ្ញាតឱ្យអ្នកផ្សេងយល់ពីការប្រើប្រាស់របស់វា។","githubHandle":"ឈ្មោះអ្នកប្រើ GitHub (ជាជម្រើស) ដូច្នេះអ្នកអាចកែសម្រួលបណ្ណាល័យបាននៅពេលដាក់ស្នើសម្រាប់ការពិនិត្យ","twitterHandle":"ឈ្មោះអ្នកប្រើប្រាស់ Twitter (ជាជម្រើស) ដូច្នេះយើងដឹងថាអ្នកណាដែលត្រូវផ្តល់ក្រេឌីតនៅពេលផ្សព្វផ្សាយតាម Twitter","website":"ភ្ជាប់ទៅគេហទំព័រផ្ទាល់ខ្លួនរបស់អ្នក ឬគេហទំព័រផ្សេងទៀត (ជាជម្រើស)"},"errors":{"required":"ត្រូវបានទាមទារ","website":"សូមវាយបញ្ចូល URL ដែលត្រឹមត្រូវ"},"noteDescription":"ដាក់ស្នើបណ្ណាល័យរបស់អ្នកដើម្បីដាក់បញ្ចូលក្នុង ឃ្លាំងបណ្ណាល័យសាធារណៈ សម្រាប់ឲ្យអ្នកផ្សេងប្រើក្នុងគំនូររបស់ពួកគេ។","noteGuidelines":"បណ្ណាល័យត្រូវតែអនុម័តដោយដៃជាមុនសិន។ សូមអាន ការណែនាំ មុនពេលដាក់ស្នើ។ ការប្រាស្រ័យទាក់ទងជាបន្តបន្ទាប់ និងការផ្លាស់ប្តូរបណ្ណាល័យទាមទារឱ្យអ្នកមានគណនី GitHub ប៉ុន្តែមិនត្រូវបានទាមទារយ៉ាងតឹងរ៉ឹងទេ។","noteLicense":"តាមរយៈការដាក់ស្នើ អ្នកយល់ព្រមថាបណ្ណាល័យនឹងត្រូវបានបោះពុម្ពផ្សាយក្រោម អាជ្ញាប័ណ្ណ MIT ដែលមានន័យយ៉ាងខ្លី អ្នកណាក៏អាចប្រើប្រាស់វាបានដោយគ្មានការរឹតត្បិត។","noteItems":"ធាតុនីមួយៗនៅក្នុងបណ្ណាល័យត្រូវតែមានឈ្មោះផ្ទាល់ខ្លួនដើម្បីយើងអាចត្រងវាបាន។ ធាតុខាងក្រោមនឹងត្រូវបានរួមបញ្ចូល:","atleastOneLibItem":"សូមជ្រើសរើសយ៉ាងហោចណាស់ធាតុបណ្ណាល័យមួយដើម្បីចាប់ផ្តើម","republishWarning":"ចំណាំ៖ ធាតុដែលត្រូវបានជ្រើសរើសមួយចំនួនត្រូវបានសម្គាល់ថាបានបោះពុម្ព/បញ្ជូនរួចរាល់ហើយ។ អ្នកគួរតែបញ្ជូនធាតុឡើងវិញនៅពេលដែលធ្វើបច្ចុប្បន្នភាពបណ្ណាល័យដែលមានស្រាប់ ឬការបញ្ជូន។"},"publishSuccessDialog":{"title":"បណ្ណាល័យត្រូវបានដាក់ស្នើ","content":"សូមអរគុណ {{authorName}}។ បណ្ណាល័យរបស់អ្នកត្រូវបានបញ្ជូនមកពិនិត្យ។ សូមចុច ទីនេះ ដើម្បីតាមដានស្ថានភាពនៃការដាក់ស្នើនេះ។"},"confirmDialog":{"resetLibrary":"កំណត់បណ្ណាល័យឡើងវិញ","removeItemsFromLib":"លុបធាតុដែលបានជ្រើសរើសចេញពីបណ្ណាល័យ"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"គំនូររបស់អ្នកត្រូវបានអ៊ិនគ្រីបពីចុងដល់ចប់ ដូច្នេះម៉ាស៊ីនមេរបស់ Excalidraw នឹងមិនឃើញពួកវាទេ។","link":"ប្លក់ផុសលើការអ៊ិនគ្រីបពីចុងដល់ចុងក្នុង Excalidraw"},"stats":{"angle":"មុំ","element":"ធាតុ","elements":"ធាតុច្រើន","height":"កម្ពស់","scene":"ស៊ីន","selected":"បានជ្រើសរើស","storage":"ការផ្ទុក","title":"ស្ថិតិសម្រាប់ nerds","total":"សរុប","version":"ជំនាន់:","versionCopy":"ចុចដើម្បីចម្លង","versionNotAvailable":"កំណែមិនអាចប្រើបាន","width":"ទទឹង"},"toast":{"addedToLibrary":"បានបន្ថែមទៅបណ្ណាល័យ","copyStyles":"រចនាប័ទ្មត្រូវបានចម្លង។","copyToClipboard":"បានចម្លងទៅក្ដារតម្បៀតខ្ទាស់។","copyToClipboardAsPng":"បានចម្លង {{exportSelection}} ទៅក្ដារតម្បៀតខ្ទាស់ជា PNG\\n({{exportColorScheme}})","fileSaved":"ឯកសារត្រូវបានរក្សាទុក។","fileSavedToFilename":"បានរក្សាទុកនៅក្នុង {filename}","canvas":"តំបន់គំនូរ","selection":"ការជ្រើសរើស","pasteAsSingleElement":"ប្រើ {{shortcut}} ដើម្បីបិទភ្ជាប់ជាធាតុតែមួយ,\\nឬបិទភ្ជាប់ទៅក្នុងកម្មវិធីនិពន្ធអត្ថបទដែលមានស្រាប់","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"ថ្លាមើលធ្លុះ","black":"ពណ៍ខ្មៅ","white":"ពណ៌ស","red":"ពណ៌ក្រហម","pink":"ពណ៌ផ្កាឈូក","grape":"ពណ៌ទំពាំងបាយជូរ","violet":"ពណ៌ស្វាយ","gray":"ពណ៌ប្រផេះ","blue":"ពណ៌ខៀវ","cyan":"ពណ៌ផ្ទៃមេឃ","teal":"ពណ៌ខៀវបៃតង","green":"ពណ៌បៃតង","yellow":"ពណ៌លឿង","orange":"ពណ៌ទឹកក្រូច","bronze":"ពណ៌សំរិទ្ធ"},"welcomeScreen":{"app":{"center_heading":"ទិន្នន័យទាំងអស់របស់អ្នក ត្រូវបានរក្សាទុកនៅក្នុង browser របស់អ្នក ។","center_heading_plus":"តើអ្នកចង់ទៅ Excalidraw+ វិញ ឬ មែន?","menuHint":"នាំចេញ ចំណូលចិត្ត ភាសា ..."},"defaults":{"menuHint":"ការនាំចេញ ចំណូលចិត្ត និង ច្រើនទៀត...","center_heading":"ងាយស្រួល ។ ធ្វើ ។ ដ្យាក្រាម ។","toolbarHint":"ជ្រើសរើសឧបករណ៍មួយ និង ចាប់ផ្តើមគូរ!","helpHint":"ផ្លូវកាត់ & ជំនួយ"}},"colorPicker":{"mostUsedCustomColors":"ពណ៌ផ្ទាល់ខ្លួនដែលប្រើច្រើនបំផុត","colors":"ពណ៌","shades":"ស្រមោល","hexCode":"លេខកូដ hex","noShades":"មិនមានស្រមោលសម្រាប់ពណ៌នេះទេ"},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/ko-KR-json-ad8e9d31d52b26f3fbc2.js b/public/excalidraw/excalidraw-assets-dev/locales/ko-KR-json-ad8e9d31d52b26f3fbc2.js
new file mode 100644
index 0000000..af37a33
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/ko-KR-json-ad8e9d31d52b26f3fbc2.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/ko-KR-json"],{
+
+/***/ "../../locales/ko-KR.json":
+/*!********************************!*\
+ !*** ../../locales/ko-KR.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"붙여넣기","pasteAsPlaintext":"일반 텍스트로 붙여넣기","pasteCharts":"차트 붙여넣기","selectAll":"전체 선택","multiSelect":"선택 영역에 추가하기","moveCanvas":"캔버스 이동","cut":"잘라내기","copy":"복사","copyAsPng":"클립보드로 PNG 이미지 복사","copyAsSvg":"클립보드로 SVG 이미지 복사","copyText":"클립보드로 텍스트 복사","bringForward":"앞으로 가져오기","sendToBack":"맨 뒤로 보내기","bringToFront":"맨 앞으로 가져오기","sendBackward":"뒤로 보내기","delete":"삭제","copyStyles":"스타일 복사하기","pasteStyles":"스타일 붙여넣기","stroke":"선 색상","background":"배경색","fill":"채우기","strokeWidth":"선 굵기","strokeStyle":"선","strokeStyle_solid":"실선","strokeStyle_dashed":"파선","strokeStyle_dotted":"점선","sloppiness":"대충 긋기","opacity":"불투명도","textAlign":"텍스트 정렬","edges":"가장자리","sharp":"뾰족하게","round":"둥글게","arrowheads":"화살촉","arrowhead_none":"없음","arrowhead_arrow":"화살표","arrowhead_bar":"막대","arrowhead_dot":"점","arrowhead_triangle":"삼각형","fontSize":"글자 크기","fontFamily":"글꼴","addWatermark":"\\"Made with Excalidraw\\" 추가","handDrawn":"손글씨","normal":"일반","code":"코드","small":"작게","medium":"보통","large":"크게","veryLarge":"매우 크게","solid":"단색","hachure":"평행선","zigzag":"지그재그","crossHatch":"교차선","thin":"얇게","bold":"굵게","left":"왼쪽","center":"가운데","right":"오른쪽","extraBold":"매우 굵게","architect":"건축가","artist":"예술가","cartoonist":"만화가","fileTitle":"파일 이름","colorPicker":"색상 선택기","canvasColors":"캔버스에서 사용되었음","canvasBackground":"캔버스 배경","drawingCanvas":"캔버스 그리기","layers":"레이어","actions":"동작","language":"언어","liveCollaboration":"실시간 협업...","duplicateSelection":"복제","untitled":"제목 없음","name":"이름","yourName":"이름 입력","madeWithExcalidraw":"Made with Excalidraw","group":"그룹 생성","ungroup":"그룹 해제","collaborators":"공동 작업자","showGrid":"그리드 보기","addToLibrary":"라이브러리에 추가","removeFromLibrary":"라이브러리에서 제거","libraryLoadingMessage":"라이브러리 불러오는 중…","libraries":"라이브러리 찾기","loadingScene":"화면 불러오는 중…","align":"정렬","alignTop":"상단 정렬","alignBottom":"하단 정렬","alignLeft":"왼쪽 정렬","alignRight":"오른쪽 정렬","centerVertically":"수직으로 중앙 정렬","centerHorizontally":"수평으로 중앙 정렬","distributeHorizontally":"수평으로 분배","distributeVertically":"수직으로 분배","flipHorizontal":"좌우반전","flipVertical":"상하반전","viewMode":"보기 모드","share":"공유","showStroke":"윤곽선 색상 선택기 열기","showBackground":"배경 색상 선택기 열기","toggleTheme":"테마 전환","personalLib":"개인 라이브러리","excalidrawLib":"Excalidraw 라이브러리","decreaseFontSize":"폰트 사이즈 줄이기","increaseFontSize":"폰트 사이즈 키우기","unbindText":"텍스트 분리","bindText":"텍스트를 컨테이너에 결합","createContainerFromText":"텍스트를 컨테이너에 담기","link":{"edit":"링크 수정하기","editEmbed":"링크 & 임베드 수정하기","create":"링크 만들기","createEmbed":"링크 & 임베드 만들기","label":"링크","labelEmbed":"링크 & 임베드","empty":"링크를 지정하지 않았습니다"},"lineEditor":{"edit":"선 수정하기","exit":"선 편집기 종료"},"elementLock":{"lock":"잠금","unlock":"잠금 해제","lockAll":"모두 잠금","unlockAll":"모두 잠금 해제"},"statusPublished":"게시됨","sidebarLock":"사이드바 유지","selectAllElementsInFrame":"프레임의 모든 요소 선택","removeAllElementsFromFrame":"프레임의 모든 요소 삭제","eyeDropper":"캔버스에서 색상 고르기"},"library":{"noItems":"추가된 아이템 없음","hint_emptyLibrary":"캔버스 위에서 아이템을 선택하여 여기에 추가를 하거나, 아래의 공용 저장소에서 라이브러리를 설치하세요.","hint_emptyPrivateLibrary":"캔버스 위에서 아이템을 선택하여 여기 추가하세요."},"buttons":{"clearReset":"캔버스 초기화","exportJSON":"파일로 내보내기","exportImage":"이미지 내보내기","export":"다른 이름으로 저장...","copyToClipboard":"클립보드로 복사","save":"현재 파일에 저장","saveAs":"다른 이름으로 저장","load":"열기","getShareableLink":"공유 가능한 링크 생성","close":"닫기","selectLanguage":"언어 선택","scrollBackToContent":"콘텐츠 영역으로 스크롤하기","zoomIn":"확대","zoomOut":"축소","resetZoom":"확대/축소 초기화","menu":"메뉴","done":"완료","edit":"수정","undo":"실행 취소","redo":"다시 실행","resetLibrary":"라이브러리 리셋","createNewRoom":"방 만들기","fullScreen":"전체화면","darkMode":"다크 모드","lightMode":"밝은 모드","zenMode":"젠 모드","objectsSnapMode":"다른 요소들에 정렬시키기","exitZenMode":"젠 모드 종료하기","cancel":"취소","clear":"지우기","remove":"삭제","embed":"임베딩 토글","publishLibrary":"게시하기","submit":"제출","confirm":"확인","embeddableInteractionButton":"클릭하여 상호작용"},"alerts":{"clearReset":"모든 작업 내용이 초기화됩니다. 계속하시겠습니까?","couldNotCreateShareableLink":"공유 가능한 링크를 생성할 수 없습니다.","couldNotCreateShareableLinkTooBig":"공유 가능한 링크를 생성할 수 없습니다: 화면이 너무 큽니다.","couldNotLoadInvalidFile":"유효하지 않은 파일입니다.","importBackendFailed":"서버로부터 불러 오지 못했습니다.","cannotExportEmptyCanvas":"빈 캔버스를 내보낼 수 없습니다.","couldNotCopyToClipboard":"클립보드로 복사하지 못했습니다.","decryptFailed":"데이터를 복호화하지 못했습니다.","uploadedSecurly":"업로드는 종단 간 암호화로 보호되므로 Excalidraw 서버 및 타사가 콘텐츠를 읽을 수 없습니다.","loadSceneOverridePrompt":"외부 파일을 불러 오면 기존 콘텐츠가 대체됩니다. 계속 진행할까요?","collabStopOverridePrompt":"협업 세션을 종료하면 로컬 저장소에 있는 그림이 협업 세션의 그림으로 대체됩니다. 진행하겠습니까?\\n\\n(로컬 저장소에 있는 그림을 유지하려면 현재 브라우저 탭을 닫아주세요.)","errorAddingToLibrary":"아이템을 라이브러리에 추가 할수 없습니다","errorRemovingFromLibrary":"라이브러리에서 아이템을 삭제할수 없습니다","confirmAddLibrary":"{{numShapes}}개의 모양이 라이브러리에 추가됩니다. 계속하시겠어요?","imageDoesNotContainScene":"이 이미지는 화면 데이터를 포함하고 있지 않은 것 같습니다. 내보낼 때 화면을 첨부하도록 설정하셨나요?","cannotRestoreFromImage":"이미지 파일에서 화면을 복구할 수 없었습니다","invalidSceneUrl":"제공된 URL에서 화면을 가져오는데 실패했습니다. 주소가 잘못되거나, 유효한 Excalidraw JSON 데이터를 포함하고 있지 않은 것일 수 있습니다.","resetLibrary":"당신의 라이브러리를 초기화 합니다. 계속하시겠습니까?","removeItemsFromsLibrary":"{{count}}개의 아이템을 라이브러리에서 삭제하시겠습니까?","invalidEncryptionKey":"암호화 키는 반드시 22글자여야 합니다. 실시간 협업이 비활성화됩니다.","collabOfflineWarning":"인터넷에 연결되어 있지 않습니다.\\n변경 사항들이 저장되지 않습니다!"},"errors":{"unsupportedFileType":"지원하지 않는 파일 형식 입니다.","imageInsertError":"이미지를 삽입할 수 없습니다. 나중에 다시 시도 하십시오","fileTooBig":"파일이 너무 큽니다. 최대 크기는 {{maxSize}} 입니다.","svgImageInsertError":"SVG 이미지를 삽입하지 못했습니다. SVG 문법이 유효하지 않은 것 같습니다.","failedToFetchImage":"이미지를 가져오는데 실패했습니다.","invalidSVGString":"유효하지 않은 SVG입니다.","cannotResolveCollabServer":"협업 서버에 접속하는데 실패했습니다. 페이지를 새로고침하고 다시 시도해보세요.","importLibraryError":"라이브러리를 불러오지 못했습니다.","collabSaveFailed":"데이터베이스에 저장하지 못했습니다. 문제가 계속 된다면, 작업 내용을 잃지 않도록 로컬 저장소에 저장해 주세요.","collabSaveFailed_sizeExceeded":"데이터베이스에 저장하지 못했습니다. 캔버스가 너무 큰 거 같습니다. 문제가 계속 된다면, 작업 내용을 잃지 않도록 로컬 저장소에 저장해 주세요.","brave_measure_text_error":{"line1":"귀하께서는 강력한 지문 차단 설정이 활성화된 Brave browser를 사용하고 계신 것 같습니다.","line2":"이 기능으로 인해 화이트보드의 텍스트 요소들이 손상될 수 있습니다.","line3":"저희는 해당 기능을 비활성화하는 것을 강력히 권장 드립니다. 비활성화 방법에 대해서는 이 게시글을 참고해주세요.","line4":"만약 이 설정을 껐음에도 텍스트 요소들이 올바르게 표시되지 않는다면, 저희 Github에 이슈를 올려주시거나 Discord로 알려주세요."},"libraryElementTypeError":{"embeddable":"임베드 요소들은 라이브러리에 추가할 수 없습니다.","image":"라이브러리에 이미지 삽입 기능은 곧 지원될 예정입니다!"}},"toolBar":{"selection":"선택","image":"이미지 삽입","rectangle":"사각형","diamond":"다이아몬드","ellipse":"타원","arrow":"화살표","line":"선","freedraw":"그리기","text":"텍스트","library":"라이브러리","lock":"선택된 도구 유지하기","penMode":"펜 모드 - 터치 방지","link":"선택한 도형에 대해서 링크를 추가/업데이트","eraser":"지우개","frame":"프레임 도구","embeddable":"웹 임베드","laser":"레이저 포인터","hand":"손 (패닝 도구)","extraTools":"다른 도구"},"headings":{"canvasActions":"캔버스 동작","selectedShapeActions":"선택된 모양 동작","shapes":"모양"},"hints":{"canvasPanning":"캔버스를 옮기려면 마우스 휠이나 스페이스바를 누르고 드래그하거나, 손 도구를 사용하기","linearElement":"여러 점을 연결하려면 클릭하고, 직선을 그리려면 바로 드래그하세요.","freeDraw":"클릭 후 드래그하세요. 완료되면 놓으세요.","text":"팁: 선택 툴로 아무 곳이나 더블 클릭해 텍스트를 추가할 수도 있습니다.","embeddable":"클릭 및 드래그하여 웹사이트 임베드 만들기","text_selected":"더블 클릭 또는 ENTER를 눌러서 텍스트 수정","text_editing":"ESC나 CtrlOrCmd+ENTER를 눌러서 수정을 종료하기","linearElementMulti":"마지막 지점을 클릭하거나 Esc 또는 Enter 키를 눌러 완료하세요.","lockAngle":"SHIFT 키를 누르면서 회전하면 각도를 제한할 수 있습니다.","resize":"SHIFT 키를 누르면서 조정하면 크기의 비율이 제한됩니다.\\nALT를 누르면서 조정하면 중앙을 기준으로 크기를 조정합니다.","resizeImage":"SHIFT를 눌러서 자유롭게 크기를 변경하거나,\\nALT를 눌러서 중앙을 고정하고 크기를 변경하기","rotate":"SHIFT 키를 누르면서 회전하면 각도를 제한할 수 있습니다.","lineEditor_info":"꼭짓점을 수정하려면 CtrlOrCmd 키를 누르고 더블 클릭을 하거나 CtrlOrCmd + Enter를 누르세요.","lineEditor_pointSelected":"Delete 키로 꼭짓점을 제거하거나,\\nCtrlOrCmd+D 로 복제하거나, 드래그 해서 이동시키기","lineEditor_nothingSelected":"꼭짓점을 선택해서 수정하거나 (SHIFT를 눌러서 여러개 선택),\\nAlt를 누르고 클릭해서 새로운 꼭짓점 추가하기","placeImage":"클릭해서 이미지를 배치하거나, 클릭하고 드래그해서 사이즈를 조정하기","publishLibrary":"당신만의 라이브러리를 게시하기","bindTextToElement":"Enter 키를 눌러서 텍스트 추가하기","deepBoxSelect":"CtrlOrCmd 키를 눌러서 깊게 선택하고, 드래그하지 않도록 하기","eraserRevert":"Alt를 눌러서 삭제하도록 지정된 요소를 되돌리기","firefox_clipboard_write":"이 기능은 설정에서 \\"dom.events.asyncClipboard.clipboardItem\\" 플래그를 \\"true\\"로 설정하여 활성화할 수 있습니다. Firefox에서 브라우저 플래그를 수정하려면, \\"about:config\\" 페이지에 접속하세요.","disableSnapping":"CtrlOrCmd 키를 눌러서 다른 요소와의 정렬 무시하기"},"canvasError":{"cannotShowPreview":"미리보기를 볼 수 없습니다","canvasTooBig":"캔버스가 너무 큽니다.","canvasTooBigTip":"팁: 멀리 있는 요소들을 좀 더 가까이로 붙여 보세요."},"errorSplash":{"headingMain":"오류가 발생했습니다. ","clearCanvasMessage":"새로고침으로 해결되지 않을 경우, ","clearCanvasCaveat":" 작업 내용을 잃게 됩니다 ","trackedToSentry":"오류 {{eventId}} 가 시스템에서 발견되었습니다.","openIssueMessage":"저희는 화면 정보를 오류에 포함하지 않도록 매우 주의하고 있습니다. 혹시 화면에 민감한 내용이 없다면 이곳에 업로드를 고려해주세요. 아래 정보를 GitHub 이슈에 복사 및 붙여넣기해 주세요.","sceneContent":"화면 내용:"},"roomDialog":{"desc_intro":"현재 화면에 공동 작업자를 초대해 협업할 수 있습니다.","desc_privacy":"안심하세요, 세션은 종단 간 암호화를 사용하므로 당신의 작업은 비공개로 유지되며 서버조차도 작업 내용을 알 수 없습니다.","button_startSession":"세션 시작","button_stopSession":"세션 중단","desc_inProgressIntro":"실시간 협업 세션이 진행 중입니다.","desc_shareLink":"공동 작업자에게 이 링크를 공유하세요.","desc_exitSession":"세션을 중단하면 연결은 끊어지나 작업을 이어갈 수 있습니다. 이 작업은 다른 작업자에게 영향을 미치지 않으며 각자의 공동 작업은 계속 유지됩니다.","shareTitle":"Excalidraw의 실시간 협업 세션에 참가하기"},"errorDialog":{"title":"오류"},"exportDialog":{"disk_title":"디스크에 저장","disk_details":"나중에 다시 불러올 수 있도록 화면 데이터를 내보냅니다.","disk_button":"파일로 저장","link_title":"공유 가능한 링크 생성","link_details":"읽기 전용 링크로 내보냅니다.","link_button":"링크로 내보내기","excalidrawplus_description":"화면을 당신의 Excalidraw+ 작업 공간으로 저장합니다.","excalidrawplus_button":"내보내기","excalidrawplus_exportError":"지금은 Excalidraw+로 내보낼 수 없습니다..."},"helpDialog":{"blog":"블로그 읽어보기","click":"클릭","deepSelect":"깊게 선택","deepBoxSelect":"영역을 깊게 선택하고, 드래그하지 않도록 하기","curvedArrow":"곡선 화살표","curvedLine":"곡선","documentation":"설명서","doubleClick":"더블 클릭","drag":"드래그","editor":"에디터","editLineArrowPoints":"직선 / 화살표 꼭짓점 수정","editText":"텍스트 수정 / 라벨 추가","github":"문제 제보하기","howto":"가이드 참고하기","or":"또는","preventBinding":"화살표가 붙지 않게 하기","tools":"도구","shortcuts":"키보드 단축키","textFinish":"편집 완료 (텍스트 에디터)","textNewLine":"줄바꿈(텍스트 에디터)","title":"도움말","view":"보기","zoomToFit":"모든 요소가 보이도록 확대/축소","zoomToSelection":"선택 영역으로 확대/축소","toggleElementLock":"선택한 항목을 잠금/잠금 해제","movePageUpDown":"페이지 움직이기 위/아래","movePageLeftRight":"페이지 움직이기 좌/우"},"clearCanvasDialog":{"title":"캔버스 지우기"},"publishDialog":{"title":"라이브러리 게시하기","itemName":"아이템 이름","authorName":"저자명","githubUsername":"깃허브 사용자이름","twitterUsername":"트위터 사용자이름","libraryName":"라이브러리 이름","libraryDesc":"라이브러리 설명","website":"웹사이트","placeholder":{"authorName":"이름 또는 사용자명","libraryName":"당신의 라이브러리 이름","libraryDesc":"사람들에게 라이브러리의 용도를 알기 쉽게 설명해주세요","githubHandle":"GitHub 사용자명 (선택), 제출한 뒤에도 심사를 위해서 라이브러리를 수정할 때 사용됩니다","twitterHandle":"Twitter 사용자명 (선택), Twitter를 통해서 홍보할 때 제작자를 밝히기 위해 사용됩니다","website":"개인 웹사이트나 다른 어딘가의 링크 (선택)"},"errors":{"required":"필수사항","website":"유효한 URL을 입력하세요"},"noteDescription":"당신의 라이브러리를 제출하여 공개 라이브러리 저장소에서 다른 사람들의 그림에 사용할 수 있도록 하세요.","noteGuidelines":"라이브러리는 먼저 수동으로 승인되어야 합니다. 제출하기 전에 가이드라인을 먼저 읽어보세요. 의견을 공유하거나 변경사항을 만들기 위해선 GitHub 계정이 필요하지만, 반드시 필요하진 않습니다.","noteLicense":"제출함으로써, 당신은 라이브러리가 MIT 라이선스 하에 배포됨을, 즉 아무나 제약 없이 사용할 수 있음에 동의합니다.","noteItems":"각각의 라이브러리는 분류할 수 있도록 고유한 이름을 가져야 합니다. 다음의 라이브러리 항목이 포함됩니다:","atleastOneLibItem":"최소한 하나의 라이브러리를 선택해주세요","republishWarning":"참고: 선택된 항목의 일부는 이미 제출/게시되었습니다. 기존의 라이브러리나 제출물을 업데이트하는 경우에만 제출하세요."},"publishSuccessDialog":{"title":"라이브러리 제출됨","content":"{{authorName}}님 감사합니다. 당신의 라이브러리가 심사를 위해 제출되었습니다. 진행 상황을여기에서 확인하실 수 있습니다."},"confirmDialog":{"resetLibrary":"라이브러리 리셋","removeItemsFromLib":"선택한 항목을 라이브러리에서 제거"},"imageExportDialog":{"header":"이미지 내보내기","label":{"withBackground":"배경","onlySelected":"선택한 항목만","darkMode":"다크 모드","embedScene":"화면을 담기","scale":"크기","padding":"여백"},"tooltip":{"embedScene":"화면 정보가 내보내는 PNG/SVG 파일에 저장되어 이후에 파일에서 화면을 복구할 수 있습니다. 파일 크기가 증가합니다."},"title":{"exportToPng":"PNG로 내보내기","exportToSvg":"SVG로 내보내기","copyPngToClipboard":"클립보드로 PNG 복사"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"클립보드로 복사"}},"encrypted":{"tooltip":"그림은 종단 간 암호화되므로 Excalidraw의 서버는 절대로 내용을 알 수 없습니다.","link":"Excalidraw의 종단 간 암호화에 대한 블로그 포스트"},"stats":{"angle":"각도","element":"요소","elements":"요소","height":"높이","scene":"화면","selected":"선택됨","storage":"저장공간","title":"덕후들을 위한 통계","total":"합계","version":"버전","versionCopy":"복사하려면 클릭","versionNotAvailable":"해당 버전 사용 불가능","width":"너비"},"toast":{"addedToLibrary":"라이브러리에 추가되었습니다","copyStyles":"스타일 복사.","copyToClipboard":"클립보드로 복사.","copyToClipboardAsPng":"{{exportSelection}}를 클립보드에 PNG로 복사했습니다\\n({{exportColorScheme}})","fileSaved":"파일이 저장되었습니다.","fileSavedToFilename":"{filename} 로 저장되었습니다","canvas":"캔버스","selection":"선택한 요소","pasteAsSingleElement":"단일 요소로 붙여넣거나, 기존 텍스트 에디터에 붙여넣으려면 {{shortcut}} 을 사용하세요.","unableToEmbed":"이 URL의 임베딩이 허용되지 않았습니다. GitHub에 이슈를 남겨서 이 URL이 화이트리스트에 등재될 수 있도록 요청하세요","unrecognizedLinkFormat":"임베딩하려는 링크의 형식이 잘못된 것 같습니다. 원본 사이트에서 제공하는 \\"임베딩\\" 텍스트를 그대로 붙여 넣어 주세요"},"colors":{"transparent":"투명","black":"블랙","white":"화이트","red":"레드","pink":"핑크","grape":"그레이프","violet":"바이올렛","gray":"그레이","blue":"블루","cyan":"시안","teal":"틸","green":"그린","yellow":"옐로우","orange":"오렌지","bronze":"브론즈"},"welcomeScreen":{"app":{"center_heading":"모든 데이터는 브라우저에 안전하게 저장됩니다.","center_heading_plus":"대신 Excalidraw+로 이동하시겠습니까?","menuHint":"내보내기, 설정, 언어, ..."},"defaults":{"menuHint":"내보내기, 설정, 등등...","center_heading":"간단하게 만드는 다이어그램.","toolbarHint":"도구를 선택하고, 그리세요!","helpHint":"단축키 & 도움말"}},"colorPicker":{"mostUsedCustomColors":"가장 많이 사용된 색상들","colors":"색상","shades":"색조","hexCode":"Hex 코드","noShades":"사용할 수 있는 색조가 없음"},"overwriteConfirm":{"action":{"exportToImage":{"title":"이미지로 내보내기","button":"이미지로 내보내기","description":"나중에 다시 불러올 수 있도록 화면 데이터를 이미지로 내보냅니다."},"saveToDisk":{"title":"디스크에 저장","button":"디스크에 저장","description":"나중에 다시 불러올 수 있도록 화면 데이터를 내보냅니다."},"excalidrawPlus":{"title":"Excalidraw+","button":"Excalidraw+로 내보내기","description":"화면을 당신의 Excalidraw+ 작업 공간으로 저장합니다."}},"modal":{"loadFromFile":{"title":"파일에서 불러오기","button":"파일에서 불러오기","description":"파일을 불러오면 현재 작성된 데이터를 덮어쓰게 됩니다. 다음 옵션 중 하나를 선택하여 작업물을 백업해 둘 수 있습니다."},"shareableLink":{"title":"주소에서 불러오기","button":"컨텐츠를 덮어쓰기","description":"외부 작업물을 불러오면 현재 작성된 데이터를 덮어쓰게 됩니다. 다음 옵션 중 하나를 선택하여 작업물을 백업해 둘 수 있습니다."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/ku-TR-json-ed67af91ae1920f114a8.js b/public/excalidraw/excalidraw-assets-dev/locales/ku-TR-json-ed67af91ae1920f114a8.js
new file mode 100644
index 0000000..9e207b0
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/ku-TR-json-ed67af91ae1920f114a8.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/ku-TR-json"],{
+
+/***/ "../../locales/ku-TR.json":
+/*!********************************!*\
+ !*** ../../locales/ku-TR.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"دانانەوە","pasteAsPlaintext":"دایبنێ وەک دەقی سادە","pasteCharts":"دانانەوەی خشتەکان","selectAll":"دیاریکردنی هەموو","multiSelect":"زیادکردنی بۆ دیاریکراوەکان","moveCanvas":"تابلۆ بجوڵێنە","cut":"بڕین","copy":"لەبەرگرتنەوە","copyAsPng":"PNGلەبەرگرتنەوە بۆ تەختەنووس وەک","copyAsSvg":"SVGلەبەرگرتنەوە بۆ تەختەنووس وەک","copyText":"لەبەرگرتنەوە بۆ تەختەنووس وەک نوسین","bringForward":"بهێنە پێشتر","sendToBack":"بنێرە دواوە","bringToFront":"بهێنە پێشەوە","sendBackward":"بنێرە دواتر","delete":"سڕینەوە","copyStyles":"لەبەرگرتنەوەی ستایل","pasteStyles":"دانانەوەی ستایل","stroke":"هێڵکار","background":"پاشبنەما","fill":"پڕکردنەوە","strokeWidth":"پانی هێڵکاری","strokeStyle":"ستایلی هێڵکاری","strokeStyle_solid":"سادە","strokeStyle_dashed":"پچڕ پچڕ","strokeStyle_dotted":"خاڵدار","sloppiness":"لێژی","opacity":"ڕوونی","textAlign":"ڕێکخستنی دەق","edges":"لێوارەکان","sharp":"تیژ","round":"چەماوە","arrowheads":"سەرەتیر","arrowhead_none":"هیچیان","arrowhead_arrow":"تیر","arrowhead_bar":"هێڵ","arrowhead_dot":"خاڵ","arrowhead_triangle":"سێگۆشە","fontSize":"قەبارەی فۆنت","fontFamily":"خێزانی فۆنت","addWatermark":"زیادبکە \\"Made with Excalidraw\\"","handDrawn":"دەست کێشراو","normal":"ئاسایی","code":"کۆد","small":"بچووک","medium":"ناوەند","large":"گهوره","veryLarge":"زۆر گهوره","solid":"سادە","hachure":"هاچور","zigzag":"زیگزاگ","crossHatch":"کرۆس هاتچ","thin":"تەنک","bold":"تۆخ","left":"چەپ","center":"ناوهند","right":"ڕاست","extraBold":"زۆر تۆخ","architect":"تەلارساز","artist":"هونەرمەند","cartoonist":"کارتۆنی","fileTitle":"ناوی فایل","colorPicker":"ڕەنگ هەڵگر","canvasColors":"بەکارهاتووە لەسەر تابلۆ","canvasBackground":"پاشبنەمای تابلۆ","drawingCanvas":"کێشانی تابلۆ","layers":"چینەکان","actions":"کردارەکان","language":"زمان","liveCollaboration":"هاوکاریکردنی زیندو...","duplicateSelection":"لەبەرگرتنەوە","untitled":"بێ ناونیشان","name":"ناو","yourName":"ناوەکەت","madeWithExcalidraw":"دروستکراوە بە Excalidraw","group":"دیاریکردنی گروپ","ungroup":"گروپی دیاریکراوەکان لابەرە","collaborators":"هاوکارەکان","showGrid":"گرید نیشانبدە","addToLibrary":"زیادکردن بۆ کتێبخانە","removeFromLibrary":"لابردن لە کتێبخانە","libraryLoadingMessage":"...بارکردنی کتێبخانە","libraries":"گەڕانی کتێبخانە","loadingScene":"...بارکردنی دیمەنەکە","align":"لاچەنکردن","alignTop":"لاچەنکردن بۆ سەرەوە","alignBottom":"لاچەنکردن بۆ خوارەوە","alignLeft":"لاچەنکردن بۆ چەپ","alignRight":"لاچەنکردن بۆ ڕاست","centerVertically":"بە ستونی ناوەند بکە","centerHorizontally":"بە ئاسۆی ناوەند بکە","distributeHorizontally":"بە ئاسۆی دابەشی بکە","distributeVertically":"بە ستونی دابەشی بکە","flipHorizontal":"هەڵگەڕانەوەی ئاسۆیی","flipVertical":"هەڵگەڕانەوەی ستونی","viewMode":"دۆخی بینین","share":"هاوبەشی پێکردن","showStroke":"ڕەنگهەڵگری هێڵکار نیشانبدە","showBackground":"ڕەنگهەڵگری باکگراوند نیشانبدە","toggleTheme":"دۆخی ڕوکار بگۆڕە","personalLib":"کتێبخانەی کەسی","excalidrawLib":"کتێبخانەی Excalidraw","decreaseFontSize":"کەمکردنەوەی قەبارەی فۆنت","increaseFontSize":"زایدکردنی قەبارەی فۆنت","unbindText":"دەقەکە جیابکەرەوە","bindText":"دەقەکە ببەستەوە بە کۆنتەینەرەکەوە","createContainerFromText":"دەق لە چوارچێوەیەکدا بپێچە","link":{"edit":"دەستکاریکردنی بەستەر","editEmbed":"","create":"دروستکردنی بەستەر","createEmbed":"","label":"بەستەر","labelEmbed":"","empty":""},"lineEditor":{"edit":"دەستکاری کردنی دێڕ","exit":"دەرچوون لە دەستکاریکەری دێڕ"},"elementLock":{"lock":"قفڵکردن","unlock":"کردنەوە","lockAll":"قفڵکردنی هەموو","unlockAll":"کردنەوەی قفلی هەمووی"},"statusPublished":"بڵاوکراوەتەوە","sidebarLock":"هێشتنەوەی شریتی لا بە کراوەیی","selectAllElementsInFrame":"هەموو توخمەکانی ناو چوارچێوەکە دیاری بکە","removeAllElementsFromFrame":"هەموو توخمەکانی ناو چوارچێوەکە لابەرە","eyeDropper":"ڕەنگێک لەسەر تابلۆکە هەڵبژێرە"},"library":{"noItems":"هێشتا هیچ بڕگەیەک زیاد نەکراوە...","hint_emptyLibrary":"شتێک لەسەر تابلۆ هەڵبژێرە بۆ ئەوەی لێرە زیادی بکەیت، یان کتێبخانەیەک لە کۆگا گشتیەکەوە دابمەزرێنە، لە خوارەوە.","hint_emptyPrivateLibrary":"شتێک لەسەر تابلۆ هەڵبژێرە بۆ ئەوەی لێرە زیادی بکەیت."},"buttons":{"clearReset":"تابلۆکە وەک سەرەتا لێبکەوە","exportJSON":"هەناردەکردن بۆ فایل","exportImage":"وێنە هەناردە بکە...","export":"پاشەکەوت بکە بۆ...","copyToClipboard":"لهبهری بگرهوه بۆ تهختهنووس","save":"پاشەکەوت بکە بۆ فایلی بەردەست","saveAs":"پاشەکەوتکردن وەک","load":"بکەرەوە","getShareableLink":"بەستەری هاوبەشیپێکردن بەدەستبهێنە","close":"داخستن","selectLanguage":"دیاریکردنی زمان","scrollBackToContent":"گەڕاندنەوە بۆ ناوەڕۆک","zoomIn":"نزیک خستنەوە","zoomOut":"دوورخستنەوە","resetZoom":"ڕێستکردنی زووم","menu":"پێڕست","done":"تەواو","edit":"دەستکاری کردن","undo":"گهڕانهوه بۆ پێشوو","redo":"گهڕانهوه بۆ داهاتوو","resetLibrary":"ڕێکخستنەوەی کتێبخانە","createNewRoom":"ژوورێکی نوێ دروست بکە","fullScreen":"پڕ بە شاشە","darkMode":"دۆخی تاریک","lightMode":"دۆخی ڕووناک","zenMode":"دۆخی زێن","objectsSnapMode":"","exitZenMode":"بەجێهێشتنی دۆخی زێن","cancel":"هەڵوەشاندنەوە","clear":"خاوێنکردنەوە","remove":"لابردن","embed":"","publishLibrary":"بڵاوکردنەوە","submit":"پێشکەشکردن","confirm":"دوپاتکردنەوە","embeddableInteractionButton":""},"alerts":{"clearReset":"ئەمە هەموو تابلۆکە خاوێن دەکاتەوە، دڵنیایت؟","couldNotCreateShareableLink":"نەتوانرا بەستەری هاوبەشیپێکردن دروستبکرێت","couldNotCreateShareableLinkTooBig":"نەتوانرا بەستەری هاوبەشیپێکردن دروستبکرێت: دیمەنەکە زۆر گەورەیە","couldNotLoadInvalidFile":"ناتوانرا باربکرێت، فایلەکە دروستنییە","importBackendFailed":"هاوردەکردن لە پاشکۆکە سەرکەوتوو نەبوو.","cannotExportEmptyCanvas":"ناتوانرێت تابلۆی بەتاڵ هەناردەبکرێت.","couldNotCopyToClipboard":"ناتوانرا لەبەربگیرێتەوە بۆ تەختەنوس","decryptFailed":"ناتوانرا داتاکان شیبکرێتەوە","uploadedSecurly":"بارکردنەکە بە کۆدکردنی کۆتایی بۆ کۆتایی پارێزراوە، ئەمەش واتە سێرڤەری Excalidraw و لایەنی سێیەم ناتوانن ناوەڕۆکەکە بخوێننەوە.","loadSceneOverridePrompt":"بارکردنی وێنەکێشانی دەرەکی جێگەی ناوەڕۆکی بەردەستت دەگرێتەوە. دەتەوێت بەردەوام بیت؟","collabStopOverridePrompt":"وەستاندنی دانیشتنەکە وێنەکێشانی پێشووت دەنووسێتەوە کە لە ناوخۆدا هەڵگیراوە. ئایا دڵنیایت?\\n\\n(ئەگەر دەتەوێت وێنەکێشانی ناوخۆیی خۆت بهێڵیتەوە، لەبری ئەوە تەنها تابی وێبگەڕەکە دابخە).","errorAddingToLibrary":"نەیتوانی بڕگە زیاد بکات بۆ کتێبخانە","errorRemovingFromLibrary":"نەیتوانی بڕگە لە کتێبخانە بسڕێتەوە","confirmAddLibrary":"ئەمە {{numShapes}} شێوە(ەکان) زیاد دەکات بۆ کتێبخانەکەت. ئایا دڵنیایت?","imageDoesNotContainScene":"وادیارە ئەم وێنەیە هیچ داتایەکی دیمەنی تێدا نییە. ئایا دیمەنی چەسپاندنت لە کاتی هەناردەدا چالاک کردووە؟","cannotRestoreFromImage":"ناتوانرێت دیمەنەکە بگەڕێندرێتەوە لەم فایلە وێنەیە","invalidSceneUrl":"ناتوانێت دیمەنەکە هاوردە بکات لە URL ی دابینکراو. یان نادروستە، یان داتای \\"ئێکسکالیدراو\\" JSON ی دروستی تێدا نییە.","resetLibrary":"ئەمە کتێبخانەکەت خاوێن دەکاتەوە. ئایا دڵنیایت?","removeItemsFromsLibrary":"سڕینەوەی {{count}} ئایتم(ەکان) لە کتێبخانە؟","invalidEncryptionKey":"کلیلی رەمزاندن دەبێت لە 22 پیت بێت. هاوکاری ڕاستەوخۆ لە کارخراوە.","collabOfflineWarning":"هێڵی ئینتەرنێت بەردەست نییە.\\n گۆڕانکارییەکانت سەیڤ ناکرێن!"},"errors":{"unsupportedFileType":"جۆری فایلی پشتگیری نەکراو.","imageInsertError":"نەیتوانی وێنە داخڵ بکات. دواتر هەوڵ بدە","fileTooBig":"فایلەکە زۆر گەورەیە. زۆرترین قەبارەی ڕێگەپێدراو {{maxSize}}}.","svgImageInsertError":"نەیتوانی وێنەی SVG داخڵ بکات. نیشانەی ئێس ڤی جی نادروست دیارە.","failedToFetchImage":"","invalidSVGString":"ئێس ڤی جی نادروستە.","cannotResolveCollabServer":"ناتوانێت پەیوەندی بکات بە سێرڤەری کۆلاب. تکایە لاپەڕەکە دووبارە باربکەوە و دووبارە هەوڵ بدەوە.","importLibraryError":"نەیتوانی کتێبخانە بار بکات","collabSaveFailed":"نەتوانرا لە بنکەدراوەی ڕاژەدا پاشەکەوت بکرێت. ئەگەر کێشەکان بەردەوام بوون، پێویستە فایلەکەت لە ناوخۆدا هەڵبگریت بۆ ئەوەی دڵنیا بیت کە کارەکانت لەدەست نادەیت.","collabSaveFailed_sizeExceeded":"نەتوانرا لە بنکەدراوەی ڕاژەدا پاشەکەوت بکرێت، پێدەچێت تابلۆکە زۆر گەورە بێت. پێویستە فایلەکە لە ناوخۆدا هەڵبگریت بۆ ئەوەی دڵنیا بیت کە کارەکانت لەدەست نادەیت.","brave_measure_text_error":{"line1":"وادیارە وێبگەڕی Brave بەکاردەهێنیت و ڕێکخستنی Aggressively Block Fingerprinting ـت چالاک کردووە.","line2":"ئەمە ئەکرێ ببێتە هۆی تێکدانی دانە دەقییەکان لە وێنەکێشانەکانتدا.","line3":"ئێمە بە توندی پێشنیاری لەکارخستنی ئەم ڕێکخستنە دەکەین. بۆ لە کارخستنی دەتوانیت بەم هەنگاوانەدا بڕۆیت.","line4":"ئەگەر لەکارخستنی ئەم ڕێکخستنە نەبوە هۆی چاککردنەوەی پێشاندانی دانە دەقییەکان، تکایە کێشەیەک بکەرەوە لەسەر گیتهەبەکەمان، یان بۆمان بنوسە لەسەر دیسکۆرد"},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"دەستنیشانکردن","image":"داخڵکردنی وێنە","rectangle":"لاکێشە","diamond":"ئەڵماس","ellipse":"هێلکەیی","arrow":"تیر","line":"هێڵ","freedraw":"کێشان","text":"دەق","library":"کتێبخانە","lock":"ئامێرە دیاریکراوەکان چالاک بهێڵەوە دوای وێنەکێشان","penMode":"شێوازی قەڵەم - دەست لێدان ڕابگرە","link":"زیادکردن/ نوێکردنەوەی لینک بۆ شێوەی دیاریکراو","eraser":"سڕەر","frame":"ئامرازی چوارچێوە","embeddable":"","laser":"","hand":"دەست (ئامرازی پانکردن)","extraTools":"ئامرازی زیاتر"},"headings":{"canvasActions":"کردارەکانی تابلۆ","selectedShapeActions":"کردارەکانی شێوەی دەستنیشانکراو","shapes":"شێوەکان"},"hints":{"canvasPanning":"بۆ جوڵاندنی تابلۆ، ویلی ماوسەکەت یان دوگمەی سپەیس بگرە لەکاتی ڕاکێشاندە، یانیش ئامرازی دەستەکە بەکاربهێنە","linearElement":"کرتە بکە بۆ دەستپێکردنی چەند خاڵێک، ڕایبکێشە بۆ یەک هێڵ","freeDraw":"کرتە بکە و ڕایبکێشە، کاتێک تەواو بوویت دەست هەڵگرە","text":"زانیاری: هەروەها دەتوانیت دەق زیادبکەیت بە دوو کرتەکردن لە هەر شوێنێک لەگەڵ ئامڕازی دەستنیشانکردن","embeddable":"","text_selected":"دووجار کلیک بکە یان ENTER بکە بۆ دەستکاریکردنی دەق","text_editing":"بۆ تەواوکردنی دەستکاریکردنەکە Escape یان Ctrl/Cmd+ENTER بکە","linearElementMulti":"کلیک لەسەر کۆتا خاڵ بکە یان Escape یان Enter بکە بۆ تەواوکردن","lockAngle":"دەتوانیت گۆشە سنووردار بکەیت بە ڕاگرتنی SHIFT","resize":"دەتوانیت ڕێژەکان سنووردار بکەیت بە ڕاگرتنی SHIFT لەکاتی گۆڕینی قەبارەدا،\\nALT ڕابگرە بۆ گۆڕینی قەبارە لە ناوەندەوە","resizeImage":"دەتوانیت بە ئازادی قەبارە بگۆڕیت بە ڕاگرتنی SHIFT،\\nALT ڕابگرە بۆ گۆڕینی قەبارە لە ناوەندەوە","rotate":"دەتوانیت گۆشەکان سنووردار بکەیت بە ڕاگرتنی SHIFT لەکاتی سوڕانەوەدا","lineEditor_info":"یان Ctrl یان Cmd بگرە و دوانە کلیک بکە یانیش پەنجە بنێ بە Ctrl یان Cmd + ئینتەر بۆ دەستکاریکردنی خاڵەکان","lineEditor_pointSelected":"بۆ لابردنی خاڵەکان Delete دابگرە، Ctrl Cmd+D بکە بۆ لەبەرگرتنەوە، یان بۆ جووڵە ڕاکێشان بکە","lineEditor_nothingSelected":"خاڵێک هەڵبژێرە بۆ دەستکاریکردن (SHIFT ڕابگرە بۆ هەڵبژاردنی چەندین)،\\nیان Alt ڕابگرە و کلیک بکە بۆ زیادکردنی خاڵە نوێیەکان","placeImage":"کلیک بکە بۆ دانانی وێنەکە، یان کلیک بکە و ڕایبکێشە بۆ ئەوەی قەبارەکەی بە دەستی دابنێیت","publishLibrary":"کتێبخانەی تایبەت بە خۆت بڵاوبکەرەوە","bindTextToElement":"بۆ زیادکردنی دەق enter بکە","deepBoxSelect":"CtrlOrCmd ڕابگرە بۆ هەڵبژاردنی قووڵ، و بۆ ڕێگریکردن لە ڕاکێشان","eraserRevert":"بۆ گەڕاندنەوەی ئەو توخمانەی کە بۆ سڕینەوە نیشانە کراون، Alt ڕابگرە","firefox_clipboard_write":"ئەم تایبەتمەندییە بە ئەگەرێکی زۆرەوە دەتوانرێت چالاک بکرێت بە ڕێکخستنی ئاڵای \\"dom.events.asyncClipboard.clipboardItem\\" بۆ \\"true\\". بۆ گۆڕینی ئاڵاکانی وێبگەڕ لە فایەرفۆکسدا، سەردانی لاپەڕەی \\"about:config\\" بکە.","disableSnapping":""},"canvasError":{"cannotShowPreview":"ناتوانرێ پێشبینین پیشان بدرێت","canvasTooBig":"تابلۆکە لەوانەیە زۆر گەورەبێت.","canvasTooBigTip":"زانیاری: هەوڵ بدە دوورترین توخمەکان کەمێک لە یەکتر نزیک بکەوە."},"errorSplash":{"headingMain":"تووشی هەڵەیەک بوو. هەوڵ بدە ","clearCanvasMessage":"ئەگەر دووبارە بارکردنەوە کار ناکات، هەوڵبدە ","clearCanvasCaveat":" ئەمە دەبێتە هۆی لەدەستدانی ئەوەی کە کردوتە ","trackedToSentry":"هەڵەکە لەگەڵ ناسێنەری {{eventId}} لەسەر سیستەمەکەمان بەدواداچوونی بۆ کرا.","openIssueMessage":"ئێمە زۆر وریا بووین کە زانیارییەکانی دیمەنەکەت لەسەر هەڵەکە نەخەینەڕوو. ئەگەر دیمەنەکەت تایبەت نییە، تکایە بیر لە بەدواداچوون بکەنەوە بۆ ئێمە تکایە ئەم زانیارییانەی خوارەوە کۆپی بکە و لە بەشی کێشەکانی Github دایبنێ.","sceneContent":"پێکهاتەی ناو دیمەنەکە:"},"roomDialog":{"desc_intro":"دەتوانیت خەڵک بانگهێشت بکەیت بۆ دیمەنی ئێستات بۆ هاوکاری کردن لەگەڵت.","desc_privacy":"نیگەران مەبە، دانیشتنەکە کۆدکردنی کۆتایی بە کۆتایی بەکاردەهێنێت، بۆیە هەرچییەک بکێشیت بە تایبەتی دەمێنێتەوە. تەنانەت سێرڤەرەکەمان ناتوانێت بزانێت کە تۆ چیت دروستکردووە.","button_startSession":"دەستپێکردنی دانیشتن","button_stopSession":"وەستاندنی دانیشتن","desc_inProgressIntro":"دانیشتنی هاوکاری ڕاستەوخۆ ئێستا لە ئارادایە.","desc_shareLink":"هاوبەشکردنی ئەم لینکە لەگەڵ هەر کەسێک کە دەتەوێت هاوکاری بکەیت لەگەڵ:","desc_exitSession":"وەستاندنی دانیشتنەکە پەیوەندیت لەگەڵ ژوورەکە دەپچڕێنێت، بەڵام تۆ دەتوانیت بەردەوام بیت لە کارکردن لەگەڵ دیمەنەکە، لە ناوخۆدا. تێبینی بکە کە ئەمە کاریگەری لەسەر کەسانی تر نابێت، وە ئەوان هێشتا دەتوانن هاوکاری بکەن لەسەر وەشانەکەیان.","shareTitle":"بەشداری بکە لە دانیشتنی هاریکاری ڕاستەوخۆ لە ئێکسکالیدراو"},"errorDialog":{"title":"ههڵه ڕوویدا"},"exportDialog":{"disk_title":"پاشەکەوت بکە لە دیسک","disk_details":"هەناردەکردنی داتای دیمەنەکە بۆ فایلێک کە دواتر دەتوانیت لێی هاوردە بکەیت.","disk_button":"پاشەکەوت بکە بۆ فایل","link_title":"بەستەری هاوبەشیپێکردن","link_details":"ناردن وەک بەستەری تەنها-خوێندنەوە.","link_button":"هەناردەکردن بۆ بەستەر","excalidrawplus_description":"دیمەنەکە لە شوێنی کارکردنی Excalidraw+ هەڵبگرە.","excalidrawplus_button":"هەناردەکردن","excalidrawplus_exportError":"لەم ساتەدا نەتوانرا هەناردە بکرێت بۆ Excalidrow+..."},"helpDialog":{"blog":"بلۆگەکەمان بخوێنەوە","click":"گرتە","deepSelect":"دەستنیشانکردنی قوڵ","deepBoxSelect":"لەناو بۆکسەکەدا بە قووڵی هەڵبژێرە، و ڕێگری لە ڕاکێشان بکە","curvedArrow":"تیری نوشتاوە","curvedLine":"هێڵی نوشتاوە","documentation":"دۆکیومێنتەیشن","doubleClick":"دوو گرتە","drag":"راکێشان","editor":"دەستکاریکەر","editLineArrowPoints":"دەستکاری خاڵەکانی هێڵ/تیر بکە","editText":"دەستکاری دەق بکە / لەیبڵێک زیاد بکە","github":"کێشەیەکت دۆزیەوە؟ پێشکەشکردن","howto":"شوێن ڕینماییەکانمان بکەوە","or":"یان","preventBinding":"ڕێگریبکە لە نوشتاناوەی تیر","tools":"ئامرازەکان","shortcuts":"کورتکراوەکانی تەختەکلیل","textFinish":"تەواوکردنی دەستکاریکردن (دەستکاریکەری دەق)","textNewLine":"زیادکردنی دێڕی نوێ (دەستکاریکەری دەق)","title":"یارماتی","view":"دیمەن","zoomToFit":"زووم بکە بۆ ئەوەی لەگەڵ هەموو توخمەکاندا بگونجێت","zoomToSelection":"زووم بکە بۆ دەستنیشانکراوەکان","toggleElementLock":"قفڵ/کردنەوەی دەستنیشانکراوەکان","movePageUpDown":"لاپەڕەکە بجوڵێنە بۆ سەرەوە/خوارەوە","movePageLeftRight":"لاپەڕەکە بجوڵێنە بۆ چەپ/ڕاست"},"clearCanvasDialog":{"title":"تابلۆکە خاوێن بکەرەوە"},"publishDialog":{"title":"پێشکەشکردنی کتێبخانە","itemName":"ناوی بڕگە","authorName":"ناوی نوسەر","githubUsername":"ناوی بەکارهێنەری Github","twitterUsername":"ناوی بەکارهێنەری Twitter","libraryName":"ناوی کتێبخانە","libraryDesc":"وەسفی کتێبخانە","website":"ماڵپەڕ","placeholder":{"authorName":"ناوەکات یاخود ناوی بەکارهێنەر","libraryName":"ناوی کتێبخانەکەت","libraryDesc":"وەسفی کتێبخانەکەت بۆ یارمەتیدانی خەڵک بۆ تێگەیشتن لە بەکارهێنانی","githubHandle":"ناوی GitHub (ئارەزوومەندانە)، بۆیە دەتوانیت دەستکاری کتێبخانەکە بکەیت کاتێک پێشکەش دەکرێت بۆ پێداچوونەوە","twitterHandle":"ناوی بەکارهێنەری تویتەر (ئارەزوومەندانە)، بۆیە بزانین لەکاتی بانگەشەکردن لە ڕێگەی تویتەرەوە کریدت بۆ کێ بکەین","website":"لینکی ماڵپەڕی تایبەتی خۆت یان شوێنێکی تر (ئارەزومەندانە)"},"errors":{"required":"داواکراوە","website":"URLێکی دروست تێبنووسە"},"noteDescription":"کتێبخانەکەت بنێرە بۆ ئەوەی بخرێتە ناو کۆگای کتێبخانەی گشتیبۆ ئەوەی کەسانی تر لە وێنەکێشانەکانیاندا بەکاری بهێنن.","noteGuidelines":"کتێبخانەکە پێویستە سەرەتا بە دەست پەسەند بکرێت. تکایە بفەرمو بە خوێندنەوەی ڕێنماییەکان پێش پێشکەشکردن. پێویستت بە ئەژمێری GitHub دەبێت بۆ پەیوەندیکردن و گۆڕانکاری ئەگەر داوای لێکرا، بەڵام بە توندی پێویست نییە.","noteLicense":"بە پێشکەشکردن، تۆ ڕەزامەندیت لەسەر بڵاوکردنەوەی کتێبخانەکە بەپێی مۆڵەتی MIT، کە بە کورتی مانای ئەوەیە کە هەرکەسێک دەتوانێت بە بێ سنوور بەکاری بهێنێت","noteItems":"هەر شتێکی کتێبخانە دەبێت ناوی تایبەتی خۆی هەبێت بۆ ئەوەی بتوانرێت فلتەر بکرێت. ئەم بابەتانەی کتێبخانانەی خوارەوە لەخۆدەگرێت:","atleastOneLibItem":"تکایە بەلایەنی کەمەوە یەک بڕگەی کتێبخانە دیاریبکە بۆ دەستپێکردن","republishWarning":"تێبینی: هەندێک لە ئایتمە دیاریکراوەکان نیشانکراون وەک ئەوەی پێشتر بڵاوکراونەتەوە/نێردراون. تەنها پێویستە شتەکان دووبارە پێشکەش بکەیتەوە لە کاتی نوێکردنەوەی کتێبخانەیەکی هەبوو یان پێشکەشکردن."},"publishSuccessDialog":{"title":"کتێبخانە پێشکەش کرا","content":"سوپاس {{authorName}}. کتێبخانەکەت پێشکەش کراوە بۆ پێداچوونەوە. دەتوانیت بەدواداچوون بۆ دۆخەکە بکەیتلێرە"},"confirmDialog":{"resetLibrary":"ڕێکخستنەوەی کتێبخانە","removeItemsFromLib":"لابردنی ئایتمە دیاریکراوەکان لە کتێبخانە"},"imageExportDialog":{"header":"وێنە هەناردە بکە","label":{"withBackground":"پاشبنەما","onlySelected":"تەنها دیاریکراوەکان","darkMode":"دۆخی تاریک","embedScene":"دیمەنەکە بەکاربهێنەرەوە","scale":"قەبارە","padding":"بۆشایی"},"tooltip":{"embedScene":"داتاکانی دیمەنەکە لە فایلە هەناردەکراوەکەی PNG/SVG هەڵدەگیرێن بۆ ئەوەی دیمەنەکە لێیەوە بگەڕێتەوە.\\nقەبارەی پەڕگەی هەناردەکراو زیاد دەکات."},"title":{"exportToPng":"هەناردە بکە وەک PNG","exportToSvg":"هەناردە بکە وەک SVG","copyPngToClipboard":"لەبەربگرەوە بۆ سەر تەختەنوس"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"لهبهری بگرهوه بۆ تهختهنووس"}},"encrypted":{"tooltip":"وێنەکێشانەکانت لە کۆتاییەوە بۆ کۆتایی کۆد کراون بۆیە سێرڤەرەکانی ئێکسکالیدرا هەرگیز نایانبینن.","link":"بلۆگ پۆست لەسەر کۆدکردنی کۆتای بۆ کۆتای لە ئێکسکالیدرەو"},"stats":{"angle":"گۆشە","element":"توخم","elements":"توخمەکان","height":"بەرزی","scene":"دیمەنەکە","selected":"دەستنیشانکراوەکان","storage":"بیرگە","title":"ئامار بۆ نێردەکان","total":"گشتی","version":"وەشان","versionCopy":"کلیک بۆ لەبەرگرتنەوە","versionNotAvailable":"وەشان بەردەست نییە","width":"پانی"},"toast":{"addedToLibrary":"زیادکرا بۆ کتێبخانە","copyStyles":"ستایلی کۆپیکراو.","copyToClipboard":"لەبەرگیرایەوە بۆ تەختەنوس.","copyToClipboardAsPng":"کۆپی کراوە {{exportSelection}} بۆ کلیپبۆرد وەک PNG\\n({{exportColorScheme}})","fileSaved":"فایل هەڵگیرا.","fileSavedToFilename":"هەڵگیراوە بۆ {filename}","canvas":"تابلۆ","selection":"دەستنیشانکراوەکان","pasteAsSingleElement":"بۆ دانانەوە وەکو یەک توخم یان دانانەوە بۆ نێو دەسکاریکەرێکی دەق کە بوونی هەیە {{shortcut}} بەکاربهێنە","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"ڕوون","black":"ڕەش","white":"سپی","red":"سور","pink":"پەمەیی","grape":"مێوژی","violet":"مۆری کاڵ","gray":"خۆڵەمێشی","blue":"شین","cyan":"شینی ئاسمانی","teal":"شەدری","green":"سهوز","yellow":"زەرد","orange":"پرتەقاڵی","bronze":"برۆنزی"},"welcomeScreen":{"app":{"center_heading":"هەموو داتاکانت لە ناوخۆی وێنگەڕەکەتدا پاشەکەوت کراوە.","center_heading_plus":"ویستت بڕۆیت بۆ Excalidraw+?","menuHint":"هەناردەکردن، ڕێکخستنەکان، زمانەکان، ..."},"defaults":{"menuHint":"هەناردەکردن، ڕێکخستنەکان، و زیاتر...","center_heading":"دایاگرامەکان. ئاسان. کراون.","toolbarHint":"ئامرازێک هەڵبگرە و دەستبکە بە کێشان!","helpHint":"قەدبڕەکان و یارمەتی"}},"colorPicker":{"mostUsedCustomColors":"زۆرترین ڕەنگە باوە بەکارهاتووەکان","colors":"ڕەنگەکان","shades":"سێبەرەکان","hexCode":"کۆدی هێکس","noShades":"هیچ سێبەرێک بۆ ئەم ڕەنگە بەردەست نییە"},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/lt-LT-json-2c3d35d6fb5dbf95a27e.js b/public/excalidraw/excalidraw-assets-dev/locales/lt-LT-json-2c3d35d6fb5dbf95a27e.js
new file mode 100644
index 0000000..5672dee
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/lt-LT-json-2c3d35d6fb5dbf95a27e.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/lt-LT-json"],{
+
+/***/ "../../locales/lt-LT.json":
+/*!********************************!*\
+ !*** ../../locales/lt-LT.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Įklijuoti","pasteAsPlaintext":"Įklijuoti kaip paprastą tekstą","pasteCharts":"Įklijuoti diagramas","selectAll":"Pažymėti viską","multiSelect":"Pridėkite elementą prie pasirinktų","moveCanvas":"Judinti drobę","cut":"Iškirpti","copy":"Kopijuoti","copyAsPng":"Kopijuoti į iškarpinę kaip PNG","copyAsSvg":"Kopijuoti į iškarpinę kaip SVG","copyText":"Kopijuoti į iškarpinę kaip tekstą","bringForward":"Kelti priekio link","sendToBack":"Nustumti į užnugarį","bringToFront":"Iškelti į priekį","sendBackward":"Nustumti link užnugario","delete":"Ištrinti","copyStyles":"Kopijuoti stilius","pasteStyles":"Įklijuoti stilius","stroke":"Linija","background":"Fonas","fill":"Užpildymas","strokeWidth":"Linijos storis","strokeStyle":"Linijos stilius","strokeStyle_solid":"Ištisinė","strokeStyle_dashed":"Brūkšniuota","strokeStyle_dotted":"Taškuota","sloppiness":"Netvarkingumas","opacity":"Nepermatomumas","textAlign":"Teksto lygiavimas","edges":"Kraštai","sharp":"Aštrus","round":"Užapvalintas","arrowheads":"Rodyklės viršūnės","arrowhead_none":"Jokios","arrowhead_arrow":"Rodyklė","arrowhead_bar":"Brukšnys","arrowhead_dot":"Taškas","arrowhead_triangle":"Trikampis","fontSize":"Šrifto dydis","fontFamily":"Šriftas","addWatermark":"Sukurta su Excalidraw","handDrawn":"Ranka rašytas","normal":"Normalus","code":"Kodas","small":"Mažas","medium":"Vidutinis","large":"Didelis","veryLarge":"Labai didelis","solid":"","hachure":"","zigzag":"","crossHatch":"","thin":"Plonas","bold":"Pastorintas","left":"Kairėje","center":"Centre","right":"Dešinėje","extraBold":"Labiau pastorintas","architect":"Architektas","artist":"Menininkas","cartoonist":"Karikatūristas","fileTitle":"Failo pavadinimas","colorPicker":"Spalvos parinkiklis","canvasColors":"","canvasBackground":"Drobės fonas","drawingCanvas":"","layers":"Sluoksniai","actions":"Veiksmai","language":"Kalba","liveCollaboration":"Bendradarbiavimas gyvai...","duplicateSelection":"","untitled":"","name":"","yourName":"Jūsų vardas","madeWithExcalidraw":"Sukurta su Excalidraw","group":"Grupuoti pasirinkimą","ungroup":"Išgrupuoti pasirinkimą","collaborators":"Bendradarbiautojai","showGrid":"Rodyti tinklelį","addToLibrary":"Pridėti į biblioteką","removeFromLibrary":"Pašalinti iš bibliotekos","libraryLoadingMessage":"","libraries":"Naršyti bibliotekas","loadingScene":"","align":"Lygiuoti","alignTop":"Lygiuoti viršuje","alignBottom":"Lygiuoti apačioje","alignLeft":"Lygiuoti kairėje","alignRight":"Lygiuoti dešinėje","centerVertically":"Centruoti vertikaliai","centerHorizontally":"Centruoti horizontaliai","distributeHorizontally":"","distributeVertically":"","flipHorizontal":"Apversti horizontaliai","flipVertical":"Apversti vertikaliai","viewMode":"","share":"Dalintis","showStroke":"","showBackground":"","toggleTheme":"","personalLib":"Asmeninė biblioteka","excalidrawLib":"Exaclidraw biblioteka","decreaseFontSize":"","increaseFontSize":"","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"Redeguoti nuorodą","editEmbed":"","create":"Sukurti nuorodą","createEmbed":"","label":"Nuoroda","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"Užrakinti","unlock":"Atrakinti","lockAll":"","unlockAll":""},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"","exportJSON":"Eksportuoti į failą","exportImage":"","export":"","copyToClipboard":"Kopijuoti į iškarpinę","save":"","saveAs":"Išsaugoti kaip","load":"","getShareableLink":"Gauti nuorodą dalinimuisi","close":"Uždaryti","selectLanguage":"Pasirinkite kalbą","scrollBackToContent":"","zoomIn":"Priartinti","zoomOut":"Nutolinti","resetZoom":"","menu":"Meniu","done":"","edit":"Redaguoti","undo":"Anuliuoti","redo":"","resetLibrary":"Atstatyti biblioteką","createNewRoom":"Sukurti naują kambarį","fullScreen":"Visas ekranas","darkMode":"Tamsus režimas","lightMode":"Šviesus režimas","zenMode":"„Zen“ režimas","objectsSnapMode":"","exitZenMode":"Išeiti iš „Zen“ režimo","cancel":"Atšaukti","clear":"Išvalyti","remove":"Pašalinti","embed":"","publishLibrary":"Paskelbti","submit":"Pateikti","confirm":"Patvirtinti","embeddableInteractionButton":""},"alerts":{"clearReset":"","couldNotCreateShareableLink":"","couldNotCreateShareableLinkTooBig":"","couldNotLoadInvalidFile":"","importBackendFailed":"","cannotExportEmptyCanvas":"","couldNotCopyToClipboard":"","decryptFailed":"","uploadedSecurly":"","loadSceneOverridePrompt":"","collabStopOverridePrompt":"Sesijos nutraukimas perrašys ankstesnį, lokaliai išsaugotą piešinį. Ar tikrai to nori?\\n\\n(Jei nori išlaikyti lokalų piešinį, tiesiog uždaryk naršyklės skirtuką.)","errorAddingToLibrary":"Nepavyko įtraukti elemento į biblioteką","errorRemovingFromLibrary":"Nepavyko pašalinti elemento iš bibliotekos","confirmAddLibrary":"Tai įtrauks {{numShapes}} figūrą/-as į tavo biblioteką. Ar tikrai to nori?","imageDoesNotContainScene":"Panašu, jog šis paveiksliukas neturi scenos duomenų. Ar yra įjuntas scenos įtraukimas ekportavimo metu?","cannotRestoreFromImage":"Nepavyko atstatyti scenos iš šio nuotraukos failo","invalidSceneUrl":"Nepavyko suimportuoti scenos iš pateiktos nuorodos (URL). Ji arba blogai suformatuota, arba savyje neturi teisingų Excalidraw JSON duomenų.","resetLibrary":"Tai išvalys tavo biblioteką. Ar tikrai to nori?","removeItemsFromsLibrary":"Ištrinti {{count}} elementą/-us iš bibliotekos?","invalidEncryptionKey":"Šifravimo raktas turi būti iš 22 simbolių. Redagavimas gyvai yra išjungtas.","collabOfflineWarning":""},"errors":{"unsupportedFileType":"Nepalaikomas failo tipas.","imageInsertError":"Nepyko įkelti paveiksliuko. Pabandyk vėliau...","fileTooBig":"Per didelis failas. Didžiausias leidžiamas dydis yra {{maxSize}}.","svgImageInsertError":"Nepavyko įtraukti SVG paveiksliuko. Panašu, jog SVG yra nevalidus.","failedToFetchImage":"","invalidSVGString":"Nevalidus SVG.","cannotResolveCollabServer":"Nepavyko prisijungti prie serverio bendradarbiavimui. Perkrauk puslapį ir pabandyk prisijungti dar kartą.","importLibraryError":"Nepavyko įkelti bibliotekos","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Žymėjimas","image":"Įkelti paveiksliuką","rectangle":"Stačiakampis","diamond":"Deimantas","ellipse":"Elipsė","arrow":"Rodyklė","line":"Linija","freedraw":"Piešti","text":"Tekstas","library":"Biblioteka","lock":"Baigus piešti, išlaikyti pasirinktą įrankį","penMode":"Rašyklio režimas - neleisti prisilietimų","link":"Pridėti / Atnaujinti pasirinktos figūros nuorodą","eraser":"Trintukas","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"Veiksmai su drobe","selectedShapeActions":"Veiksmai su pasirinkta figūra","shapes":"Figūros"},"hints":{"canvasPanning":"","linearElement":"Paspaudimai sukurs papildomus taškus, nepertraukiamas tempimas sukurs liniją","freeDraw":"Spausk ir tempk, paleisk kai norėsi pabaigti","text":"Užuomina: tekstą taip pat galima pridėti bet kur su dvigubu pelės paspaudimu, kol parinkas žymėjimo įrankis","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"","lockAngle":"","resize":"","resizeImage":"","rotate":"","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"","canvasTooBig":"","canvasTooBigTip":""},"errorSplash":{"headingMain":"","clearCanvasMessage":"","clearCanvasCaveat":"","trackedToSentry":"","openIssueMessage":"","sceneContent":""},"roomDialog":{"desc_intro":"","desc_privacy":"","button_startSession":"Pradėti seansą","button_stopSession":"Sustabdyti seansą","desc_inProgressIntro":"","desc_shareLink":"","desc_exitSession":"","shareTitle":""},"errorDialog":{"title":"Klaida"},"exportDialog":{"disk_title":"Įrašyti į diską","disk_details":"","disk_button":"Įrašyti į failą","link_title":"Nuoroda dalinimuisi","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"Eksportuoti","excalidrawplus_exportError":""},"helpDialog":{"blog":"","click":"paspaudimas","deepSelect":"","deepBoxSelect":"","curvedArrow":"Banguota rodyklė","curvedLine":"Banguota linija","documentation":"Dokumentacija","doubleClick":"dvigubas paspaudimas","drag":"vilkti","editor":"Redaktorius","editLineArrowPoints":"","editText":"","github":"Radai klaidą? Pateik","howto":"Vadovaukis mūsų gidu","or":"arba","preventBinding":"","tools":"Įrankiai","shortcuts":"Spartieji klavišai","textFinish":"Baigti redagavimą (teksto redaktoriuje)","textNewLine":"Pridėti naują eilutę (tekto redaktoriuje)","title":"Pagalba","view":"","zoomToFit":"","zoomToSelection":"Priartinti iki pažymėtos vietos","toggleElementLock":"","movePageUpDown":"Pajudinti puslapį aukštyn/žemyn","movePageLeftRight":"Pajudinti puslapį kairėn/dešinėn"},"clearCanvasDialog":{"title":"Išvalyti drobę"},"publishDialog":{"title":"Paviešinti biblioteką","itemName":"Elemento pavadinimas","authorName":"Autoriaus vardas","githubUsername":"Github spalyvardis","twitterUsername":"Twitter slapyvardis","libraryName":"Bibliotekos pavadinimas","libraryDesc":"Bibliotekos aprašas","website":"Tinklalapis","placeholder":{"authorName":"Tavo vardas arba spalyvardis","libraryName":"Tavo bibliotekos pavadinimas","libraryDesc":"Tavo bibliotekos aprašas, padėti žmonėms geriau suprasti jos paskirtį","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"Privalomas","website":"Įveskite teisingą nuorodą (URL)"},"noteDescription":"Pateik savo biblioteką, jog ji galėtų būti įtraukta į jog kiti žmonės galėtų tai naudoti savo piešiniuose.","noteGuidelines":"Visų pirma, biblioteka turi būti rankiniu būdu patvirtinta. Prašome paskaityti gairės","noteLicense":"MIT licencija, ","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"Biblioteka pateikta","content":"Ačiū {{authorName}}. Tavo biblioteka buvo pateikta peržiūrai. Gali sekti būsenąčia"},"confirmDialog":{"resetLibrary":"Atstatyti biblioteką","removeItemsFromLib":"Pašalinti pasirinktus elementus iš bibliotekos"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"","link":""},"stats":{"angle":"","element":"Elementas","elements":"Elementai","height":"Aukštis","scene":"Scena","selected":"Pasirinkta","storage":"Saugykla","title":"Informacija moksliukams","total":"","version":"","versionCopy":"","versionNotAvailable":"","width":"Plotis"},"toast":{"addedToLibrary":"Pridėta į biblioteką","copyStyles":"","copyToClipboard":"Nukopijuota į iškarpinę.","copyToClipboardAsPng":"","fileSaved":"Failas išsaugotas.","fileSavedToFilename":"Išsaugota į {filename}","canvas":"drobė","selection":"","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Permatoma","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/lv-LV-json-fa8973c231afb2ddafe9.js b/public/excalidraw/excalidraw-assets-dev/locales/lv-LV-json-fa8973c231afb2ddafe9.js
new file mode 100644
index 0000000..6d45a98
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/lv-LV-json-fa8973c231afb2ddafe9.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/lv-LV-json"],{
+
+/***/ "../../locales/lv-LV.json":
+/*!********************************!*\
+ !*** ../../locales/lv-LV.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Ielīmēt","pasteAsPlaintext":"Ielīmēt kā vienkāršu tekstu","pasteCharts":"Ielīmēt grafikus","selectAll":"Atlasīt visu","multiSelect":"Pievienot elementu atlasei","moveCanvas":"Pārvietot tāfeli","cut":"Izgriezt","copy":"Kopēt","copyAsPng":"Kopēt starpliktuvē kā PNG","copyAsSvg":"Kopēt starpliktuvē kā SVG","copyText":"Kopēt starpliktuvē kā tekstu","bringForward":"Pārvietot vienu slāni augstāk","sendToBack":"Pārvietot uz zemāko slāni","bringToFront":"Pārvietot uz virsējo slāni","sendBackward":"Pārvietot par vienu slāni zemāk","delete":"Dzēst","copyStyles":"Kopēt stilus","pasteStyles":"Ielīmēt stilus","stroke":"Svītras krāsa","background":"Fona krāsa","fill":"Aizpildījums","strokeWidth":"Svītras platums","strokeStyle":"Svītras stils","strokeStyle_solid":"Vienlaidu","strokeStyle_dashed":"Raustīta līnija","strokeStyle_dotted":"Punktota līnija","sloppiness":"Precizitāte","opacity":"Necaurspīdīgums","textAlign":"Teksta līdzināšana","edges":"Malas","sharp":"Asas","round":"Apaļas","arrowheads":"Bultas","arrowhead_none":"Nekādas","arrowhead_arrow":"Bulta","arrowhead_bar":"Svītra","arrowhead_dot":"Punkts","arrowhead_triangle":"Trijstūris","fontSize":"Teksta lielums","fontFamily":"Fontu saime","addWatermark":"Pievienot \\"Radīts ar Excalidraw\\"","handDrawn":"Rokraksts","normal":"Parasts","code":"Kods","small":"Mazs","medium":"Vidējs","large":"Liels","veryLarge":"Ļoti liels","solid":"Pilns","hachure":"Svītrots","zigzag":"Zigzaglīnija","crossHatch":"Šķērssvītrots","thin":"Šaurs","bold":"Trekns","left":"Pa kreisi","center":"Vidū","right":"Pa labi","extraBold":"Īpaši trekns","architect":"Arhitekts","artist":"Mākslinieks","cartoonist":"Karikatūrists","fileTitle":"Datnes nosaukums","colorPicker":"Krāsu atlasītājs","canvasColors":"Izmantots tāfelei","canvasBackground":"Ainas fons","drawingCanvas":"Tāfele","layers":"Slāņi","actions":"Darbības","language":"Valoda","liveCollaboration":"Sadarbība tiešsaistē...","duplicateSelection":"Izveidot kopiju","untitled":"Bez nosaukuma","name":"Vārds","yourName":"Jūsu vārds","madeWithExcalidraw":"Radīts ar Excalidraw","group":"Grupēt atlasīto","ungroup":"Atgrupēt atlasīto","collaborators":"Dalībnieki","showGrid":"Rādīt režģi","addToLibrary":"Pievienot bibliotēkai","removeFromLibrary":"Izņemt no bibliotēkas","libraryLoadingMessage":"Ielādē bibliotēku…","libraries":"Apskatīt bibliotēkas","loadingScene":"Ielādē ainu…","align":"Līdzināt","alignTop":"Līdzināt augšpusē","alignBottom":"Līdzināt lejā","alignLeft":"Līdzināt pa kreisi","alignRight":"Līdzināt pa labi","centerVertically":"Centrēt vertikāli","centerHorizontally":"Centrēt horizontāli","distributeHorizontally":"Izdalīt horizontāli","distributeVertically":"Izdalīt vertikāli","flipHorizontal":"Apmest horizontāli","flipVertical":"Apmest vertikāli","viewMode":"Skata režīms","share":"Kopīgot","showStroke":"Rādīt svītras krāsas atlasītāju","showBackground":"Rādīt fona krāsas atlasītāju","toggleTheme":"Pārslēgt krāsu tēmu","personalLib":"Personīgā bibliotēka","excalidrawLib":"Excalidraw bibliotēka","decreaseFontSize":"Samazināt fonta izmēru","increaseFontSize":"Palielināt fonta izmēru","unbindText":"Atdalīt tekstu","bindText":"Piesaistīt tekstu figūrai","createContainerFromText":"Ietilpināt tekstu figurā","link":{"edit":"Rediģēt saiti","editEmbed":"","create":"Izveidot saiti","createEmbed":"","label":"Saite","labelEmbed":"","empty":""},"lineEditor":{"edit":"Rediģēt līniju","exit":"Aizvērt līnijas redaktoru"},"elementLock":{"lock":"Fiksēt","unlock":"Atbrīvot","lockAll":"Fiksēt visu","unlockAll":"Atbrīvot visu"},"statusPublished":"Publicēts","sidebarLock":"Paturēt atvērtu sānjoslu","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Neviena vienība vēl nav pievienota...","hint_emptyLibrary":"Atlasiet objektu tāfelē, lai to šeit pievienotu, vai pievienojiet publisku bibliotēku zemāk.","hint_emptyPrivateLibrary":"Atlasiet objektu tāfelē, lai to šeit pievienotu."},"buttons":{"clearReset":"Atiestatīt tāfeli","exportJSON":"Eksportēt kā failu","exportImage":"Eksportēt attēlu...","export":"Saglabāt uz...","copyToClipboard":"Kopēt starpliktuvē","save":"Saglabāt pašreizējo datni","saveAs":"Saglabāt kā","load":"Atvērt","getShareableLink":"Iegūt kopīgošanas saiti","close":"Aizvērt","selectLanguage":"Izvēlieties valodu","scrollBackToContent":"Atgriezties pie satura","zoomIn":"Tuvināt","zoomOut":"Tālināt","resetZoom":"Atiestatīt tuvinājumu","menu":"Izvēlne","done":"Gatavs","edit":"Rediģēt","undo":"Atsaukt","redo":"Atcelt atsaukšanu","resetLibrary":"Atiestatīt bibliotēku","createNewRoom":"Izveidot jaunu telpu","fullScreen":"Pilnekrāna režīms","darkMode":"Tumšais režīms","lightMode":"Gaišais režīms","zenMode":"Zen režīms","objectsSnapMode":"","exitZenMode":"Pamest Zen režīmu","cancel":"Atcelt","clear":"Notīrīt","remove":"Noņemt","embed":"","publishLibrary":"Publicēt","submit":"Iesniegt","confirm":"Apstiprināt","embeddableInteractionButton":""},"alerts":{"clearReset":"Šī funkcija notīrīs visu tāfeli. Vai turpināt?","couldNotCreateShareableLink":"Nevarēja izveidot kopīgojamo saiti.","couldNotCreateShareableLinkTooBig":"Nevarēja izveidot kopīgojamo saiti – aina ir par lielu","couldNotLoadInvalidFile":"Nevarēja ielādēt nederīgu datni","importBackendFailed":"Ielāde no krātuves neizdevās.","cannotExportEmptyCanvas":"Nevar eksportēt tukšu tāfeli.","couldNotCopyToClipboard":"Nevarēja nokopēt starpliktuvē.","decryptFailed":"Nevarēja atšifrēt datus.","uploadedSecurly":"Augšuplāde nodrošināta ar šifrēšanu no gala līdz galam, kas nozīmē, ka Excalidraw serveri un trešās puses nevar lasīt saturu.","loadSceneOverridePrompt":"Ārēja satura ielāde aizstās jūsu pašreizējo saturu. Vai vēlaties turpināt?","collabStopOverridePrompt":"Sesijas pārtraukšana pārrakstīs jūsu iepriekšējo zīmējumu, kas saglabāts jūsu pārlūkā. Vai turpināt?\\n\\n(Ja vēlaties paturēt zīmējumu, kas saglabāts jūsu pārlūkā, vienkārši aizveriet pārlūka cilni.)","errorAddingToLibrary":"Nevarēja pievienot vienumu bibliotēkai","errorRemovingFromLibrary":"Nevarēja izņemt vienumu no bibliotēkas","confirmAddLibrary":"Šī funkcija pievienos {{numShapes}} formu(-as) jūsu bibliotēkai. Vai turpināt?","imageDoesNotContainScene":"Šķiet, ka attēls nesatur ainas datus. Vai iespējojāt ainas iegulšanu, kad eksportējāt?","cannotRestoreFromImage":"Ainu nevarēja atgūt no attēla datnes","invalidSceneUrl":"Nevarēja importēt ainu no norādītā URL. Vai nu tas ir nederīgs, vai nesatur derīgus Excalidraw JSON datus.","resetLibrary":"Šī funkcija iztukšos bibliotēku. Vai turpināt?","removeItemsFromsLibrary":"Vai izņemt {{count}} vienumu(s) no bibliotēkas?","invalidEncryptionKey":"Šifrēšanas atslēgai jābūt 22 simbolus garai. Tiešsaistes sadarbība ir izslēgta.","collabOfflineWarning":"Nav pieejams interneta pieslēgums.\\nJūsu izmaiņas netiks saglabātas!"},"errors":{"unsupportedFileType":"Neatbalstīts datnes veids.","imageInsertError":"Nevarēja ievietot attēlu. Mēģiniet vēlāk...","fileTooBig":"Datne ir par lielu. Lielākais atļautais izmērs ir {{maxSize}}.","svgImageInsertError":"Nevarēja ievietot SVG attēlu. Šķiet, ka SVG marķējums nav derīgs.","failedToFetchImage":"","invalidSVGString":"Nederīgs SVG.","cannotResolveCollabServer":"Nevarēja savienoties ar sadarbošanās serveri. Lūdzu, pārlādējiet lapu un mēģiniet vēlreiz.","importLibraryError":"Nevarēja ielādēt bibliotēku","collabSaveFailed":"Darbs nav saglabāts datubāzē. Ja problēma turpinās, saglabājiet datni lokālajā krātuvē, lai nodrošinātos pret darba pazaudēšanu.","collabSaveFailed_sizeExceeded":"Darbs nav saglabāts datubāzē, šķiet, ka tāfele ir pārāk liela. Saglabājiet datni lokālajā krātuvē, lai nodrošinātos pret darba pazaudēšanu.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Atlase","image":"Ievietot attēlu","rectangle":"Taisnstūris","diamond":"Rombs","ellipse":"Elipse","arrow":"Bulta","line":"Līnija","freedraw":"Zīmēt","text":"Teksts","library":"Bibliotēka","lock":"Paturēt izvēlēto rīku pēc darbības","penMode":"Pildspalvas režīms – novērst pieskaršanos","link":"Pievienot/rediģēt atlasītās figūras saiti","eraser":"Dzēšgumija","frame":"","embeddable":"","laser":"","hand":"Roka (panoramēšanas rīks)","extraTools":""},"headings":{"canvasActions":"Tāfeles darbības","selectedShapeActions":"Izvēlētās formas darbības","shapes":"Formas"},"hints":{"canvasPanning":"Lai bīdītu tāfeli, turiet nospiestu ritināšanas vai atstarpes taustiņu, vai izmanto rokas rīku","linearElement":"Klikšķiniet, lai sāktu zīmēt vairākus punktus; velciet, lai zīmētu līniju","freeDraw":"Spiediet un velciet; atlaidiet, kad pabeidzat","text":"Ieteikums: lai pievienotu tekstu, varat arī jebkur dubultklikšķināt ar atlases rīku","embeddable":"","text_selected":"Dubultklikšķiniet vai spiediet ievades taustiņu, lai rediģētu tekstu","text_editing":"Spiediet iziešanas taustiņu vai CtrlOrCmd+ENTER, lai beigtu rediģēt","linearElementMulti":"Klikšķiniet uz pēdējā punkta vai spiediet izejas vai ievades taustiņu, lai pabeigtu","lockAngle":"Varat ierobežot leņķi, turot nospiestu SHIFT","resize":"Kad maināt izmēru, varat ierobežot proporcijas, turot nospiestu SHIFT,\\nvai arī ALT, lai mainītu izmēru ap centru","resizeImage":"Varat brīvi mainīt izmēru, turot nospiestu SHIFT;\\nturiet nospiestu ALT, lai mainītu izmēru ap centru","rotate":"Rotējot varat ierobežot leņķi, turot nospiestu SHIFT","lineEditor_info":"Turiet CtrlOrCmd un dubultklikšķiniet, vai spiediet CtrlOrCmd + Enter, lai rediģētu punktus","lineEditor_pointSelected":"Spiediet dzēšanas taustiņu, lai noņemtu punktus, – CtrlOrCmd+D, lai to kopētu, vai velciet, lai pārvietotu","lineEditor_nothingSelected":"Atlasiet punktu, lai labotu (turiet nospiestu SHIFT, lai atlasītu vairākus),\\nvai turiet Alt un clikšķiniet, lai pievienotu jaunus punktus","placeImage":"Klikšķiniet, lai novietotu attēlu, vai spiediet un velciet, lai iestatītu tā izmēru","publishLibrary":"Publicēt savu bibliotēku","bindTextToElement":"Spiediet ievades taustiņu, lai pievienotu tekstu","deepBoxSelect":"Turient nospiestu Ctrl vai Cmd, lai atlasītu dziļumā un lai nepieļautu objektu pavilkšanu","eraserRevert":"Turiet Alt, lai noņemtu elementus no dzēsšanas atlases","firefox_clipboard_write":"Šis iestatījums var tikt ieslēgts ar \\"dom.events.asyncClipboard.clipboardItem\\" marķieri pārslēgtu uz \\"true\\". Lai mainītu pārlūka marķierus Firefox, apmeklē \\"about:config\\" lapu.","disableSnapping":""},"canvasError":{"cannotShowPreview":"Nevar rādīt priekšskatījumu","canvasTooBig":"Iespējams, tāfele ir par lielu.","canvasTooBigTip":"Ieteikums: mēģiniet satuvināt pašus tālākos elementus."},"errorSplash":{"headingMain":"Notikusi kļūda. Mēģiniet ","clearCanvasMessage":"Ja pārlādēšana nestrādā, mēģiniet ","clearCanvasCaveat":" Tas novedīs pie darba zaudēšanas ","trackedToSentry":"Kļūda ar kodu {{eventId}} tika noteikta mūsu sistēmā.","openIssueMessage":"Mēs uzmanījāmies, lai neiekļautu jūsu ainas informāciju šajā kļūdā. Ja jūsu aina nav privāta, lūdzu ziņojiet par šo kļūdu mūsu Lūdzu, miniet sekojošo informāciju to kopējot un ielīmējot jūsu ziņojumā platformā GitHub.","sceneContent":"Ainas saturs:"},"roomDialog":{"desc_intro":"Varat ielūgt cilvēkus pašreizējajā ainā, lai sadarbotos ar tiem.","desc_privacy":"Neuztraucieties, sesija izmanto šifrēšanu no gala līdz galam, tātad jūsu zīmējums paliks privāts. Pat mūsu serveri nevarēs redzēt, ar ko esat nācis klajā.","button_startSession":"Sākt sesiju","button_stopSession":"Beigt sesiju","desc_inProgressIntro":"Notiek tiešsaistes sadarbības sesija.","desc_shareLink":"Dalieties ar šo saiti ar jebkuru, ar ko vēlaties sadarboties:","desc_exitSession":"Sesijas beigšana jūs atvienos no sadarbošanās, bet jūs vēl joprojām varēsiet strādāt ar ainu savā datorā. Ievērojiet, ka šis neietekmēs citus dalībniekus, un viņi vēl joprojām varēs sadarboties savā ainas versijā.","shareTitle":"Pievienoties tiešsaistes sadarbībai programmā Excalidraw"},"errorDialog":{"title":"Kļūda"},"exportDialog":{"disk_title":"Saglabāt diskā","disk_details":"Eksportēt ainas datus datnē, ko vēlāk varēsiet importēt.","disk_button":"Saglabāt datnē","link_title":"Kopīgošanas saite","link_details":"Eksportēt kā tikai lasāmu saiti.","link_button":"Eksportēt kā saiti","excalidrawplus_description":"Saglabāt ainu savā Excalidraw+ darbvietā.","excalidrawplus_button":"Eksportēt","excalidrawplus_exportError":"Pašreiz nevarēja eksportēt uz Excalidraw+..."},"helpDialog":{"blog":"Lasīt mūsu blogu","click":"klikšķis","deepSelect":"Atlasīt dziļumā","deepBoxSelect":"Atlasīt dziļumā kastes ietvaros, un nepieļaut pavilkšanu","curvedArrow":"Liekta bulta","curvedLine":"Liekta līnija","documentation":"Dokumentācija","doubleClick":"dubultklikšķis","drag":"vilkt","editor":"Redaktors","editLineArrowPoints":"Rediģēt līniju/bultu punktus","editText":"Rediģēt tekstu/pievienot birku","github":"Sastapāt kļūdu? Ziņot","howto":"Sekojiet mūsu instrukcijām","or":"vai","preventBinding":"Novērst bultu piesaistīšanos","tools":"Rīki","shortcuts":"Tastatūras saīsnes","textFinish":"Pabeigt rediģēšanu (teksta redaktorā)","textNewLine":"Nākamā rindiņa (teksta redaktorā)","title":"Palīdzība","view":"Skatīt","zoomToFit":"Iestatīt mērogu, kas iekļauj visus elementus","zoomToSelection":"Iestatīt mērogu, lai rādītu atlasi","toggleElementLock":"Fiksēt/atbrīvot atlasīto","movePageUpDown":"Pārvietot lapu augšup/lejup","movePageLeftRight":"Pārvietot lapu pa labi/kreisi"},"clearCanvasDialog":{"title":"Notīrīt tāfeli"},"publishDialog":{"title":"Publicēt bibliotēku","itemName":"Vienuma nosaukums","authorName":"Autora vārds","githubUsername":"GitHub lietotājvārds","twitterUsername":"Twitter lietotājvārds","libraryName":"Bibliotēkas nosaukums","libraryDesc":"Bibliotēkas apraksts","website":"Mājaslapa","placeholder":{"authorName":"Jūsu vārds vai lietotājvārds","libraryName":"Jūsu bibliotēkas nosaukums","libraryDesc":"Bibliotēkas apraksts, kas palīdzēs citiem saprast tās pielietojumu","githubHandle":"GitHub lietotājvārds (neobligāts), lai jūs varētu rediģēt bibliotēku pēc tās iesniegšanas izskatīšanai","twitterHandle":"Twitter lietotājvārds (neobligāts), lai mēs varētu jūs pieminēt kā autoru, kad reklamēsim bibliotēku platformā Twitter","website":"Saikne uz jūsu personīgo mājaslapu vai kādu citu lapu (neobligāta)"},"errors":{"required":"Obligāts","website":"Ievadiet derīgu URL"},"noteDescription":"Iesniegt savu bibliotēku iekļaušanai publiskajā bibliotēku datubāzē, lai citi to varētu izmantot savos zīmējumos.","noteGuidelines":"Šai bibliotēkai vispirms jātiek manuāli apstiprinātai. Lūdzu, izlasiet norādījumus pirms iesniegšanas. Jums vajadzēs GitHub kontu, lai sazinātos un veiktu izmaiņas, ja tādas būs pieprasītas, bet tas nav absolūti nepieciešams.","noteLicense":"Iesniedzot bibliotēku, jūs piekrītat tās publicēšanai saskaņā ar MIT Licenci, kas īsumā nozīmē, ka jebkurš to varēs izmantot bez ierobežojumiem.","noteItems":"Katram bibliotēkas vienumam jābūt savam nosaukumam, lai to varētu atrast filtrējot. Tiks iekļauti sekojošie bibliotēkas vienumi:","atleastOneLibItem":"Lūdzu, atlasiet vismaz vienu bibliotēkas vienumu, lai sāktu darbu","republishWarning":"Ievēro: daži no atzīmētajiem objektiem jau atzīmēti kā publicēti vai iesniegti publicēšanai. Tos vajadzētu atkārtoti iesniegt tikai tad, ja vēlies labot esošo bibliotēku."},"publishSuccessDialog":{"title":"Bibliotēka iesniegta","content":"Paldies, {{authorName}}! Jūsu bibliotēka iesniegta izskatīšanai. Jūs varat izsekot iesnieguma statusamšeit"},"confirmDialog":{"resetLibrary":"Atiestatīt bibliotēku","removeItemsFromLib":"Noņemt atlasītos vienumus no bibliotēkas"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"Jūsu zīmējumi ir šifrēti no gala līdz galam; līdz ar to Excalidraw serveri tos nekad neredzēs.","link":"Ieraksts par šifrēšanu no gala līdz galam Excalidraw blogā"},"stats":{"angle":"Leņķis","element":"Elements","elements":"Elementi","height":"Augstums","scene":"Aina","selected":"Atlasīti","storage":"Krātuve","title":"Statistika entuziastiem","total":"Kopā","version":"Versija","versionCopy":"Klikšķiniet, lai nokopētu","versionNotAvailable":"Versija nav pieejama","width":"Platums"},"toast":{"addedToLibrary":"Pievienots bibliotēkai","copyStyles":"Nokopēja stilus.","copyToClipboard":"Nokopēja starpliktuvē.","copyToClipboardAsPng":"Nokopēja {{exportSelection}} starpliktuvē kā PNG ({{exportColorScheme}})","fileSaved":"Datne saglabāta.","fileSavedToFilename":"Saglabāts kā {filename}","canvas":"tāfeli","selection":"atlasi","pasteAsSingleElement":"Izmantojiet {{shortcut}}, lai ielīmētu kā jaunu elementu, vai ielīmētu esošā teksta lauciņā","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Caurspīdīgs","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"Visi jūsu dati tiek glabāti uz vietas jūsu pārlūkā.","center_heading_plus":"Vai tā vietā vēlies doties uz Excalidraw+?","menuHint":"Eksportēšana, iestatījumi, valodas..."},"defaults":{"menuHint":"Eksportēšana, iestatījumi un vēl...","center_heading":"Diagrammas. Izveidotas. Vienkārši.","toolbarHint":"Izvēlies rīku un sāc zīmēt!","helpHint":"Īsceļi un palīdzība"}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/mr-IN-json-2949146743072eb11b40.js b/public/excalidraw/excalidraw-assets-dev/locales/mr-IN-json-2949146743072eb11b40.js
new file mode 100644
index 0000000..a146719
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/mr-IN-json-2949146743072eb11b40.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/mr-IN-json"],{
+
+/***/ "../../locales/mr-IN.json":
+/*!********************************!*\
+ !*** ../../locales/mr-IN.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"चिटकवा","pasteAsPlaintext":"साधा मजकूर च्या रुपात पेस्ट करा","pasteCharts":"चार्ट चिकटवा","selectAll":"समस्त निवडा","multiSelect":"निवडित तत्व जोडा","moveCanvas":"पटल हलवा","cut":"कापा","copy":"प्रतिलिपी","copyAsPng":"PNG रूपे फळी वर कॉपी करा","copyAsSvg":"SVG रूपे फळी वर कॉपी करा","copyText":"लिखित रूपे फळी वर कॉपी करा","bringForward":"पुढे पुढे आणा","sendToBack":"सर्वात मागे करा","bringToFront":"सर्वात पुढे आणा","sendBackward":"मागे मागे करा","delete":"हटवा","copyStyles":"शैली कॉपी करा","pasteStyles":"कॉपी केलेली शैली वापरा","stroke":"रेघे चा रंग","background":"पार्श्वभूमी","fill":"भरा","strokeWidth":"रेघ रुंदी","strokeStyle":"रेघ शैली","strokeStyle_solid":"भरीव","strokeStyle_dashed":"तुटित तुटित","strokeStyle_dotted":"ठिपके ठिपके","sloppiness":"गबाळेपणा","opacity":"अपारदर्शक्ता","textAlign":"मजकूर संरेखन","edges":"किनारी","sharp":"टोचरं","round":"गोलाकार","arrowheads":"बाण टोक","arrowhead_none":"कुठलाहि नाही","arrowhead_arrow":"बाण","arrowhead_bar":"दांडुक","arrowhead_dot":"ठिपका","arrowhead_triangle":"त्रिकोण","fontSize":"अक्षर आकार","fontFamily":"अक्षर समूह","addWatermark":"\\"एक्सकेलीड्रॉ ने बनवलेलं\\" जोडा","handDrawn":"हातानी बनवलेलं","normal":"सामान्य","code":"सांकेतिक लिपि","small":"छोटे","medium":"मध्यम","large":"मोठं","veryLarge":"फार मोठं","solid":"भरीव","hachure":"हैशूर रेखांकन","zigzag":"वाकडी तिकड़ी","crossHatch":"आडव्या रेघा","thin":"पातळ","bold":"जाड","left":"डावं","center":"मधे","right":"उजवं","extraBold":"जास्त जाड","architect":"वास्तुविद्याविशारद","artist":"कलाकार","cartoonist":"व्यंग्य चित्रकार","fileTitle":"फाईलचे नाव","colorPicker":"रंग निवडक","canvasColors":"कॅनवास वर वापरलेले","canvasBackground":"पटल पार्श्वभूमि","drawingCanvas":"चित्र पटल","layers":"स्तर","actions":"क्रिया","language":"भाषा","liveCollaboration":"ज्वलंत सहयोग...","duplicateSelection":"प्रतिलिपि","untitled":"अशीर्षकांकित","name":"नाव","yourName":"तुमचे नाव","madeWithExcalidraw":"एक्सकेलीड्रॉ ने बनवलेलं","group":"समूह निवड","ungroup":"समूह निवड ला रद्द करा","collaborators":"Sahayog","showGrid":"ग्रिड दाखवा","addToLibrary":"संग्रह मधे सम्मिलित करा","removeFromLibrary":"संग्रहातून काढ़ा","libraryLoadingMessage":"संग्रह लोड होत आहे…","libraries":"संग्रह देखे","loadingScene":"दृश्य लोड होत आहे…","align":"संरेखित करा","alignTop":"वर संरेखित करा","alignBottom":"खाली संरेखित करा","alignLeft":"डावा बाजूला संरेखित करा","alignRight":"उजव्या बाजूला संरेखित करा","centerVertically":"मधल्या मधे उभं संरेखित करा","centerHorizontally":"मधल्या मधे आडवं संरेखित करा","distributeHorizontally":"आडवं वितरित करा","distributeVertically":"उभं वितरित करा","flipHorizontal":"आडवं फ्लिप करा","flipVertical":"उभं फ्लिप करा","viewMode":"पहायची पद्धत","share":"सामायिक करा","showStroke":"रेघ रंग निवड यंत्र दाखवा","showBackground":"पार्श्वभूमि: रंग निवड यंत्र दाखवा","toggleTheme":"शैली बदला","personalLib":"वैयक्तिक संग्रह","excalidrawLib":"एक्सकेलीड्रॉ संग्रह","decreaseFontSize":"अक्षर आकार छोटा करा","increaseFontSize":"अक्षर आकार मोठा करा","unbindText":"लेखन संबंध संपवा","bindText":"शब्द समूह ला पात्रात घ्या","createContainerFromText":"मजकूर कंटेनर मधे मोडून दाखवा","link":{"edit":"दुवा संपादन","editEmbed":"","create":"दुवा तयार करा","createEmbed":"","label":"दुवा","labelEmbed":"","empty":""},"lineEditor":{"edit":"रेघ संपादन","exit":"रेघ संपादकाबाहेर"},"elementLock":{"lock":"कुलूपात ठेवा","unlock":"कुलूपातून बाहेर","lockAll":"सर्व कुलूपात ठेवा","unlockAll":"सर्व कुलूपातून बाहेर"},"statusPublished":"प्रकाशित करा","sidebarLock":"साइडबार उघडं ठेवा","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":"चित्रफलकातून रंग निवडा"},"library":{"noItems":"अजून कोणतेही आइटम जोडलेले नाही...","hint_emptyLibrary":"पटल वर एक वस्तु निवडुन एथे जोडा, किव्हा एक संग्रह जन कोष कडुन खाली स्थापित करा.","hint_emptyPrivateLibrary":"ईथे जोडण्या साठी पटल वरून एक वस्तु निवडा."},"buttons":{"clearReset":"पटल पुसा","exportJSON":"फ़ाइलमधे बाहेर ठेवा","exportImage":"प्रतिमा निर्यात करा...","export":"येथे सुरक्षित करा...","copyToClipboard":"फळी वर कॉपी करा","save":"वर्तमान फ़ाइल मधे जतन करा","saveAs":"ह्या नावाने जतन करा","load":"उघडा","getShareableLink":"सामायिके साठी दुवा प्राप्त करा","close":"बंद करा","selectLanguage":"भाषा निवड करा","scrollBackToContent":"पहलेचा मजकुर वर मागे स्क्रॉल करा","zoomIn":"मोठं करून पहा","zoomOut":"छोटं करून पहा","resetZoom":"छोटं मोठं करणं बंद करा","menu":"यादि","done":"झालं","edit":"संपादित करा","undo":"पूर्ववत करा","redo":"पुन्हा करा(&R)","resetLibrary":"संग्रह पुनर्स्थित करा","createNewRoom":"एक नवी खोली बनवा","fullScreen":"पूर्ण दृश्यपटल","darkMode":"अंधार स्थिथि","lightMode":"उजेड स्थिति","zenMode":"ध्यानग्र स्थिति","objectsSnapMode":"वस्तूंपासून पकड़ा","exitZenMode":"ध्यानग्र स्थितितून बाहेर","cancel":"रद्द","clear":"स्वछ","remove":"हटवा","embed":"","publishLibrary":"प्रकाशित करा","submit":"जमा करा","confirm":"पुष्टि करा","embeddableInteractionButton":""},"alerts":{"clearReset":"पटल स्वच्छ होणार, तुम्हाला खात्री आहे का?","couldNotCreateShareableLink":"सामायी करण करण्या योग्य दुवा नाही बनवता आला.","couldNotCreateShareableLinkTooBig":"सामायी करण करण्या योग्य दुवा नाही बनवता आला: दृश्य फार मोठं आहे","couldNotLoadInvalidFile":"अवैध फ़ाइल लोड करता आली नाही","importBackendFailed":"बैकएंड हून मागवणे विफल झाले.","cannotExportEmptyCanvas":"रिकामा पटल जतन करता येत नाही.","couldNotCopyToClipboard":"पटल वर कॉपी नाही झाली.","decryptFailed":"डीक्रिप्ट करता आले नाही.","uploadedSecurly":"अपलोड या टोकापासून त्या टोकापर्यंत कूटबद्धित करून सुरक्षित केले गेले आहे, हयाचा अर्थ असा की एक्सकेलीड्रॉ सर्व्हर आणि तृतीय पक्ष मजकूर वाचू शकत नाहीत.","loadSceneOverridePrompt":"बाह्य रेखाचित्र लोड केल्याने तुमची तुमचा विद्यमान मजकूर बदलेल. हे काम तुम्हाला चालू ठेवायचे आहे का?","collabStopOverridePrompt":"सत्र थांबवल्याने तुमचे पूर्वीचे, स्थानिकरित्या संग्रहित रेखाचित्र अधिलिखित होईल. तुला खात्री आहे?\\n\\n(तुम्हाला तुमचे स्थानिक रेखाचित्र ठेवायचे असल्यास, त्याऐवजी फक्त ब्राउझर टॅब बंद करा.)","errorAddingToLibrary":"संग्रहात तत्व जोडू शकलो नाही","errorRemovingFromLibrary":"संग्रहातून तत्व काढू शकलो नाही","confirmAddLibrary":"हे तुमच्या संग्राहात {{numShapes}} आकार (एक किव्हा अनेक) जोडेल. तुला खात्री आहे?","imageDoesNotContainScene":"या प्रतिमेमध्ये कोणताही दृश्य डेटा असल्याचे दिसत नाही. बाहेर जतन करताना तुम्ही दृश्य रुतवले होते का?","cannotRestoreFromImage":"प्रतिमा फ़ाइल पासून दृश्य पुनः रचित नाही झाला","invalidSceneUrl":"दिलेल्या यू-आर-एल पासून दृश्य आणू शकलो नाही. तो एकतर बरोबार नाही आहे किंवा त्यात वैध एक्सकेलीड्रॉ जेसन डेटा नाही.","resetLibrary":"पटल स्वच्छ होणार, तुम्हाला खात्री आहे का?","removeItemsFromsLibrary":"संग्रहातून {{count}} तत्व (एक किव्हा अनेक) काढू?","invalidEncryptionKey":"कूटबद्धन कुंजी 22 अक्षरांची असणे आवश्यक आहे. थेट सहयोग अक्षम केले आहे.","collabOfflineWarning":"इंटरनेट कनेक्शन उपलब्ध नाही.\\nतुमचे बदल जतन केले जाणार नाहीत!"},"errors":{"unsupportedFileType":"असमर्थित फाइल प्रकार.","imageInsertError":"प्रतिमा आत घालता येत नाही. नंतर पुन्हा प्रयत्न करा...","fileTooBig":"फाइल फार मोठी आहे. आकाराची कमाल परवानगी {{maxSize}} आहे.","svgImageInsertError":"एस-वी-जी प्रतिमा आत घालवू शकलो नाही. एस-वी-जी-मार्क-अप यंत्र अयोग्य आहे.","failedToFetchImage":"","invalidSVGString":"अयोग्य एस-वी-जी.","cannotResolveCollabServer":"कॉलेब-सर्वर हे पोहोचत नाही आहे. पान परत लोड करायचा प्रयत्न करावे.","importLibraryError":"संग्रह प्रतिस्थापित नाही करता आला","collabSaveFailed":"काही कारणा निमित्त आतल्या डेटाबेसमध्ये जतन करू शकत नाही। समस्या तशिस राहिल्यास, तुम्ही तुमचे काम गमावणार नाही याची खात्री करण्यासाठी तुम्ही तुमची फाइल स्थानिक जतन करावी.","collabSaveFailed_sizeExceeded":"लगता है कि पृष्ठ तल काफ़ी बड़ा है, इस्कारण अंदरूनी डेटाबेस में सहेजा नहीं जा सका। किये काम को खोने न देने के लिये अपनी फ़ाइल को स्थानीय रूप से सहेजे।\\n\\nबॅकएंड डेटाबेसमध्ये जतन करू शकत नाही, कॅनव्हास खूप मोठा असल्याचे दिसते. तुम्ही तुमचे काम गमावणार नाही याची खात्री करण्यासाठी तुम्ही फाइल स्थानिक पातळीवर जतन करावी.","brave_measure_text_error":{"line1":"असं वाटते की तुम्हीं Brave ब्राउज़र वापरतात आहात आणि त्या बरोबार आक्रामक पद्धति चें बोटांचे ठसे हां सेटिंग्स चा विकल्प चयन केलेला आहे.","line2":"हे तुमच्या चित्रांच्या पाठ तत्वांनां खंडित करू शकतात.","line3":"तुम्हाला आमच्या कड़ून खूप आग्रह आहे की हे सेटिंग्स मधले चयन नका करु. हे अनुक्रम हे कसे करावे हे दाखवु शकते.","line4":"ही सेटिंग अक्षम करूनही पृष्ठ योग्यरित्या प्रदर्शित होत नसल्यास, आमच्या GitHub वर समस्या सबमिट करा, किव्हा डिस्कॉर्ड वर आम्हाला लिहा"},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"निवड","image":"प्रतिमा आत घाला","rectangle":"आयत","diamond":"चौकोन आकाराचा","ellipse":"अंडाकार","arrow":"बाण","line":"रेखा","freedraw":"रेखांकित करा","text":"टेक्स्ट","library":"संग्रह","lock":"निवडलेले यंत्र चित्रकरण झाल्या नंतर ही सक्रिय ठेवा","penMode":"पेन चा मोड - स्पर्श टाळा","link":"निवडलेल्या आकारासाठी दुवा जोडा/बदल करा","eraser":"खोड रबर","frame":"","embeddable":"","laser":"लेसर टॉर्च","hand":"हात ( सरकवण्या चे उपकरण)","extraTools":""},"headings":{"canvasActions":"पटल क्रिया","selectedShapeActions":"निवडित आकार क्रिया","shapes":"आकार"},"hints":{"canvasPanning":"कॅनव्हास सरकवण्या साठी, ड्रॅग करताना माउस व्हील धरा किंवा स्पेसबार दाबून ठेवा अथवा हात वालं उपकरण वापरा","linearElement":"अनेक बिंदु साठी क्लिक करा, रेघे साठी ड्रैग करा","freeDraw":"क्लिक आणि ड्रैग करा, झालं तेव्हा सोडा","text":"टीप: तुम्हीं निवड यंत्रानी कोठेही दुहेरी क्लिक करून टेक्स्ट जोडू शकता","embeddable":"","text_selected":"लेखन संपादन साठी दुहेरी क्लिक करा किव्हा एंटर दाबा","text_editing":"संपादन संपवायचं असल्यास एस्केप दाबा किव्हा कंट्रोल या कम्मांड बरोबार एंटर दाबा","linearElementMulti":"शेवटच्या बिंदु वर क्लिक करा किव्हा एस्केप या एंटर दाबा","lockAngle":"शिफ्ट धरून तुम्ही कोन मर्यादित करू शकता","resize":"आकार छोटा मोठा करताना SHIFT धरून तुम्ही प्रमाण मर्यादित करू शकता, \\nकेंद्रापासून आकार छोटा मोठा करण्यासाठी ALT धरून ठेवा","resizeImage":"SHIFT धरून तुम्ही मुक्तपणे आकार मोठा छोटा करु शकता,\\nकेंद्रापासून आकार मोठा छोटा करण्यासाठी ALT धरून ठेवा","rotate":"फिरवत असताना शिफ्ट धरून तुम्ही कोन मर्यादित करू शकता","lineEditor_info":"पॉइंट संपादित करण्यासाठी CtrlOrCmd दाबून ठेवुन डबल-क्लिक करा किंवा CtrlOrCmd + Enter बरोबर दाबा","lineEditor_pointSelected":"बिंदु (एक किव्हा अनेक) काढ़ण्या साठी डिलीट की दाबा,\\nCtrlOrCmd बरोबार D प्रति साठी,\\nकिव्हा ड्रेग हलवण्या साठी","lineEditor_nothingSelected":"संपादित करण्यासाठी एक बिंदू निवडा (अनेक निवडण्यासाठी SHIFT धरून ठेवा),\\nकिंवा Alt धरून ठेवा आणि नवीन बिंदू जोडण्यासाठी क्लिक करा","placeImage":"प्रतिमा ठेवण्यासाठी क्लिक करा, किंवा त्याचा आकार बदलण्या साठी क्लिक करा आणि ड्रॅग करा","publishLibrary":"आपला खाजगी संग्रह प्रकाशित करा","bindTextToElement":"मजकूर जोडण्यासाठी एंटर की दाबा","deepBoxSelect":"खोल निवड ह्या साठी कंट्रोल किव्हा कमांड दाबून ठेवा, आणि बाहेर खेचणे वाचवण्या साठी पण","eraserRevert":"खोडण्या साठी घेतलेल्या वस्तु ना घेण्या साठी Alt दाबून ठेवावे","firefox_clipboard_write":"हे वैशिष्ट्य \\"dom.events.asyncClipboard.clipboardItem\\" फ्लॅग \\"सत्य\\" वर सेट करून शक्यतो सक्षम केले जाऊ शकते. Firefox मध्ये ब्राउझर फ्लॅग बदलण्यासाठी, \\"about:config\\" पृष्ठावर जा.","disableSnapping":"स्नैपिंग अक्षम करण्या साठी CtrlOrCmd दाबून ठेवा"},"canvasError":{"cannotShowPreview":"पूर्वावलोकन दाखवू शकत नाही","canvasTooBig":"पटल खूप जास्त मोठा असू शकतो.","canvasTooBigTip":"टीप: दूर चा तत्व थोडं जवळ आणण्याचा प्रयत्न करावा."},"errorSplash":{"headingMain":"त्रुटि आली. परत प्रयत्न करा ","clearCanvasMessage":"रीलोडिंग होत नसल्यास, परत प्रयत्न करा ","clearCanvasCaveat":" त्यामुळे केलेल्या कामाचे नुकसान होईल ","trackedToSentry":"त्रुटि क्रमांक के साथ त्रुटि {{eventId}} आमच्या प्रणाली नी निरीक्षण केले होते.","openIssueMessage":"त्रुटीत तुमची दृश्य माहिती समाविष्ट न करण्यासाठी आम्ही खूप सावध होतो. तुमचा सीन खाजगी नसल्यास, कृपया आम्हाला पुढ च्या कारवाई साठी सम्पर्क साधा कृपया गिटहब समस्येमध्ये कॉपी आणि पेस्ट करून खालिल माहिती समाविष्ट करा.","sceneContent":"दृश्य विषय:"},"roomDialog":{"desc_intro":"तुम्ही तुमच्या सध्याच्या दृश्यासाठी लोकांना आपल्यासह सहयोग करण्यासाठी आमंत्रित करू शकता.","desc_privacy":"काळजी करू नका, सत्र या टोकापासून त्या टोकापर्यंत कूटबद्धता वापरते, त्यामुळे तुम्ही जे काही काढाल ते खाजगी राहील. तुम्ही काय घेऊन आला आहात हे आमचा सर्व्हर ही देखील पाहू शकत नाही.","button_startSession":"सत्र सुरु करा","button_stopSession":"सत्र थाम्बवा","desc_inProgressIntro":"थेट सहयोग सत्र चालू आहे.","desc_shareLink":"तुम्ही ज्यांच्याशी सहयोग करू इच्छिता त्यांच्याशी ही दुवा सामायिक करा:","desc_exitSession":"सत्र थांबवल्याने तुम्हीं खोली तून बाहेर याल, तरिही तुम्ही स्थानिक पातळीवर दृश्यासह काम करु शकाल. लक्षात ठेवा की याचा इतर लोकांवर परिणाम होणार नाही आणि ते त्यांच्या आवृत्तीवर सहयोग करित राहातील.","shareTitle":"एक्सकेलीड्रॉ वर थेट सहयोग सत्रात सामील व्हा"},"errorDialog":{"title":"त्रुटि"},"exportDialog":{"disk_title":"डिस्क मधे जतन करा","disk_details":"सीन डेटा बाहेर एक फ़ाइल मधे जतन करा, त्या फ़ाइल मधुम तो डेटा नंतर परत आणु शकता.","disk_button":"फ़ाइल मधे जतन करा","link_title":"सामायिके साठी दुवा","link_details":"नुसतं वाचु देणारा दुवा चा स्वरूपे बाहेर ठेवा.","link_button":"दुवा स्वरूपे बाहेर ठेवा","excalidrawplus_description":"दृश्य तुमच्या एक्सकेलीड्रॉ कार्यक्षेत्र मधे जतन करा.","excalidrawplus_button":"बाहेर ठेवा","excalidrawplus_exportError":"एक्सकेलीड्रॉ मधे बाहेर ठेवता नाही येत..."},"helpDialog":{"blog":"आमचा ब्लॉग वाचा","click":"क्लिक करा","deepSelect":"खोल निवड","deepBoxSelect":"चौकट मधे खोल निवड करा आणि बाहेर ओढणे वाचवा","curvedArrow":"वक्र बाण","curvedLine":"वक्र रेघ","documentation":"कागदपत्रे","doubleClick":"दुहेरी क्लिक","drag":"ओढा","editor":"संपादक","editLineArrowPoints":"रेघ/तीर बिंदु सम्पादित करा","editText":"पाठ्य सम्पादित करा/ लेबल जोडा","github":"समस्या मिळाली? प्रस्तुत करा","howto":"आमच्या मार्गदर्शकाचे अनुसरण करा","or":"किंवा","preventBinding":"बाण बंधन होणं टाळा","tools":"अवजार","shortcuts":"कीबोर्ड शॉर्टकट","textFinish":"संपादन संपले (मजकूर संपादन)","textNewLine":"नवी ओळ जोडा (मजकूर संपादक)","title":"मदत","view":"दृश्य","zoomToFit":"सर्व तत्व दिसतील असे दृश्यरूप आकार करा","zoomToSelection":"निवडी प्रयंत दृश्यरूप आकार करा","toggleElementLock":"कुलूपातून आत/बाहेर निवड","movePageUpDown":"पान वर/खाली करा","movePageLeftRight":"पान डावी/उजवी कडे करा"},"clearCanvasDialog":{"title":"पटल स्वच्छ करा"},"publishDialog":{"title":"संग्रह प्रकाशित करा","itemName":"वस्तु चे नाव","authorName":"लेखक चे नाव","githubUsername":"गिटहब वापरकर्तानाव","twitterUsername":"ट्विटर वापरकर्तानाव","libraryName":"संग्रहाचे नाव","libraryDesc":"संग्रहाचे वर्णन","website":"वेबसाइट","placeholder":{"authorName":"तुमचे नाव किव्हा वापरकर्तानाव","libraryName":"तुमचा संग्रहाचे नाव","libraryDesc":"तुमचा संग्रहाचे वर्णन लोकांना संग्रहा बद्दल जाणकारी देतील","githubHandle":"गिटहब हैंडल (वैकल्पिक), एकदा संग्रह पुनरावलोकना साठी जमा केल्या नंतर ही तुम्हीं सम्पादित करु शकता","twitterHandle":"ट्विटर वापरकार्यक नाव (वैकल्पिक), त्यामुळे ट्विटर वर ज़हीरांति साठी कोणाला गुण द्यायचे हे आम्हाला समजेल","website":"दुवा तुमच्या वैयक्तिक वेब-साइट किव्हा कुठे दूसरिकडे (ऐच्छिक) करावा"},"errors":{"required":"आवश्यक आहे","website":"वैध यू-आर-एल द्या"},"noteDescription":"समाविष्ट करण्या साठी तुमचा संग्रह ह्याचात जमा करा सार्वजनिक संग्रहाचे कोठारइतर लोकांना त्यांच्या रेखाचित्रांमधे वापरण्यासाठी.","noteGuidelines":"संग्रहाला आधी स्वहस्ते स्वीकृती मिळणे आवश्यक आहे. कृपया हे वाचा मार्गदर्शक तत्त्वे जमा करण्या पूर्वी, तुमच्या जवळ एक गिटहब खाते असणे आवश्यक आहे जे संवादा साठी आणिक बदल करण्या साठी लागेल, तरी हे सर्व अगदी आवश्यक नाही आहे.","noteLicense":"जमा करताना तुम्हीं सहमति दाखवतात आहे की संग्रह ह्याचा खाली प्रकाशित होईल एम-आइ-टी परवाना, ज्याचा थोडक्यात अर्थ कोणीही निर्बंधांशिवाय वापरू शकतो.","noteItems":"प्रतैक संग्रहाचे नाव, नीट शोधनासाठी, असणे आवश्यक आहे. खाली दिलेल्या वस्तु समाविष्ट केल्या जातील:","atleastOneLibItem":"सुरु करण्यासाठी, कृपया करून, कमित कमी एक वस्तु तरी निवडा","republishWarning":"टीप: काही निवडक आयटम आधीच प्रकाशित/प्रस्तुत केलेले आहेत. विद्यमान लायब्ररी किंवा प्रस्तुतित आयटम अद्यावित करताना तुम्ही फक्त तो पुन्हा प्रस्तुत करा."},"publishSuccessDialog":{"title":"संग्रह जमा केला","content":"धन्यवाद {{authorName}}. आपला संग्रह पुनरावलोकना साठी जमा झाला आहे. तुम्हीं स्थिति सारखी तपासू सकताइकडे"},"confirmDialog":{"resetLibrary":"संग्रह पुनर्स्थित करा","removeItemsFromLib":"निवडलेले आयटम्स संग्रहातून काढा"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"तुमचे चित्रे या टोकापासून त्या टोकापर्यंत कूटबद्धतित आहेत, त्या कारणांनी ऐक्सकैलिड्रॉ सर्वर्स ह्यानां ते पहाणं कधीच जमणार नाही.","link":"ब्लॉग पोस्ट ऐक्सकैलिड्रॉ मधे या टोकापासून त्या टोकापर्यंत कूटबद्धतित आहेत"},"stats":{"angle":"कोण","element":"वस्तु","elements":"वस्तु","height":"उंची","scene":"दृश्य","selected":"निवडलेले","storage":"साठवण","title":"अभ्यासू लोगो के लिये आंकडे","total":"योग","version":"आवृत्ती","versionCopy":"कॉपी करायला क्लिक करा","versionNotAvailable":"आवृति उपलब्ध नाही","width":"रुंदी"},"toast":{"addedToLibrary":"संग्रह मधे सम्मिलित","copyStyles":"कॉपी केलेली शैली.","copyToClipboard":"फळी वर कॉपी झाली.","copyToClipboardAsPng":"{{exportSelection}} फळी वर पी-एन-जी स्वरूपात कॉपी झाली\\n({{exportColorScheme}})","fileSaved":"फ़ाइल जतन झाली.","fileSavedToFilename":"{filename} मधे जतन झाली","canvas":"पटल","selection":"निवड","pasteAsSingleElement":"एक घटक म्हणून चिपकावण्या साठी {{shortcut}} वापरा,\\nकिंवा विद्यमान मजकूर संपादकात चिपकवा","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"पारदर्शक","black":"काळा","white":"पांढरा","red":"लाल","pink":"गुलाबी","grape":"अंगूरी","violet":"जांभळा","gray":"राखाडी","blue":"निळा","cyan":"आकाशी","teal":"हिरवट निळा","green":"हिरवा","yellow":"पिवळा","orange":"केशरी","bronze":"कांस्य"},"welcomeScreen":{"app":{"center_heading":"तुमचा सर्व डेटा तुमच्या ब्राउझरमध्ये स्थानिक पातळीवर जतन केला जातो.","center_heading_plus":"त्याऐवजी तुम्हाला Excalidraw+ वर जायचे आहे का?","menuHint":"निर्यात, आवड़ी-निवडी, भाषा, ..."},"defaults":{"menuHint":"निर्यात, आवड़ी निवडी आणि आणकिही...","center_heading":"आकृत्या. काढणे. सोपे.","toolbarHint":"एक साधन निवडा आणि चित्रीकरण सुरु करा!","helpHint":"शॉर्टकट आणि सहाय्य"}},"colorPicker":{"mostUsedCustomColors":"सर्वात जास्त वापरणीस रंग","colors":"रंग","shades":"रंगछटा","hexCode":"हेक्स कोड","noShades":"ह्या रंगाच्या छटा उपलब्ध नाहित"},"overwriteConfirm":{"action":{"exportToImage":{"title":"छवि स्वरूपे निर्यात करा","button":"छवि स्वरूपे निर्यात करा","description":"सीन डेटा बाहेर एक फ़ाइल मधे जतन करा, त्या फ़ाइल मधुन तो डेटा नंतर परत आणु शकता."},"saveToDisk":{"title":"डिस्क मधे जतन करा","button":"डिस्क मधे जतन करा","description":"सीन डेटा बाहेर एक फ़ाइल मधे जतन करा, त्या फ़ाइल मधुन तो डेटा नंतर परत आणु शकता."},"excalidrawPlus":{"title":"एक्षकालीड्रॉ +","button":"एक्षकाली ड्रॉ+ मधे निर्यात करा","description":"दृष्य तुमच्या एक्षकालीड्रॉ+ चा कार्यस्थल मधे जतन करा."}},"modal":{"loadFromFile":{"title":"फ़ाइल मधुन लोड करा","button":"फ़ाइल मधुन लोड करा","description":"फ़ाइल मधुन लोड केल्या वर ते तुमचा सध्याचा कामा ठिकाणि एईल तुम्हीं तुमचं चित्र एकाधं खाली दिलेलं विकल्प निवडुन पहले सुरक्षीत करु शकता."},"shareableLink":{"title":"लिंक पासून लोड करा","button":"माझ सध्याचे कार्य बदला","description":"बाहरी चित्र लोड केल्या वर ते तुमचा सध्याचा कामा ठिकाणि एईल तुम्हीं तुमचं चित्र एकाधं खाली दिलेलं विकल्प निवडुन पहले सुरक्षीत करु शकता."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/my-MM-json-4c04ffe415641f69ed75.js b/public/excalidraw/excalidraw-assets-dev/locales/my-MM-json-4c04ffe415641f69ed75.js
new file mode 100644
index 0000000..4a577f6
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/my-MM-json-4c04ffe415641f69ed75.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/my-MM-json"],{
+
+/***/ "../../locales/my-MM.json":
+/*!********************************!*\
+ !*** ../../locales/my-MM.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"ထား","pasteAsPlaintext":"","pasteCharts":"","selectAll":"အကုန်ရွေး","multiSelect":"ရွေးထားသည့်ထဲပုံထည့်","moveCanvas":"ကားချပ်ရွှေ့","cut":"","copy":"ကူး","copyAsPng":"PNG အနေဖြင့်ကူး","copyAsSvg":"SVG အနေဖြင့်ကူး","copyText":"","bringForward":"ရှေ့ပို့","sendToBack":"နောက်ဆုံးထား","bringToFront":"ရှေ့ဆုံးထား","sendBackward":"နောက်ပို့","delete":"ဖျက်","copyStyles":"ပုံစံကူး","pasteStyles":"ပုံစံထား","stroke":"မျဉ်း","background":"နောက်ခံ","fill":"ဖြည့်","strokeWidth":"မျဉ်းအထူ","strokeStyle":"မျဉ်းပုံစံ","strokeStyle_solid":"အပြည့်","strokeStyle_dashed":"မျဉ်းပြတ်","strokeStyle_dotted":"မျဉ်းစက်","sloppiness":"သေသပ်မှု","opacity":"ထင်ရှားမှု","textAlign":"စာသားညှိ","edges":"အစွန်း","sharp":"ထောင့်ချွန်","round":"ထောင့်ဝိုင်း","arrowheads":"မြှားခေါင်း","arrowhead_none":"ဘာမျှမရှိ","arrowhead_arrow":"မြှား","arrowhead_bar":"","arrowhead_dot":"အစက်","arrowhead_triangle":"","fontSize":"စာလုံးအရွယ်","fontFamily":"စာလုံးပုံစံ","addWatermark":"\\"Excalidraw ဖြင့်ဖန်တီးသည်။\\" စာသားထည့်","handDrawn":"လက်ရေး","normal":"ပုံမှန်","code":"ကုဒ်","small":"အသေး","medium":"အလတ်","large":"အကြီး","veryLarge":"ပိုကြီး","solid":"အပြည့်","hachure":"မျဉ်းစောင်း","zigzag":"","crossHatch":"ဇကာကွက်","thin":"ပါး","bold":"ထူ","left":"ဘယ်","center":"အလယ်","right":"ညာ","extraBold":"ပိုထူ","architect":"ဗိသုကာ","artist":"ပန်းချီ","cartoonist":"ကာတွန်း","fileTitle":"","colorPicker":"အရောင်ရွေး","canvasColors":"","canvasBackground":"ကားချပ်နောက်ခံ","drawingCanvas":"ပုံဆွဲကားချပ်","layers":"အလွှာများ","actions":"လုပ်ဆောင်ချက်များ","language":"ဘာသာစကား","liveCollaboration":"","duplicateSelection":"ပွား","untitled":"အမည်မရှိ","name":"အမည်","yourName":"သင့်အမည်","madeWithExcalidraw":"Excalidraw ဖြင့်ဖန်တီးသည်။","group":"အုပ်စုဖွဲ့","ungroup":"အုပ်စုဖျက်သိမ်း","collaborators":"ပူးပေါင်းပါဝင်သူများ","showGrid":"","addToLibrary":"မှတ်တမ်းတင်","removeFromLibrary":"မှတ်တမ်းမှထုတ်","libraryLoadingMessage":"မှတ်တမ်းအား တင်သွင်းနေသည်…","libraries":"စာကြည့်တိုက်တွင်ရှာဖွေပါ","loadingScene":"မြင်ကွင်းဖော်နေသည်…","align":"ချိန်ညှိ","alignTop":"ထိပ်ညှိ","alignBottom":"အခြေညှိ","alignLeft":"ဘယ်ညှိ","alignRight":"ညာညှိ","centerVertically":"ဒေါင်လိုက်အလယ်ညှိ","centerHorizontally":"အလျားလိုက်အလယ်ညှိ","distributeHorizontally":"အလျားလိုက်","distributeVertically":"ထောင်လိုက်","flipHorizontal":"","flipVertical":"","viewMode":"","share":"","showStroke":"","showBackground":"","toggleTheme":"","personalLib":"","excalidrawLib":"","decreaseFontSize":"","increaseFontSize":"","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"","editEmbed":"","create":"","createEmbed":"","label":"","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"","unlock":"","lockAll":"","unlockAll":""},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"ကားချပ်ရှင်းလင်း","exportJSON":"","exportImage":"","export":"","copyToClipboard":"ကူးယူ","save":"","saveAs":"ပြောင်းသိမ်း","load":"","getShareableLink":"မျှဝေရန် လင့်ခ်ရယူ","close":"ပိတ်","selectLanguage":"ဘာသာစကားရွေးပါ","scrollBackToContent":"ကားချပ်ပြန်တည်","zoomIn":"ချဲ့","zoomOut":"ချုံ့","resetZoom":"ပုံမှန်ပြန်ထား","menu":"မီနူး","done":"ပြီးပြီ","edit":"ပြင်ဆင်","undo":"ပြန်ထား","redo":"ထပ်လုပ်","resetLibrary":"","createNewRoom":"အခန်းသစ်ဖွဲ့","fullScreen":"","darkMode":"","lightMode":"","zenMode":"","objectsSnapMode":"","exitZenMode":"ဇင်မြင်ကွင်းမှထွက်","cancel":"","clear":"","remove":"","embed":"","publishLibrary":"","submit":"","confirm":"","embeddableInteractionButton":""},"alerts":{"clearReset":"ကားချပ်တစ်ခုလုံးရှင်းလင်းပါတော့မည်။ အတည်ပြုပါ။","couldNotCreateShareableLink":"မျှဝေရန် လင့်ခ်မရယူနိုင်သေးပါ။","couldNotCreateShareableLinkTooBig":"မြင်ကွင်းအရမ်းကြီးနေသဖြင့် မျှဝေရန် လင့်ခ်မရယူနိုင်သေးပါ။","couldNotLoadInvalidFile":"လွဲမှားနေသောဖိုင်အား တင်၍မရပါ။","importBackendFailed":"Backend မှမလုပ်ဆောင်နိုင်သေးပါ။","cannotExportEmptyCanvas":"ကားချပ်အလွတ်အားထုတ်ယူ၍မရပါ။","couldNotCopyToClipboard":"","decryptFailed":"အချက်အလက်ဖော်ယူ၍မရပါ။","uploadedSecurly":"တင်သွင်းအချက်အလက်များအား နှစ်ဘက်စွန်းတိုင်လျှို့ဝှက်စနစ်အသုံးပြု၍လုံခြုံစွာထိန်းသိမ်းထားပါသဖြင့် Excalidraw ဆာဗာနှင့်ဆက်စပ်အဖွဲ့အစည်းများပင်လျှင်မဖတ်ရှုနိုင်ပါ။","loadSceneOverridePrompt":"လက်ရှိရေးဆွဲထားသမျှအား ပြင်ပမှတင်သွင်းသောပုံနှင့်အစားထိုးပါမည်။ ဆက်လက်ဆောင်ရွက်လိုပါသလား။","collabStopOverridePrompt":"","errorAddingToLibrary":"","errorRemovingFromLibrary":"","confirmAddLibrary":"{{numShapes}} ခုသောပုံသဏ္ဌာန်အားမှတ်တမ်းတင်ပါမည်။ အတည်ပြုပါ။","imageDoesNotContainScene":"","cannotRestoreFromImage":"ဤပုံဖြင့်မြင်ကွင်းပြန်လည်မရယူနိုင်ပါ။","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"","invalidEncryptionKey":"","collabOfflineWarning":""},"errors":{"unsupportedFileType":"","imageInsertError":"","fileTooBig":"","svgImageInsertError":"","failedToFetchImage":"","invalidSVGString":"","cannotResolveCollabServer":"","importLibraryError":"","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"ရွေးချယ်","image":"","rectangle":"စတုဂံ","diamond":"စိန်","ellipse":"အဝိုင်း","arrow":"မြှား","line":"မျဉ်း","freedraw":"","text":"စာသား","library":"မှတ်တမ်း","lock":"ရွေးချယ်ထားသောကိရိယာကိုသာဆက်သုံး","penMode":"","link":"","eraser":"","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"ကားချပ်လုပ်ဆောင်ချက်","selectedShapeActions":"ပုံသဏ္ဌာန်လုပ်ဆောင်ချက်","shapes":"ပုံသဏ္ဌာန်များ"},"hints":{"canvasPanning":"","linearElement":"အမှတ်များချမှတ်ရေးဆွဲရန်ကလစ်နှိပ်ပါ၊ မျဉ်းတစ်ကြောင်းတည်းအတွက် တရွတ်ဆွဲပါ။","freeDraw":"ကလစ်နှိပ်၍ တရွတ်ဆွဲပါ၊ ပြီးလျှင်လွှတ်ပါ။","text":"မှတ်ချက်။ ။မည်သည့်ကိရိယာရွေးထားသည်ဖြစ်စေ ကလစ်နှစ်ချက်နှိပ်၍စာသားထည့်နိုင်သည်","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"နောက်ဆုံးအမှတ်ပေါ်တွင်ကလစ်နှိပ်ခြင်း၊ Escape (သို့) Enter နှိပ်ခြင်းတို့ဖြင့်အဆုံးသတ်နိုင်","lockAngle":"","resize":"အချိုးအစားကန့်သတ်ရန် Shift နှင့် ဗဟိုမှချိန်ညှိရန် Alt တို့ကိုနှိပ်ထားနိုင်သည်","resizeImage":"","rotate":"Shift ကိုနှိပ်ထားခြင်းဖြင့် ထောင့်အလိုက်လှည့်နိုင်သည်","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"နမူနာမပြသနိုင်ပါ","canvasTooBig":"ကားချပ်အလွန်ကြီးကောင်းကြီးနေနိုင်သည်။","canvasTooBigTip":"မှတ်ချက်။ ။ဝေးကွာနေသော ပုံများ၊ စာများအား ပိုမိုနီးကပ်အောင်ရွှေ့ကြည့်ပါ။"},"errorSplash":{"headingMain":"ချို့ယွင်းမှုဖြစ်ပေါ်ခဲ့သဖြင့် ထပ်မံကြိုးစားကြည့်ရန် ","clearCanvasMessage":"အသစ်ပြန်လည်မရယူနိုင်ပါက ထပ်မံကြိုးစားကြည့်ရန်","clearCanvasCaveat":" ရေးဆွဲထားသည်များ ဆုံးရှုံးနိုင်သည် ","trackedToSentry":"ချို့ယွင်းမှုသတ်မှတ်ချက် {{eventId}} အားစနစ်အတွင်းခြေရာကောက်ပြီးပါပြီ။","openIssueMessage":"ချို့ယွင်းမှုမှတ်တမ်းတွင် အရေးကြီးအချက်အလက်များပါဝင်မှုမရှိစေရန်အထူးသတိပြုပါသည်။ မပါဝင်ပါက ဆက်လက်ဆောင်ရွက်ရန် အောက်ပါအချက်အလက်များအား Github တွင် Issue အနေဖြင့်ဖြည့်သွင်းဖော်ပြပေးပါ။","sceneContent":"မြင်ကွင်းပါအချက်အလက်။ ။"},"roomDialog":{"desc_intro":"လက်ရှိမြင်ကွင်းတွင်ပူးပေါင်းရေးဆွဲရန် အခြားသူများအား ဖိတ်ကြားနိုင်သည်။","desc_privacy":"နှစ်ဘက်စွန်းတိုင်လျှို့ဝှက်ထားသဖြင့်ရေးဆွဲသမျှအား ဆာဗာပေါ်မှပင်လျှင်ကြည့်ရှုနိုင်မည်မဟုတ်ပါ။ မစိုးရိမ်ပါနှင့်။","button_startSession":"ပူးပေါင်းမှုစတင်","button_stopSession":"ပူးပေါင်းမှုအဆုံးသတ်","desc_inProgressIntro":"တိုက်ရိုက်ပူးပေါင်းရေးဆွဲမှုများပြုလုပ်နေပါသည်။","desc_shareLink":"ဤလင့်ခ်အား ပူးပေါင်းရေးဆွဲလိုသူများထံပေးပို့ပါ။ ။ ","desc_exitSession":"ပူးပေါင်းမှုရပ်တန့်ပါက အဖွဲ့အတွင်းမှထွက်ခွာသွားမည်ဖြစ်သော်လည်း မိမိမြင်ကွင်းတွင်ဆက်လက်ရေးဆွဲနိုင်ပါမည်။ အဖွဲ့အတွင်းကျန်ရှိနေခဲ့သောအခြားပါဝင်သူများသည်လည်း ဆက်လက်ပူးပေါင်းရေးဆွဲနေနိုင်ပါလိမ့်မည်။","shareTitle":""},"errorDialog":{"title":"ချို့ယွင်းချက်"},"exportDialog":{"disk_title":"","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"","excalidrawplus_exportError":""},"helpDialog":{"blog":"","click":"","deepSelect":"","deepBoxSelect":"","curvedArrow":"","curvedLine":"","documentation":"","doubleClick":"","drag":"","editor":"","editLineArrowPoints":"","editText":"","github":"","howto":"","or":"","preventBinding":"","tools":"","shortcuts":"","textFinish":"","textNewLine":"","title":"","view":"","zoomToFit":"","zoomToSelection":"","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"","githubUsername":"","twitterUsername":"","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"ရေးဆွဲထားသောပုံများအား နှစ်ဘက်စွန်းတိုင်လျှို့ဝှက်ထားသဖြင့် Excalidraw ၏ဆာဗာများပင်လျှင်မြင်တွေ့ရမည်မဟုတ်ပါ။","link":""},"stats":{"angle":"ထောင့်","element":"","elements":"","height":"အမြင့်","scene":"မြင်ကွင်း","selected":"ရွေးချယ်သည်","storage":"သိုလှောင်ခန်း","title":"အက္ခရာများအတွက်အချက်အလက်များ","total":"စုစုပေါင်း","version":"","versionCopy":"","versionNotAvailable":"","width":"အကျယ်"},"toast":{"addedToLibrary":"","copyStyles":"","copyToClipboard":"","copyToClipboardAsPng":"","fileSaved":"","fileSavedToFilename":"","canvas":"","selection":"","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/nb-NO-json-b8d7a5b70562dacdad45.js b/public/excalidraw/excalidraw-assets-dev/locales/nb-NO-json-b8d7a5b70562dacdad45.js
new file mode 100644
index 0000000..c0c3208
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/nb-NO-json-b8d7a5b70562dacdad45.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/nb-NO-json"],{
+
+/***/ "../../locales/nb-NO.json":
+/*!********************************!*\
+ !*** ../../locales/nb-NO.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Lim inn","pasteAsPlaintext":"Lim inn som klartekst","pasteCharts":"Lim inn diagrammer","selectAll":"Velg alt","multiSelect":"Legg til element i utvalg","moveCanvas":"Flytt lerretet","cut":"Klipp ut","copy":"Kopier","copyAsPng":"Kopier til PNG","copyAsSvg":"Kopier til utklippstavlen som SVG","copyText":"Kopier til utklippstavlen som tekst","bringForward":"Flytt framover","sendToBack":"Send bakerst","bringToFront":"Flytt forrest","sendBackward":"Send bakover","delete":"Slett","copyStyles":"Kopier stiler","pasteStyles":"Lim inn stiler","stroke":"Strek","background":"Bakgrunn","fill":"Fyll","strokeWidth":"Strektykkelse","strokeStyle":"Strekstil","strokeStyle_solid":"Heltrukket","strokeStyle_dashed":"Stiplet","strokeStyle_dotted":"Prikket","sloppiness":"Ujevnhet","opacity":"Synlighet","textAlign":"Tekstjustering","edges":"Kanter","sharp":"Skarp","round":"Rund","arrowheads":"Pilspisser","arrowhead_none":"Ingen","arrowhead_arrow":"Pil","arrowhead_bar":"Søyle","arrowhead_dot":"Prikk","arrowhead_triangle":"Trekant","fontSize":"Skriftstørrelse","fontFamily":"Fontfamilie","addWatermark":"Legg til \\"Laget med Excalidraw\\"","handDrawn":"Håndtegnet","normal":"Normal","code":"Kode","small":"Liten","medium":"Medium","large":"Stor","veryLarge":"Svært stor","solid":"Helfarge","hachure":"Skravert","zigzag":"Sikk-sakk","crossHatch":"Krysskravert","thin":"Tynn","bold":"Tykk","left":"Venstre","center":"Midtstill","right":"Høyre","extraBold":"Ekstra tykk","architect":"Arkitekt","artist":"Kunstner","cartoonist":"Tegner","fileTitle":"Filnavn","colorPicker":"Fargevelger","canvasColors":"Brukes på lerretet","canvasBackground":"Lerretsbakgrunn","drawingCanvas":"Lerret","layers":"Lag","actions":"Handlinger","language":"Språk","liveCollaboration":"Sanntids-samarbeid...","duplicateSelection":"Dupliser","untitled":"Uten navn","name":"Navn","yourName":"Ditt navn","madeWithExcalidraw":"Laget med Excalidraw","group":"Gruppér utvalg","ungroup":"Avgruppér utvalg","collaborators":"Samarbeidspartnere","showGrid":"Vis rutenett","addToLibrary":"Legg til i bibliotek","removeFromLibrary":"Fjern fra bibliotek","libraryLoadingMessage":"Laster bibliotek…","libraries":"Bla gjennom biblioteker","loadingScene":"Laster inn scene…","align":"Juster","alignTop":"Juster øverst","alignBottom":"Juster nederst","alignLeft":"Juster venstre","alignRight":"Juster høyre","centerVertically":"Midtstill vertikalt","centerHorizontally":"Midtstill horisontalt","distributeHorizontally":"Distribuer horisontalt","distributeVertically":"Distribuer vertikalt","flipHorizontal":"Snu horisontalt","flipVertical":"Snu vertikalt","viewMode":"Visningsmodus","share":"Del","showStroke":"Vis fargevelger for kantfarge","showBackground":"Vis fargevelger for bakgrunnsfarge","toggleTheme":"Veksle tema","personalLib":"Personlig bibliotek","excalidrawLib":"Excalidraw-bibliotek","decreaseFontSize":"Reduser skriftstørrelse","increaseFontSize":"Øk skriftstørrelse","unbindText":"Avbind tekst","bindText":"Bind tekst til beholderen","createContainerFromText":"La tekst flyte i en beholder","link":{"edit":"Rediger lenke","editEmbed":"Rediger lenke og bygg inn","create":"Opprett lenke","createEmbed":"Opprett lenke og bygg inn","label":"Lenke","labelEmbed":"Lenk & bygg inn","empty":"Ingen lenke er valgt"},"lineEditor":{"edit":"Rediger linje","exit":"Avslutt linjeredigering"},"elementLock":{"lock":"Lås","unlock":"Lås opp","lockAll":"Lås alle","unlockAll":"Lås opp alle"},"statusPublished":"Publisert","sidebarLock":"Holde sidemenyen åpen","selectAllElementsInFrame":"Velg alle elementene i rammen","removeAllElementsFromFrame":"Fjern alle elementer fra rammen","eyeDropper":"Velg farge fra lerretet"},"library":{"noItems":"Ingen elementer lagt til ennå...","hint_emptyLibrary":"Velg et objekt på lerretet for å legge det til her, eller installer et bibliotek fra den offentlige samlingen under.","hint_emptyPrivateLibrary":"Velg et objekt på lerretet for å legge det til her."},"buttons":{"clearReset":"Tøm lerretet og tilbakestill bakgrunnsfargen","exportJSON":"Eksporter til fil","exportImage":"Eksporter bilde...","export":"Lagre som...","copyToClipboard":"Kopier til utklippstavle","save":"Lagre til aktiv fil","saveAs":"Lagre som","load":"Åpne","getShareableLink":"Få delingslenke","close":"Lukk","selectLanguage":"Velg språk","scrollBackToContent":"Skroll tilbake til innhold","zoomIn":"Zoom inn","zoomOut":"Zoom ut","resetZoom":"Nullstill zoom","menu":"Meny","done":"Ferdig","edit":"Rediger","undo":"Angre","redo":"Gjør om","resetLibrary":"Nullstill bibliotek","createNewRoom":"Opprett et nytt rom","fullScreen":"Fullskjerm","darkMode":"Mørk modus","lightMode":"Lys modus","zenMode":"Zen-modus","objectsSnapMode":"","exitZenMode":"Avslutt zen-modus","cancel":"Avbryt","clear":"Tøm","remove":"Fjern","embed":"Slå av/på innebygging","publishLibrary":"Publiser","submit":"Send inn","confirm":"Bekreft","embeddableInteractionButton":"Klikk for å samhandle"},"alerts":{"clearReset":"Dette vil tømme lerretet. Er du sikker?","couldNotCreateShareableLink":"Kunne ikke lage delbar lenke.","couldNotCreateShareableLinkTooBig":"Kunne ikke opprette lenke til deling: scenen er for stor","couldNotLoadInvalidFile":"Kunne ikke laste inn ugyldig fil","importBackendFailed":"Importering av backend feilet.","cannotExportEmptyCanvas":"Kan ikke eksportere et tomt lerret.","couldNotCopyToClipboard":"Kunne ikke kopiere til utklippstavlen.","decryptFailed":"Kunne ikke dekryptere data.","uploadedSecurly":"Opplastingen er kryptert og kan ikke leses av Excalidraw-serveren eller tredjeparter.","loadSceneOverridePrompt":"Å laste inn ekstern tegning vil erstatte det eksisterende innholdet. Ønsker du å fortsette?","collabStopOverridePrompt":"Hvis du slutter økten, overskrives din forrige, lokalt lagrede tegning. Er du sikker?\\n\\n(Hvis du ønsker å beholde din lokale tegning, bare lukk nettleserfanen i stedet.)","errorAddingToLibrary":"Kunne ikke legge element i biblioteket","errorRemovingFromLibrary":"Kunne ikke fjerne element fra biblioteket","confirmAddLibrary":"Dette vil legge til {{numShapes}} figur(er) i biblioteket ditt. Er du sikker?","imageDoesNotContainScene":"Det ser ikke ut til at dette bildet inneholder noen scenedata. Har du aktivert innebygging av scene under eksporten?","cannotRestoreFromImage":"Scenen kunne ikke gjenopprettes fra denne bildefilen","invalidSceneUrl":"Kunne ikke importere scene fra den oppgitte URL-en. Den er enten ødelagt, eller inneholder ikke gyldig Excalidraw JSON-data.","resetLibrary":"Dette vil tømme biblioteket ditt. Er du sikker?","removeItemsFromsLibrary":"Slett {{count}} element(er) fra biblioteket?","invalidEncryptionKey":"Krypteringsnøkkel må ha 22 tegn. Live-samarbeid er deaktivert.","collabOfflineWarning":"Ingen Internett-tilkobling tilgjengelig.\\nEndringer dine vil ikke bli lagret!"},"errors":{"unsupportedFileType":"Filtypen støttes ikke.","imageInsertError":"Kunne ikke sette inn bildet. Prøv igjen senere...","fileTooBig":"Filen er for stor. Maksimal tillatt størrelse er {{maxSize}}.","svgImageInsertError":"Kunne ikke sette inn SVG-bilde. SVG-koden ser ugyldig ut.","failedToFetchImage":"","invalidSVGString":"Ugyldig SVG.","cannotResolveCollabServer":"Kunne ikke koble til samarbeidsserveren. Vennligst oppdater siden og prøv på nytt.","importLibraryError":"Kunne ikke laste bibliotek","collabSaveFailed":"Kan ikke lagre i backend-databasen. Hvis problemer vedvarer, bør du lagre filen lokalt for å sikre at du ikke mister arbeidet.","collabSaveFailed_sizeExceeded":"Kunne ikke lagre til backend-databasen, lerretet ser ut til å være for stort. Du bør lagre filen lokalt for å sikre at du ikke mister arbeidet ditt.","brave_measure_text_error":{"line1":"Ser ut som om du bruker Brave nettleser med Aggressivt Block Finger -innstillingen aktivert.","line2":"Dette kan resultere i å bryte tekst-elementene i tegningene.","line3":"Vi anbefaler på det sterkeste å deaktivere denne innstillingen. Du kan følge disse trinnene om hvordan du gjør det.","line4":"Hvis deaktivering av denne innstillingen ikke fikser visningen av tekstelementer, vennligst åpne en sak på vår GitHub, eller skriv oss på Discord"},"libraryElementTypeError":{"embeddable":"Innebygde elementer kan ikke legges til i biblioteket.","image":"Støtte for å legge til bilder i biblioteket kommer snart!"}},"toolBar":{"selection":"Velg","image":"Sett inn bilde","rectangle":"Rektangel","diamond":"Diamant","ellipse":"Ellipse","arrow":"Pil","line":"Linje","freedraw":"Tegn","text":"Tekst","library":"Bibliotek","lock":"Behold merket verktøy som aktivt","penMode":"Pennemodus - forhindre berøring","link":"Legg til / oppdater link for en valgt figur","eraser":"Viskelær","frame":"Rammeverktøy","embeddable":"Nettinnbygging","laser":"","hand":"Hånd (panoreringsverktøy)","extraTools":"Flere verktøy"},"headings":{"canvasActions":"Handlinger: lerret","selectedShapeActions":"Handlinger: valgt objekt","shapes":"Former"},"hints":{"canvasPanning":"For å flytte lerretet, hold musehjulet eller mellomromstasten mens du drar, eller bruk hånd-verktøyet","linearElement":"Klikk for å starte linje med flere punkter, eller dra for en enkel linje","freeDraw":"Klikk og dra, slipp når du er ferdig","text":"Tips: du kan også legge til tekst ved å dobbeltklikke hvor som helst med utvalgsverktøyet","embeddable":"Klikk og dra for å opprette en nettside innebygd","text_selected":"Dobbeltklikk eller trykk ENTER for å redigere tekst","text_editing":"Trykk Escape eller Ctrl/Cmd+Enter for å fullføre redigering","linearElementMulti":"Klikk på siste punkt eller trykk Escape eller Enter for å fullføre","lockAngle":"Du kan låse vinkelen ved å holde nede SHIFT","resize":"Du kan beholde forholdet ved å trykke SHIFT mens du endrer størrelse,\\ntrykk ALT for å endre størrelsen fra midten","resizeImage":"Du kan endre størrelse fritt ved å holde SHIFT,\\nhold ALT for å endre størrelse fra midten","rotate":"Du kan låse vinklene ved å holde SHIFT mens du roterer","lineEditor_info":"Hold Ctrl/Cmd og dobbelklikk eller trykk Ctrl/Cmd + Enter for å endre punkter","lineEditor_pointSelected":"Trykk på Slett for å fjerne punktet, Ctrl / Cmd+D for å duplisere, eller dra for å flytte","lineEditor_nothingSelected":"Velg et punkt å redigere (hold SHIFT for å velge flere),\\neller hold Alt og klikk for å legge til nye punkter","placeImage":"Klikk for å plassere bildet, eller klikk og dra for å angi størrelsen manuelt","publishLibrary":"Publiser ditt eget bibliotek","bindTextToElement":"Trykk Enter for å legge til tekst","deepBoxSelect":"Hold CTRL/CMD for å markere dypt og forhindre flytting","eraserRevert":"Hold Alt for å reversere elementene merket for sletting","firefox_clipboard_write":"Denne funksjonen kan sannsynligvis aktiveres ved å sette \\"dom.events.asyncClipboard.clipboardItem\\" flagget til \\"true\\". For å endre nettleserens flagg i Firefox, besøk \\"about:config\\"-siden.","disableSnapping":""},"canvasError":{"cannotShowPreview":"Kan ikke vise forhåndsvisning","canvasTooBig":"Lerretet kan være for stort.","canvasTooBigTip":"Tips: Prøv å flytte de ytterste elementene litt tettere sammen."},"errorSplash":{"headingMain":"En feil oppsto. Prøv ","clearCanvasMessage":"Om ny sidelasting ikke fungerer, prøv ","clearCanvasCaveat":" Dette vil føre til tap av arbeid ","trackedToSentry":"Feilen med identifikator {{eventId}} ble logget i vårt system.","openIssueMessage":"Vi er veldig nøye med å ikke inkludere dine scene-opplysninger i feilen. Hvis din scene ikke er privat, vurder å følge opp i vårt Ta med opplysningene nedenfor ved å kopiere og lime inn i GitHub-saken.","sceneContent":"Scene-innhold:"},"roomDialog":{"desc_intro":"Du kan invitere personer til scenen din for å samarbeide med deg.","desc_privacy":"Ta det med ro, sesjonen bruker ende-til-ende-kryptering, så alt du tegner forblir privat. Ikke en gang serveren vår kan se hva du lager.","button_startSession":"Start økt","button_stopSession":"Stopp sesjon","desc_inProgressIntro":"Sanntids-samarbeidsøkt er nå i gang.","desc_shareLink":"Del denne linken med de du vil samarbeide med:","desc_exitSession":"Dersom du avslutter sesjonen blir du frakoblet rommet, men du kan fortsette å arbeide med scenen lokalt. Vær oppmerksom på at dette ikke vil påvirke andre personer, og de vil fortsatt ha mulighet til å samarbeide på deres versjon.","shareTitle":"Bli med i en live samarbeidsøkt på Excalidraw"},"errorDialog":{"title":"Feil"},"exportDialog":{"disk_title":"Lagre til disk","disk_details":"Eksporter scene-dataene til en fil som du kan importere fra senere.","disk_button":"Lagre til fil","link_title":"Delbar lenke","link_details":"Eksporter som en skrivebeskyttet lenke.","link_button":"Eksporter til lenke","excalidrawplus_description":"Lagre scenen til ditt Excalidraw+ arbeidsområde.","excalidrawplus_button":"Eksporter","excalidrawplus_exportError":"Kunne ikke eksportere til Excalidraw+ for øyeblikket..."},"helpDialog":{"blog":"Les bloggen vår","click":"klikk","deepSelect":"Marker dypt","deepBoxSelect":"Marker dypt innad i boks og forhindre flytting","curvedArrow":"Buet pil","curvedLine":"Buet linje","documentation":"Dokumentasjon","doubleClick":"dobbeltklikk","drag":"dra","editor":"Redigeringsvisning","editLineArrowPoints":"Rediger linje/pilpunkter","editText":"Rediger tekst / legg til etikett","github":"Funnet et problem? Send inn","howto":"Følg våre veiledninger","or":"eller","preventBinding":"Forhindre pilbinding","tools":"Verktøy","shortcuts":"Tastatursnarveier","textFinish":"Fullfør redigering (teksteditor)","textNewLine":"Legg til ny linje (teksteditor)","title":"Hjelp","view":"Vis","zoomToFit":"Zoom for å se alle elementer","zoomToSelection":"Zoom til utvalg","toggleElementLock":"Lås/lås opp utvalg","movePageUpDown":"Flytt side opp/ned","movePageLeftRight":"Flytt siden til venstre/høyre"},"clearCanvasDialog":{"title":"Tøm lerret"},"publishDialog":{"title":"Publiser bibliotek","itemName":"Elementnavn","authorName":"Forfatterens navn","githubUsername":"GitHub-brukernavnet","twitterUsername":"Twitter-brukernavn","libraryName":"Biblioteknavn","libraryDesc":"Beskrivelse av bibliotek","website":"Nettsted","placeholder":{"authorName":"Ditt navn eller brukernavn","libraryName":"Navnet på biblioteket ditt","libraryDesc":"Beskrivelse av biblioteket ditt for å hjelpe folk med å forstå bruken","githubHandle":"Github-brukernavn (valgfritt), slik at du kan redigere biblioteket når du har sendt inn for gjennomgang","twitterHandle":"Twitter-brukernavn (valgfritt), slik at vi vet hvem vi skal kreditere når promotert på Twitter","website":"Lenke til din personlige nettside eller et annet sted (valgfritt)"},"errors":{"required":"Påkrevd","website":"Angi en gyldig nettadresse"},"noteDescription":"Send inn biblioteket ditt som skal inkluderes i kildekode for offentlig bibliotekfor andre å bruke dem i tegninger.","noteGuidelines":"Biblioteket må godkjennes manuelt først. Les retningslinjene før innsending. Du vil trenge en GitHub-konto for å kommunisere og gjøre endringer hvis ønsket, men det er ikke påkrevd.","noteLicense":"Ved å sende inn godtar du at biblioteket blir publisert under MIT-lisens, som kortfattet betyr at andre kan bruke dem uten begrensninger.","noteItems":"Hvert bibliotek må ha sitt eget navn, så det er filtrerbart. Følgende bibliotekselementer vil bli inkludert:","atleastOneLibItem":"Vennligst velg minst ett bibliotek for å komme i gang","republishWarning":"Merk: noen av de valgte elementene er merket som allerede publisert/sendt. Du bør kun sende inn elementer på nytt når du oppdaterer et eksisterende bibliotek eller innlevering."},"publishSuccessDialog":{"title":"Bibliotek innsendt","content":"Takk {{authorName}}. Ditt bibliotek har blitt sendt inn for gjennomgang. Du kan spore statusenher"},"confirmDialog":{"resetLibrary":"Nullstill bibliotek","removeItemsFromLib":"Fjern valgte elementer fra bibliotek"},"imageExportDialog":{"header":"Eksporter bilde","label":{"withBackground":"Bakgrunn","onlySelected":"Kun valgte","darkMode":"Mørk modus","embedScene":"Bygg inn scene","scale":"Skalering","padding":"Avstand"},"tooltip":{"embedScene":"Scenedata vil bli lagret i den eksporterte PNG/SVG-filen, slik at scenen kan gjenopprettes fra den.\\nDet vil øke den eksporterte filstørrelsen."},"title":{"exportToPng":"Eksporter til PNG","exportToSvg":"Eksporter til SVG","copyPngToClipboard":"Kopier PNG til utklippstavlen"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Kopier til utklippstavle"}},"encrypted":{"tooltip":"Dine tegninger er ende-til-ende-krypterte slik at Excalidraw sine servere aldri vil se dem.","link":"Blogginnlegg om ende-til-ende-kryptering i Excalidraw"},"stats":{"angle":"Vinkel","element":"Element","elements":"Elementer","height":"Høyde","scene":"Scene","selected":"Valgt","storage":"Lagring","title":"Statistikk for nerder","total":"Totalt","version":"Versjon","versionCopy":"Klikk for å kopiere","versionNotAvailable":"Versjon ikke tilgjengelig","width":"Bredde"},"toast":{"addedToLibrary":"Lagt til i biblioteket","copyStyles":"Kopierte stiler.","copyToClipboard":"Kopiert til utklippstavlen.","copyToClipboardAsPng":"Kopierte {{exportSelection}} til utklippstavlen som PNG\\n({{exportColorScheme}})","fileSaved":"Fil lagret.","fileSavedToFilename":"Lagret til {filename}","canvas":"lerret","selection":"utvalg","pasteAsSingleElement":"Bruk {{shortcut}} for å lime inn som ett enkelt element,\\neller lim inn i en eksisterende tekstbehandler","unableToEmbed":"Innbygging av denne nettadressen er ikke tillatt. Oppret en sak på GitHub for å be om url-hvitelisting","unrecognizedLinkFormat":"Linken du bygget inn samsvarer ikke med det forventede formatet. Prøv å lime inn \\"bygg inn\\"-strengen fra kildesiden"},"colors":{"transparent":"Gjennomsiktig","black":"Svart","white":"Hvit","red":"Rød","pink":"Rosa","grape":"Drue","violet":"Fiolett","gray":"Grå","blue":"Blå","cyan":"Turkis","teal":"Blågrønn","green":"Grønn","yellow":"Gul","orange":"Oransje","bronze":"Bronse"},"welcomeScreen":{"app":{"center_heading":"Alle dine data lagres lokalt i din nettleser.","center_heading_plus":"Ønsker du å gå til Excalidraw+ i stedet?","menuHint":"Eksporter, innstillinger, språk, ..."},"defaults":{"menuHint":"Eksporter, innstillinger og mer...","center_heading":"Diagrammer. Gjort. Enkelt.","toolbarHint":"Velg et verktøy og start å tegne!","helpHint":"Snarveier & hjelp"}},"colorPicker":{"mostUsedCustomColors":"Mest brukte egendefinerte farger","colors":"Farger","shades":"Toner","hexCode":"Heksadesimal kode","noShades":"Ingen toner tilgjengelig for denne fargen"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Eksporter som bilde","button":"Eksporter som bilde","description":"Eksporter scene-dataene til en fil som du kan importere fra senere."},"saveToDisk":{"title":"Lagre til disk","button":"Lagre til disk","description":"Eksporter scene-dataene til en fil som du kan importere fra senere."},"excalidrawPlus":{"title":"Excalidraw+","button":"Eksporter til Excalidraw+","description":"Lagre scenen til ditt Excalidraw+-arbeidsområde."}},"modal":{"loadFromFile":{"title":"Last inn fra fil","button":"Last inn fra fil","description":"Å laste fra en fil vil erstatte ditt eksisterende innhold. Du kan sikkerhetskopiere tegningen din først ved å bruke en av valgene under."},"shareableLink":{"title":"Last inn fra lenke","button":"Erstatt innholdet mitt","description":"Lasting av ekstern tegning vil erstatte ditt eksisterende innhold. Du kan sikkerhetskopiere tegningen din først ved å bruke en av valgene nedenfor."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/nl-NL-json-a65f82a25fe038c45d35.js b/public/excalidraw/excalidraw-assets-dev/locales/nl-NL-json-a65f82a25fe038c45d35.js
new file mode 100644
index 0000000..3add9d4
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/nl-NL-json-a65f82a25fe038c45d35.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/nl-NL-json"],{
+
+/***/ "../../locales/nl-NL.json":
+/*!********************************!*\
+ !*** ../../locales/nl-NL.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Plakken","pasteAsPlaintext":"Plakken als platte tekst","pasteCharts":"Plak grafieken","selectAll":"Alles selecteren","multiSelect":"Voeg element toe aan selectie","moveCanvas":"Canvas verplaatsen","cut":"Knip","copy":"Kopiëren","copyAsPng":"Kopieer als PNG","copyAsSvg":"Kopieer naar klembord als SVG","copyText":"Kopieer naar klembord als tekst","bringForward":"Breng naar voren","sendToBack":"Stuur naar achtergrond","bringToFront":"Breng naar voorgrond","sendBackward":"Breng naar achter","delete":"Verwijderen","copyStyles":"Kopieer opmaak","pasteStyles":"Plak opmaak","stroke":"Lijn","background":"Achtergrond","fill":"Invulling","strokeWidth":"Lijnbreedte","strokeStyle":"Lijnstijl","strokeStyle_solid":"Ononderbroken","strokeStyle_dashed":"Gestreept","strokeStyle_dotted":"Gestippeld","sloppiness":"Slordigheid","opacity":"Doorzichtigheid","textAlign":"Uitlijning","edges":"Randen","sharp":"Hoekig","round":"Rond","arrowheads":"Pijlpunten","arrowhead_none":"Geen","arrowhead_arrow":"Pijl","arrowhead_bar":"Balk","arrowhead_dot":"Punt","arrowhead_triangle":"Driehoek","fontSize":"Tekstgrootte","fontFamily":"Lettertype","addWatermark":"Voeg \\"Gemaakt met Excalidraw\\" toe","handDrawn":"Handgetekend","normal":"Normaal","code":"Code","small":"Klein","medium":"Medium","large":"Groot","veryLarge":"Zeer groot","solid":"Ingekleurd","hachure":"Arcering","zigzag":"","crossHatch":"Tweemaal gearceerd","thin":"Dun","bold":"Vet","left":"Links","center":"Midden","right":"Rechts","extraBold":"Zwaar","architect":"Architect","artist":"Artiest","cartoonist":"Cartoonist","fileTitle":"Bestandsnaam","colorPicker":"Kleurenkiezer","canvasColors":"Gebruikt op canvas","canvasBackground":"Canvas achtergrond","drawingCanvas":"Canvas","layers":"Lagen","actions":"Acties","language":"Taal","liveCollaboration":"Live Samenwerking...","duplicateSelection":"Dupliceer","untitled":"Naamloos","name":"Naam","yourName":"Jouw naam","madeWithExcalidraw":"Gemaakt met Excalidraw","group":"Groeperen","ungroup":"Groep opheffen","collaborators":"Deelnemers","showGrid":"Raster weergeven","addToLibrary":"Voeg toe aan bibliotheek","removeFromLibrary":"Verwijder uit bibliotheek","libraryLoadingMessage":"Bibliotheek laden…","libraries":"Blader door bibliotheken","loadingScene":"Scène laden…","align":"Uitlijnen","alignTop":"Boven uitlijnen","alignBottom":"Onder uitlijnen","alignLeft":"Links uitlijnen","alignRight":"Rechts uitlijnen","centerVertically":"Verticaal Centreren","centerHorizontally":"Horizontaal Centreren","distributeHorizontally":"Horizontaal verspreiden","distributeVertically":"Verticaal distribueren","flipHorizontal":"Horizontaal spiegelen","flipVertical":"Verticaal spiegelen","viewMode":"Weergavemodus","share":"Deel","showStroke":"Toon lijn kleur kiezer","showBackground":"Toon achtergrondkleur kiezer","toggleTheme":"Thema aan/uit","personalLib":"Persoonlijke bibliotheek","excalidrawLib":"Excalidraw bibliotheek","decreaseFontSize":"Letters verkleinen","increaseFontSize":"Letters vergroten","unbindText":"Ontkoppel tekst","bindText":"Koppel tekst aan de container","createContainerFromText":"","link":{"edit":"Wijzig link","editEmbed":"Link bewerken & insluiten","create":"Maak link","createEmbed":"Link maken en insluiten","label":"Link","labelEmbed":"Link toevoegen & insluiten","empty":"Er is geen link ingesteld"},"lineEditor":{"edit":"Bewerk regel","exit":"Verlaat regel-editor"},"elementLock":{"lock":"Vergrendel","unlock":"Ontgrendel","lockAll":"Vergrendel alles","unlockAll":"Ontgrendel alles"},"statusPublished":"Gepubliceerd","sidebarLock":"Zijbalk open houden","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Nog geen items toegevoegd...","hint_emptyLibrary":"Selecteer een item op het canvas om het hier toe te voegen of installeer een bibliotheek uit de openbare repository, hieronder.","hint_emptyPrivateLibrary":"Selecteer een item op het canvas om het hier toe te voegen."},"buttons":{"clearReset":"Canvas opnieuw instellen","exportJSON":"Exporteren naar bestand","exportImage":"Exporteer afbeelding...","export":"Sla op...","copyToClipboard":"Kopieer","save":"Opslaan naar huidige bestand","saveAs":"Opslaan als","load":"Open","getShareableLink":"Maak een deelbare link","close":"Sluiten","selectLanguage":"Taal selecteren","scrollBackToContent":"Scroll terug naar inhoud","zoomIn":"Inzoomen","zoomOut":"Uitzoomen","resetZoom":"Zoom terugzetten","menu":"Menu","done":"Klaar","edit":"Bewerken","undo":"Ongedaan maken","redo":"Herstel ongedaan maken","resetLibrary":"Bibliotheek Resetten","createNewRoom":"Creëer live-samenwerkingssessie","fullScreen":"Volledig scherm","darkMode":"Donkere modus","lightMode":"Lichte modus","zenMode":"Zen modus","objectsSnapMode":"","exitZenMode":"Verlaat zen modus","cancel":"Annuleren","clear":"Wissen","remove":"Verwijderen","embed":"Insluiten in-/uitschakelen","publishLibrary":"Publiceren","submit":"Versturen","confirm":"Bevestigen","embeddableInteractionButton":"Klik voor interactie"},"alerts":{"clearReset":"Dit zal het hele canvas verwijderen. Weet je het zeker?","couldNotCreateShareableLink":"Kon geen deelbare link aanmaken.","couldNotCreateShareableLinkTooBig":"Kan geen deelbare link aanmaken: de scène is te groot","couldNotLoadInvalidFile":"Kan ongeldig bestand niet laden","importBackendFailed":"Importeren vanuit backend mislukt.","cannotExportEmptyCanvas":"Kan geen leeg canvas exporteren.","couldNotCopyToClipboard":"Kon niet naar klembord kopiëren.","decryptFailed":"Kan gegevens niet decoderen.","uploadedSecurly":"De upload is beveiligd met end-to-end encryptie, wat betekent dat de Excalidraw server en derden de inhoud niet kunnen lezen.","loadSceneOverridePrompt":"Het inladen van een externe tekening zal je bestaande inhoud vervangen. Wil je verdergaan?","collabStopOverridePrompt":"Wanneer de sessie wordt gestopt, overschrijft u de eerdere, lokaal opgeslagen tekening. Weet je het zeker?\\n\\n(Als je de lokale tekening wilt behouden, sluit je in plaats daarvan het browsertabblad)","errorAddingToLibrary":"Kan item niet toevoegen aan de bibliotheek","errorRemovingFromLibrary":"Kan item niet uit de bibliotheek verwijderen","confirmAddLibrary":"Dit zal {{numShapes}} vorm(en) toevoegen aan je bibliotheek. Weet je het zeker?","imageDoesNotContainScene":"Deze afbeelding lijkt geen scène gegevens te bevatten. Heb je scène embedding tijdens het exporteren ingeschakeld?","cannotRestoreFromImage":"Scène kan niet worden hersteld vanuit dit afbeeldingsbestand","invalidSceneUrl":"Kan scène niet importeren vanuit de opgegeven URL. Het is onjuist of bevat geen geldige Excalidraw JSON-gegevens.","resetLibrary":"Dit zal je bibliotheek wissen. Weet je het zeker?","removeItemsFromsLibrary":"Verwijder {{count}} item(s) uit bibliotheek?","invalidEncryptionKey":"Encryptiesleutel moet 22 tekens zijn. Live samenwerking is uitgeschakeld.","collabOfflineWarning":"Geen internetverbinding beschikbaar.\\nJe wijzigingen worden niet opgeslagen!"},"errors":{"unsupportedFileType":"Niet-ondersteund bestandstype.","imageInsertError":"Afbeelding invoegen mislukt. Probeer het later opnieuw...","fileTooBig":"Bestand is te groot. Maximale grootte is {{maxSize}}.","svgImageInsertError":"Kon geen SVG-afbeelding invoegen. De SVG-opmaak ziet er niet geldig uit.","failedToFetchImage":"","invalidSVGString":"Ongeldige SVG.","cannotResolveCollabServer":"Kan geen verbinding maken met de collab server. Herlaad de pagina en probeer het opnieuw.","importLibraryError":"Kon bibliotheek niet laden","collabSaveFailed":"Kan niet opslaan in de backend database. Als de problemen blijven bestaan, moet u het bestand lokaal opslaan om ervoor te zorgen dat u uw werk niet verliest.","collabSaveFailed_sizeExceeded":"Kan de backend database niet opslaan, het canvas lijkt te groot te zijn. U moet het bestand lokaal opslaan om ervoor te zorgen dat u uw werk niet verliest.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"Ingesloten elementen kunnen niet worden toegevoegd aan de bibliotheek.","image":"Ondersteuning voor het toevoegen van afbeeldingen aan de bibliotheek komt binnenkort!"}},"toolBar":{"selection":"Selectie","image":"Voeg afbeelding in","rectangle":"Rechthoek","diamond":"Ruit","ellipse":"Ovaal","arrow":"Pijl","line":"Lijn","freedraw":"Teken","text":"Tekst","library":"Bibliotheek","lock":"Geselecteerde tool actief houden na tekenen","penMode":"Pen modus - Blokkeer aanraken","link":"Link toevoegen / bijwerken voor een geselecteerde vorm","eraser":"Gum","frame":"","embeddable":"Web insluiten","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"Canvasacties","selectedShapeActions":"Acties van geselecteerde vorm","shapes":"Vormen"},"hints":{"canvasPanning":"Om de canvas te verplaatsen, houd muiswiel of spatiebalk ingedrukt tijdens slepen, of gebruik het handgereedschap","linearElement":"Klik om meerdere punten te starten, sleep voor één lijn","freeDraw":"Klik en sleep, laat los als je klaar bent","text":"Tip: je kunt tekst toevoegen door ergens dubbel te klikken met de selectietool","embeddable":"Klink-sleep om een website-insluiting te maken","text_selected":"Dubbelklik of druk op ENTER om tekst te bewerken","text_editing":"Druk op Escape of CtrlOrCmd+ENTER om het bewerken te voltooien","linearElementMulti":"Klik op het laatste punt of druk op Escape of Enter om te stoppen","lockAngle":"Je kunt de hoek beperken door SHIFT ingedrukt te houden","resize":"Houd tijdens het vergroten SHIFT ingedrukt om verhoudingen te behouden,\\ngebruik ALT om vanuit het midden te vergroten/verkleinen","resizeImage":"","rotate":"Je kan hoeken beperken door SHIFT ingedrukt te houden wanneer je draait","lineEditor_info":"Houd CtrlOrCmd en Dubbelklik of druk op CtrlOrCmd + Enter om punten te bewerken","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"Publiceer je eigen bibliotheek","bindTextToElement":"Druk op enter om tekst toe te voegen","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"Kan voorbeeld niet tonen","canvasTooBig":"Het canvas is mogelijk te groot.","canvasTooBigTip":"Tip: beweeg de verste elementen iets dichter bij elkaar."},"errorSplash":{"headingMain":"Fout opgetreden. Probeer ","clearCanvasMessage":"Als herladen niet werkt, probeer ","clearCanvasCaveat":" Dit zal leiden tot verlies van je werk ","trackedToSentry":"De fout met ID {{eventId}} was gevolgd op ons systeem.","openIssueMessage":"We waren voorzichtig om je scène-informatie niet in de fout toe te voegen. Als je scène niet privé is, overweeg dan alstublieft het opvolgen op onze Kopieer de informatie hieronder naar de GitHub issue.","sceneContent":"Scène-inhoud:"},"roomDialog":{"desc_intro":"Je kunt mensen uitnodigen om met je samen te werken.","desc_privacy":"Geen zorgen, de sessie gebruikt end-to-end encryptie, dus wat je tekent blijft privé. Zelfs onze server zal niet kunnen zien wat je tekent.","button_startSession":"Start sessie","button_stopSession":"Stop sessie","desc_inProgressIntro":"De live-samenwerkingssessie is nu gestart.","desc_shareLink":"Deel deze link met iedereen waarmee je wil samenwerken:","desc_exitSession":"Het stoppen van de sessie zal je loskoppelen van de kamer, maar je kunt lokaal doorwerken met de scène.\\nPas op: dit heeft geen invloed op andere mensen en dat zij nog steeds in staat zullen zijn om samen te werken aan hun versie.","shareTitle":"Neem deel aan een live samenwerkingssessie op Excalidraw"},"errorDialog":{"title":"Fout"},"exportDialog":{"disk_title":"Opslaan op schijf","disk_details":"De scènegegevens exporteren naar een bestand waaruit u later kunt importeren.","disk_button":"Opslaan naar bestand","link_title":"Deelbare link","link_details":"Exporteren als een alleen-lezen link.","link_button":"Exporteer naar link","excalidrawplus_description":"Sla de scène op in je Excalidraw+ werkruimte.","excalidrawplus_button":"Exporteer","excalidrawplus_exportError":"Kan op dit moment niet exporteren naar Excalidraw+..."},"helpDialog":{"blog":"Lees onze blog","click":"klik","deepSelect":"Deep selecteer","deepBoxSelect":"","curvedArrow":"Gebogen pijl","curvedLine":"Kromme lijn","documentation":"Documentatie","doubleClick":"dubbelklikken","drag":"slepen","editor":"Editor","editLineArrowPoints":"","editText":"","github":"Probleem gevonden? Verzenden","howto":"Volg onze handleidingen","or":"of","preventBinding":"Pijlbinding voorkomen","tools":"Tools","shortcuts":"Sneltoetsen","textFinish":"Voltooi het bewerken (teksteditor)","textNewLine":"Nieuwe regel toevoegen (teksteditor)","title":"Help","view":"Weergave","zoomToFit":"Zoom in op alle elementen","zoomToSelection":"Inzoomen op selectie","toggleElementLock":"","movePageUpDown":"Pagina omhoog/omlaag","movePageLeftRight":"Verplaats pagina links/rechts"},"clearCanvasDialog":{"title":"Wis canvas"},"publishDialog":{"title":"Publiceer bibliotheek","itemName":"Itemnaam","authorName":"Naam auteur","githubUsername":"GitHub gebruikersnaam","twitterUsername":"Twitter gebruikersnaam","libraryName":"Naam bibliotheek","libraryDesc":"Beschrijving van de bibliotheek","website":"Website","placeholder":{"authorName":"Je naam of gebruikersnaam","libraryName":"Naam van je bibliotheek","libraryDesc":"Beschrijving van je bibliotheek om mensen te helpen het gebruik ervan te begrijpen","githubHandle":"","twitterHandle":"","website":"Link naar je persoonlijke website of elders (optioneel)"},"errors":{"required":"Vereist","website":"Vul een geldige URL in"},"noteDescription":"openbare repository","noteGuidelines":"richtlijnen","noteLicense":"MIT-licentie, ","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"Bibliotheek ingediend","content":"Hier"},"confirmDialog":{"resetLibrary":"Reset bibliotheek","removeItemsFromLib":"Verwijder geselecteerde items uit bibliotheek"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"Je tekeningen zijn beveiligd met end-to-end encryptie, dus Excalidraw\'s servers zullen nooit zien wat je tekent.","link":"Blog post over end-to-end versleuteling in Excalidraw"},"stats":{"angle":"Hoek","element":"Element","elements":"Elementen","height":"Hoogte","scene":"Scene","selected":"Geselecteerd","storage":"Opslag","title":"Statistieken voor nerds","total":"Totaal","version":"Versie","versionCopy":"Klik om te kopiëren","versionNotAvailable":"Versie niet beschikbaar","width":"Breedte"},"toast":{"addedToLibrary":"Toegevoegd aan bibliotheek","copyStyles":"Stijlen gekopieerd.","copyToClipboard":"Gekopieerd naar het klembord.","copyToClipboardAsPng":"{{exportSelection}} naar klembord gekopieerd als PNG\\n({{exportColorScheme}})","fileSaved":"Bestand opgeslagen.","fileSavedToFilename":"Opgeslagen als {filename}","canvas":"canvas","selection":"selectie","pasteAsSingleElement":"Gebruik {{shortcut}} om te plakken als een enkel element,\\nof plak in een bestaande teksteditor","unableToEmbed":"Het insluiten van deze url is momenteel niet toegestaan. Zet een probleem op GitHub om de URL op de whitelist te zetten","unrecognizedLinkFormat":"De link die u hebt ingesloten komt niet overeen met het verwachte formaat. Probeer de \'embed\' string van de bronsite te plakken"},"colors":{"transparent":"Transparant","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"Exporteren, voorkeuren en meer...","center_heading":"Diagrammen. Eenvoudig. Gemaakt.","toolbarHint":"Kies een tool & begin met tekenen!","helpHint":"Snelkoppelingen en hulp"}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/nn-NO-json-858fbccbc5be386977db.js b/public/excalidraw/excalidraw-assets-dev/locales/nn-NO-json-858fbccbc5be386977db.js
new file mode 100644
index 0000000..fdf465d
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/nn-NO-json-858fbccbc5be386977db.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/nn-NO-json"],{
+
+/***/ "../../locales/nn-NO.json":
+/*!********************************!*\
+ !*** ../../locales/nn-NO.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Lim inn","pasteAsPlaintext":"","pasteCharts":"Lim inn diagram","selectAll":"Vel alt","multiSelect":"Legg til element i utval","moveCanvas":"Flytt lerretet","cut":"Klipp ut","copy":"Kopier","copyAsPng":"Kopier til utklippstavla som PNG","copyAsSvg":"Kopier til utklippstavla som SVG","copyText":"","bringForward":"Flytt framover","sendToBack":"Send heilt bak","bringToFront":"Flytt heilt fram","sendBackward":"Send bakover","delete":"Slett","copyStyles":"Kopier stilar","pasteStyles":"Lim inn stilar","stroke":"Strek","background":"Bakgrunn","fill":"Fyll","strokeWidth":"Strekbreidd","strokeStyle":"Strekstil","strokeStyle_solid":"Solid","strokeStyle_dashed":"Stipla","strokeStyle_dotted":"Prikka","sloppiness":"Ujamnheit","opacity":"Synlegheit","textAlign":"Tekstjustering","edges":"Kanter","sharp":"Skarp","round":"Rund","arrowheads":"Pilhovud","arrowhead_none":"Ingen","arrowhead_arrow":"Pil","arrowhead_bar":"Stolpe","arrowhead_dot":"Prikk","arrowhead_triangle":"Trekant","fontSize":"Skriftstorleik","fontFamily":"Skrifttype","addWatermark":"Legg til «Laga med Excalidraw»","handDrawn":"Handteikna","normal":"Normal","code":"Kode","small":"Liten","medium":"Medium","large":"Stor","veryLarge":"Svært stor","solid":"Solid","hachure":"Skravert","zigzag":"","crossHatch":"Krysskravert","thin":"Tynn","bold":"Tjukk","left":"Venstre","center":"Midstill","right":"Høgre","extraBold":"Ekstra tjukk","architect":"Arkitekt","artist":"Kunstnar","cartoonist":"Teiknar","fileTitle":"Filnamn","colorPicker":"Fargeveljar","canvasColors":"Brukt på lerretet","canvasBackground":"Lerretsbakgrunn","drawingCanvas":"Lerret","layers":"Lag","actions":"Handlingar","language":"Språk","liveCollaboration":"","duplicateSelection":"Dupliser","untitled":"Utan namn","name":"Namn","yourName":"Namnet ditt","madeWithExcalidraw":"Laga med Excalidraw","group":"Grupper utval","ungroup":"Avgrupper utval","collaborators":"Samarbeidarar","showGrid":"Vis rutenett","addToLibrary":"Legg til i bibliotek","removeFromLibrary":"Fjern frå bibliotek","libraryLoadingMessage":"Laster bibliotek…","libraries":"Blad gjennom bibliotek","loadingScene":"Laster scene…","align":"Juster","alignTop":"Juster til topp","alignBottom":"Juster til botn","alignLeft":"Juster til venstre","alignRight":"Juster til høgre","centerVertically":"Midtstill vertikalt","centerHorizontally":"Midtstill horisontalt","distributeHorizontally":"Sprei horisontalt","distributeVertically":"Sprei vertikalt","flipHorizontal":"Vipp vassrett","flipVertical":"Vipp loddrett","viewMode":"Visningsmodus","share":"Del","showStroke":"Vis fargeveljar for linjer","showBackground":"Vis fargeveljar for bakgrunn","toggleTheme":"Veksle tema","personalLib":"Personleg bibliotek","excalidrawLib":"Excalidraw-bibliotek","decreaseFontSize":"Gjer skriftstorleik mindre","increaseFontSize":"Gjer skriftstorleik større","unbindText":"Avbind tekst","bindText":"","createContainerFromText":"","link":{"edit":"Rediger lenke","editEmbed":"","create":"Lag lenke","createEmbed":"","label":"Lenke","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"","unlock":"","lockAll":"","unlockAll":""},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"Tilbakestill lerretet","exportJSON":"Eksporter til fil","exportImage":"","export":"","copyToClipboard":"Kopier til utklippstavla","save":"Lagre til noverande fil","saveAs":"Lagre som","load":"","getShareableLink":"Hent delingslenke","close":"Lukk","selectLanguage":"Vel språk","scrollBackToContent":"Skroll tilbake til innhald","zoomIn":"Zoom inn","zoomOut":"Zoom ut","resetZoom":"Nullstill zoom","menu":"Meny","done":"Ferdig","edit":"Rediger","undo":"Angre","redo":"Gjer om","resetLibrary":"Nullstill bibliotek","createNewRoom":"Lag nytt rom","fullScreen":"Fullskjerm","darkMode":"Mørk modus","lightMode":"Lys modus","zenMode":"Zen-modus","objectsSnapMode":"","exitZenMode":"Avslutt zen-modus","cancel":"Avbryt","clear":"Tøm","remove":"Fjern","embed":"","publishLibrary":"Publiser","submit":"Send inn","confirm":"Stadfest","embeddableInteractionButton":""},"alerts":{"clearReset":"Dette vil tømme lerretet. Er du sikker?","couldNotCreateShareableLink":"Kunne ikkje lage delingslenke.","couldNotCreateShareableLinkTooBig":"Kunne ikkje opprette deleleg lenke: scena er for stor","couldNotLoadInvalidFile":"Kunne ikkje laste inn ugyldig fil","importBackendFailed":"Importering av backend feila.","cannotExportEmptyCanvas":"Kan ikkje eksportere eit tomt lerret.","couldNotCopyToClipboard":"","decryptFailed":"Kunne ikkje dekryptere data.","uploadedSecurly":"Opplastinga er kryptert og er ikkje mogleg å lese av Excalidraw-serveren eller tredjepartar.","loadSceneOverridePrompt":"Innlasting av ekstern teikning erstattar ditt eksisterande innhald. Ynskjer du å fortsette?","collabStopOverridePrompt":"Viss du avsluttar økta overskriv du den førre, lokalt lagra teikninga di. Er du sikker?\\n\\n(Ønsker du å halde fram med denne? Då er det berre å lukke denne fana.)","errorAddingToLibrary":"Kunne ikkje legge elementet i biblioteket","errorRemovingFromLibrary":"Kunne ikkje fjerne elementet frå biblioteket","confirmAddLibrary":"Dette vil legge til {{numShapes}} form(er) i biblioteket ditt. Er du sikker?","imageDoesNotContainScene":"Dette biletet ser ikkje ut til å ha noko scenedata. Har du skrutt på innbygging av scene medan eksporteringa heldt på?","cannotRestoreFromImage":"Scena kunne ikkje gjenopprettast frå denne biletfila","invalidSceneUrl":"Kunne ikkje hente noko scene frå den URL-en. Ho er anten øydelagd eller inneheld ikkje gyldig Excalidraw JSON-data.","resetLibrary":"Dette vil fjerne alt innhald frå biblioteket. Er du sikker?","removeItemsFromsLibrary":"Slette {{count}} element frå biblioteket?","invalidEncryptionKey":"Krypteringsnøkkelen må ha 22 teikn. Sanntidssamarbeid er deaktivert.","collabOfflineWarning":""},"errors":{"unsupportedFileType":"Filtypen er ikkje støtta.","imageInsertError":"Kunne ikkje sette inn biletet. Prøv igjen seinare...","fileTooBig":"Fila er for stor. Maksimal tillate storleik er {{maxSize}}.","svgImageInsertError":"Kunne ikkje sette inn SVG-biletet. SVG-koden ser ugyldig ut.","failedToFetchImage":"","invalidSVGString":"Ugyldig SVG.","cannotResolveCollabServer":"Kunne ikkje kople til samarbeidsserveren. Ver vennleg å oppdatere inn sida og prøv på nytt.","importLibraryError":"","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Vel","image":"Sett in bilete","rectangle":"Rektangel","diamond":"Diamant","ellipse":"Ellipse","arrow":"Pil","line":"Linje","freedraw":"Teikn","text":"Tekst","library":"Bibliotek","lock":"Hald fram med valt verktøy","penMode":"","link":"Legg til/ oppdater lenke til valt figur","eraser":"Viskelêr","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"Handlingar: lerret","selectedShapeActions":"Handlingar: valt objekt","shapes":"Formar"},"hints":{"canvasPanning":"","linearElement":"Klikk for å starte linje med fleire punkt, eller drag for ei enkel linje","freeDraw":"Klikk og drag, slepp når du er ferdig","text":"Tips: du kan òg leggje til tekst ved å dobbeltklikke kor som helst med utvalgsverktyet","embeddable":"","text_selected":"Dobbelklikk eller trykk ENTER for å redigere teksta","text_editing":"Trykk Escape eller CtrlOrCmd+ENTER for å fullføre redigeringa","linearElementMulti":"Klikk på siste punkt eller trykk Escape eller Enter for å fullføre","lockAngle":"Du kan begrense vinkelen ved å holde nede SKIFT","resize":"Du kan halde fram med forholdet ved å trykke SHIFT medan du endrar storleik,\\ntrykk ALT for å endre storleiken frå midten","resizeImage":"Du kan endre storleiken fritt ved å halde inne SHIFT,\\nhald ALT for å endre storleik frå sentrum","rotate":"Du kan låse vinklane ved å halde SHIFT medan du roterer","lineEditor_info":"","lineEditor_pointSelected":"Trykk på Slett for å fjerne punkt(a),\\nCtrl / Cmd+D for å duplisere, eller drag for å flytte","lineEditor_nothingSelected":"Vel eit punkt å redigere (hald inne SHIFT for å velje fleire),\\neller hald inne Alt og klikk for å legge til nye punkt","placeImage":"Klikk for å plassere biletet, eller klikk og drag for å velje storleik manuelt","publishLibrary":"Publiser ditt eige bibliotek","bindTextToElement":"Trykk på enter for å legge til tekst","deepBoxSelect":"Hald inne Ctrl / Cmd for å velje djupt, og forhindre flytting","eraserRevert":"Hald inne Alt for å reversere markering av element for sletting","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"Kan ikkje vise førehandsvising","canvasTooBig":"Lerretet er mogleg for stort.","canvasTooBigTip":"Tips: prøv å flytte elementa som er lengst frå kvarandre, litt nærare kvarandre."},"errorSplash":{"headingMain":"Ein feil oppstod. Prøv ","clearCanvasMessage":"Om ny sidelasting ikkje fungerer, prøv ","clearCanvasCaveat":" Dette vil føre til tap av arbeid ","trackedToSentry":"Feilen med identifikator {{eventId}} vart logga i systemet vårt.","openIssueMessage":"Vi er veldig nøye med å ikkje inkludere scene-opplysingane dine i feilmeldinga. Viss scena di ikkje er privat kan du vurdere å følge opp i Ta med opplysingane nedanfor ved å kopiere og lime inn i GitHub-saka.","sceneContent":"Scene-innhald:"},"roomDialog":{"desc_intro":"Du kan invitere personar til scena di for å samarbeide med deg.","desc_privacy":"Ta det med ro; økta brukar ende-til-ende-kryptering, så alt du teiknar held fram med å vere privat. Ikkje ein gong serveren vår kan sjå kva du lagar.","button_startSession":"Start økt","button_stopSession":"Stopp økt","desc_inProgressIntro":"Sanntids-samarbeidsøkt er no i gang.","desc_shareLink":"Del denne lenka med dei du vil samarbeide med:","desc_exitSession":"Dersom du avsluttar økta blir du kopla frå rommet, men du kan halde fram med å arbeide med scena lokalt. Ver merksam på at dette ikkje vil påverke andre personar, og desse vil framleis ha moglegheit til å samarbeide på deira eigen versjon.","shareTitle":"Bli med på eit sanntidssamarbeid på Excalidraw"},"errorDialog":{"title":"Feil"},"exportDialog":{"disk_title":"Lagre til disk","disk_details":"Eksporter scenedataa til ei fil du kan importere seinare.","disk_button":"Lagre til fil","link_title":"Deleleg lenke","link_details":"Eksporter som skrivebeskytta lenke.","link_button":"Eksporter til lenke","excalidrawplus_description":"Lagre scena til Excalidraw+-arbeidsområdet ditt.","excalidrawplus_button":"Eksporter","excalidrawplus_exportError":"Kunne ikkje eksportere til Excalidraw+ akkurat no..."},"helpDialog":{"blog":"Les bloggen vår","click":"klikk","deepSelect":"Marker djupt","deepBoxSelect":"Marker djupt inni boksen og forhindr flytting","curvedArrow":"Boga pil","curvedLine":"Boga linje","documentation":"Dokumentasjon","doubleClick":"dobbelklikk","drag":"drag","editor":"Redigering","editLineArrowPoints":"","editText":"","github":"Funne eit problem? Send inn","howto":"Følg vegleiinga vår","or":"eller","preventBinding":"Hindre pilkopling","tools":"","shortcuts":"Tastatursnarvegar","textFinish":"Fullfør redigering (teksthandsamar)","textNewLine":"Legg til ny linje (teksthandsamar)","title":"Hjelp","view":"Vising","zoomToFit":"Zoom for å sjå alle elementa","zoomToSelection":"Zoom til utval","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":"Tøm lerretet"},"publishDialog":{"title":"Publiser bibliotek","itemName":"Elementnamn","authorName":"Eigaren sitt namn","githubUsername":"GitHub-brukarnamn","twitterUsername":"Twitter-brukarnamn","libraryName":"Biblioteknamn","libraryDesc":"Bibliotekskildring","website":"Nettstad","placeholder":{"authorName":"Namnet eller brukarnamnet ditt","libraryName":"Namnet på biblioteket ditt","libraryDesc":"Skildring av biblioteket ditt sånn at andre forstår bruken av det","githubHandle":"GitHub-brukarnamn (valfritt), slik at du kan redigere bibiloteket når det er sendt inn til vurdering","twitterHandle":"Twitter-brukarnamn (valfritt), så vi veit kven vi skal kreditere på Twitter","website":"Lenke til den personlege nettstaden din eller ein anna stad (valfritt)"},"errors":{"required":"Kravt","website":"Fyll inn ein gyldig URL"},"noteDescription":"Send inn biblioteket ditt til inkludering i den offentlege bibliotek-kjeldekodaslik at andre kan bruke det i teikningane deira.","noteGuidelines":"Biblioteket må godkjennast manuelt fyrst. Ver vennleg å lese retningslinjene før du sender inn. Du kjem til å trenge ein GitHub-konto for å kommunisere og gjere endringar dersom kravt, men det er ikkje strengt naudsynt.","noteLicense":"Ved å sende inn godkjenner du at biblioteket vert publisert under MIT-lisensen, som kort sagt betyr at kven som helst kan bruke det utan avgrensingar.","noteItems":"Kvart bibliotekselement må ha eit eige namn, slik at det er mogleg å filtrere. Dei følgande bibliotekselementa blir inkludert:","atleastOneLibItem":"Ver vennleg å markere minst eitt bibliotekselement for å starte","republishWarning":""},"publishSuccessDialog":{"title":"Bibliotek innsendt","content":"Tusen takk {{authorName}}! Biblioteket ditt har blitt sendt inn til gjennomgang. Du kan halde styr på statusher"},"confirmDialog":{"resetLibrary":"Tilbakestill bibliotek","removeItemsFromLib":"Fjern valde element frå biblioteket"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"Teikningane dine er ende-til-ende-krypterte slik at Excalidraw sine serverar aldri får sjå dei.","link":"Blogginnlegg om ende-til-ende-kryptering i Excalidraw"},"stats":{"angle":"Vinkel","element":"Element","elements":"Element","height":"Høgde","scene":"Scene","selected":"Valde","storage":"Lagring","title":"Statistikk for nerdar","total":"Totalt","version":"Versjon","versionCopy":"Klikk for å kopiere","versionNotAvailable":"Versjonen er ikkje tilgjengeleg","width":"Breidde"},"toast":{"addedToLibrary":"Lagt til i bibliotek","copyStyles":"Kopierte stilane.","copyToClipboard":"Kopiert til utklippstavla.","copyToClipboardAsPng":"Kopierte {{exportSelection}} til utklippstavla som PNG\\n({{exportColorScheme}})","fileSaved":"Fila er lagra.","fileSavedToFilename":"Lagra som {filename}","canvas":"lerret","selection":"val","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Gjennomsiktig","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/oc-FR-json-a68ea08272c8da3c0e3f.js b/public/excalidraw/excalidraw-assets-dev/locales/oc-FR-json-a68ea08272c8da3c0e3f.js
new file mode 100644
index 0000000..d1e517a
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/oc-FR-json-a68ea08272c8da3c0e3f.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/oc-FR-json"],{
+
+/***/ "../../locales/oc-FR.json":
+/*!********************************!*\
+ !*** ../../locales/oc-FR.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Pegar","pasteAsPlaintext":"Pegar en tèxt brut","pasteCharts":"Pegar los grafics","selectAll":"Tot seleccionar","multiSelect":"Apondre un element a la seleccion","moveCanvas":"Desplaçar lo canabàs","cut":"Talhar","copy":"Copiar","copyAsPng":"Copiar al quichapapièrs coma PNG","copyAsSvg":"Copiar al quichapapièrs coma SVG","copyText":"Copiar al quichapapièrs coma tèxt","bringForward":"En avant","sendToBack":"En arrièr","bringToFront":"A l’endavant","sendBackward":"Endarrièr","delete":"Suprimir","copyStyles":"Copiar los estiles","pasteStyles":"Pegar los estils","stroke":"Contorn","background":"Rèireplan","fill":"Empliment","strokeWidth":"Largor de contorn","strokeStyle":"Estil de contorn","strokeStyle_solid":"Solide","strokeStyle_dashed":"Tiret","strokeStyle_dotted":"Puntilhat","sloppiness":"Estil de traça","opacity":"Opacitat","textAlign":"Alinhament tèxt","edges":"Angles","sharp":"Ponchut","round":"Arredonit","arrowheads":"Cap de la flècha","arrowhead_none":"Cap","arrowhead_arrow":"Sageta","arrowhead_bar":"Barra","arrowhead_dot":"Ponch","arrowhead_triangle":"Triangle","fontSize":"Talha polissa","fontFamily":"Familha de polissa","addWatermark":"Apondre « Fabricat amb Excalidraw »","handDrawn":"A la man levada","normal":"Normala","code":"Còdi","small":"Pichona","medium":"Mejana","large":"Granda","veryLarge":"Gradassa","solid":"Solide","hachure":"Raia","zigzag":"","crossHatch":"Raia crosada","thin":"Fin","bold":"Espés","left":"Esquèrra","center":"Centre","right":"Drecha","extraBold":"Espesàs","architect":"Arquitècte","artist":"Artista","cartoonist":"Dessenhaire","fileTitle":"Nom del fichièr","colorPicker":"Selector de color","canvasColors":"Utilizada suls canabassses","canvasBackground":"Rèireplan del canabàs","drawingCanvas":"Zòna de dessenh","layers":"Calques","actions":"Accions","language":"Lenga","liveCollaboration":"Collaboracion en dirèct...","duplicateSelection":"Duplicar","untitled":"Sens títol","name":"Nom","yourName":"Vòstre nom","madeWithExcalidraw":"Fabricat amb Excalidraw","group":"Gropar la seleccion","ungroup":"Desunir la seleccion","collaborators":"Collaborators","showGrid":"Afichar la gresilha","addToLibrary":"Apondre a la bibliotèca","removeFromLibrary":"Suprimir de la bibliotèca","libraryLoadingMessage":"Cargament de la bibliotèca…","libraries":"Percórrer las bibliotècas","loadingScene":"Cargament de la scèna…","align":"Alinhament","alignTop":"Alinhar ennaut","alignBottom":"Alinhar enbàs","alignLeft":"Alinhar a esquèrra","alignRight":"Alinhar a drecha","centerVertically":"Centrar verticalament","centerHorizontally":"Centrar orizontalament","distributeHorizontally":"Distribuir orizontalament","distributeVertically":"Distribuir verticalament","flipHorizontal":"Virar orizontalament","flipVertical":"Virar verticalament","viewMode":"Mòde de vista","share":"Partejar","showStroke":"Mostrar lo selector de color de contorn","showBackground":"Mostrar lo selector de color de fons","toggleTheme":"Alternar tèma","personalLib":"Bibliotèca personala","excalidrawLib":"Bibliotèca Excalidraw","decreaseFontSize":"Reduire talha polissa","increaseFontSize":"Aumentar talha polissa","unbindText":"Dessociar lo tèxte","bindText":"Ligar lo tèxt al contenidor","createContainerFromText":"","link":{"edit":"Modificar lo ligam","editEmbed":"","create":"Crear un ligam","createEmbed":"","label":"Ligam","labelEmbed":"","empty":""},"lineEditor":{"edit":"Modificar la linha","exit":"Sortir de l’editor de linha"},"elementLock":{"lock":"Verrolhar","unlock":"Desverrolhar","lockAll":"Tot verrolhar","unlockAll":"Tot desverrolhar"},"statusPublished":"Publicat","sidebarLock":"Gardar la barra laterala dobèrta","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Cap d’element pas encara apondut...","hint_emptyLibrary":"Seleccionatz un element d’apondre aquí, o installatz una bibliotèca del depaus public, çai-jos.","hint_emptyPrivateLibrary":"Seleccionatz un element d’apondre aquí pel canabàs."},"buttons":{"clearReset":"Reïnicializar lo canabàs","exportJSON":"Exportar en fichièr","exportImage":"Exportar imatges...","export":"Enregistrar dins...","copyToClipboard":"Copiar al quichapapièrs","save":"Salvar al fichièr actual","saveAs":"Enregistrar jos","load":"Dobrir","getShareableLink":"Obténer lo ligam de partatge","close":"Tampar","selectLanguage":"Causir una lenga","scrollBackToContent":"Tornar al contengut","zoomIn":"Zoom avant","zoomOut":"Zoom arrièr","resetZoom":"Tirar lo zoom","menu":"Menú","done":"Acabat","edit":"Modificar","undo":"Anullar","redo":"Restablir","resetLibrary":"Reïnicializar la bibliotèca","createNewRoom":"Crear sala novèla","fullScreen":"Ecran complèt","darkMode":"Mòde escur","lightMode":"Mòde clar","zenMode":"Mòde escur","objectsSnapMode":"","exitZenMode":"Sortir del mòde zen","cancel":"Anullar","clear":"Escafar","remove":"Tirar","embed":"","publishLibrary":"Publicar","submit":"Enviar","confirm":"Confirmar","embeddableInteractionButton":""},"alerts":{"clearReset":"Aquò suprimirà lo canabàs complèt. O volètz vertadièrament ?","couldNotCreateShareableLink":"Creacion impossibla del ligam de partatge.","couldNotCreateShareableLinkTooBig":"Creacion impossibla del ligam de partatge : la scèna es tròp granda","couldNotLoadInvalidFile":"Cargament impossible d’un fichièr invalid","importBackendFailed":"Importacion fracassada.","cannotExportEmptyCanvas":"Impossible d’exportar los canabasses voids.","couldNotCopyToClipboard":"Còpia impossibla al quichapapièrs.","decryptFailed":"Deschiframent impossible de las donadas.","uploadedSecurly":"Lo telecargament es estat securizat amb un chiframent del cap a la fin, significa que los servidors d’Excalidraw o que quina tèrça part que siá pòdon pas legir lo contengut.","loadSceneOverridePrompt":"Cargar un dessenh extèrn remplaçarà vòstre contengut existent. Volètz contunhar ?","collabStopOverridePrompt":"Arrestar la session remplaçarà vòstre precedent dessenh gardat localament. O volètz vertadièrament ?\\n\\n(Se volètz gardar vòstre dessenh local, tampatz simplament l’onglet del navegador a la plaça)","errorAddingToLibrary":"Apondon impossible de l’element a la bibliotèca","errorRemovingFromLibrary":"Supression impossibla de l’element a la bibliotèca","confirmAddLibrary":"Apondrà {{numShapes}} forma(s) a vòstra bibliotèca. Confirmatz ?","imageDoesNotContainScene":"Aqueste imatge sembla pas conténer cap de donadas de scèna. Avètz activat l’integracion de scèna pendent l’exportacion ?","cannotRestoreFromImage":"Restauracion impossibla de la scèna a partir del fichièr imatge","invalidSceneUrl":"Importacion impossibla de la scèna a partir de l’URL provesida. Es siá mal formatada o siá conten pas cap de donada JSON Excalidraw valida.","resetLibrary":"Aquò suprimirà vòstra bibliotèca. O volètz vertadièrament ?","removeItemsFromsLibrary":"Suprimir {{count}} element(s) de la bibliotèca ?","invalidEncryptionKey":"La clau de chiframent deu conténer 22 caractèrs. La collaboracion en dirèct es desactivada.","collabOfflineWarning":"Cap de connexion pas disponibla.\\nVòstras modificacions seràn pas salvadas !"},"errors":{"unsupportedFileType":"Tipe de fichièr pas pres en carga.","imageInsertError":"Insercion d’imatge impossibla. Tornatz ensajar mai tard...","fileTooBig":"Fichièr tròp pesuc. La talha maximala autorizada es {{maxSize}}.","svgImageInsertError":"Insercion d’imatge SVG impossibla. Las balisas SVG semblan invalidas.","failedToFetchImage":"","invalidSVGString":"SVG invalid.","cannotResolveCollabServer":"Connexion impossibla al servidor collab. Mercés de recargar la pagina e tornar ensajar.","importLibraryError":"Impossible de cargar la bibliotèca","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Seleccion","image":"Inserir imatge","rectangle":"Rectangle","diamond":"Lausange","ellipse":"Ellipsa","arrow":"Sageta","line":"Linha","freedraw":"Dessenhar","text":"Tèxt","library":"Bibliotèca","lock":"Mantenir activa l’aisina aprèp dessenhar","penMode":"Mòde estilo - empachar lo contact","link":"Apondre/Actualizar lo ligam per una fòrma seleccionada","eraser":"Goma","frame":"","embeddable":"","laser":"","hand":"Man (aisina de desplaçament de la vista)","extraTools":""},"headings":{"canvasActions":"Accions del canabàs","selectedShapeActions":"Accions per la forma seleccionada","shapes":"Formas"},"hints":{"canvasPanning":"","linearElement":"Clicatz per començar mantun punt, lisatz per una sola linha","freeDraw":"Clicatz e lisatz, relargatz un còp acabat","text":"Astúcia : podètz tanben apondre de tèxt en doble clicant ont que siá amb l’aisina de seleccion","embeddable":"","text_selected":"Clicatz dos còps o quichatz ENTRADA per modificar lo tèxt","text_editing":"Quichatz ESCAPAR o CtrlOrCmd+ENTRADA per acabar la modificacion","linearElementMulti":"Clicatz sul darrièr punt o quichatz Ecap o Entrada per acabar","lockAngle":"Podètz restrénger l’angle en mantenent MAJ","resize":"Podètz servar las proporcions en mantenent la tòca MAJ pendent lo redimensionament,\\nmantenètz la tòca ALT per redimensionar a partir del centre","resizeImage":"Podètz retalhar liurament en quichant CTRL,\\nquichatz ALT per retalhar a partir del centre","rotate":"Podètz restrénger los angles en mantenent MAJ pendent la rotacion","lineEditor_info":"Tenètz quichat Ctrl o Cmd e doble clic o quichatz Ctrl o Cmd + Entrada per modificar los ponches","lineEditor_pointSelected":"Quichar Suprimir per tirar lo(s) punt(s),\\nCtrlOCmd+D per duplicar, o lisatz per desplaçar","lineEditor_nothingSelected":"Seleccionar un punt d’editar (manténer Maj. per ne seleccionar mantun),\\no manténer Alt e clicar per n’apondre de novèls","placeImage":"Clicatz per plaçar l’imatge, o clicatz e lisatz per definir sa talha manualament","publishLibrary":"Publicar vòstra pròpria bibliotèca","bindTextToElement":"Quichatz Entrada per apondre de tèxte","deepBoxSelect":"Gardar CtrlOCmd per una seleccion gropada e empachar lo desplaçament","eraserRevert":"Tenètz quichat Alt per anullar los elements marcats per supression","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"Afichatge impossible de l’apercebut","canvasTooBig":"Lo canabàs pòt èsser tròp grand.","canvasTooBigTip":"Astúcia : ensajatz de sarrar los elements mai alonhats."},"errorSplash":{"headingMain":"Una error s’es producha. Ensajatz ","clearCanvasMessage":"Se recargar fonciona pas, ensajatz ","clearCanvasCaveat":" Menarà a una pèrda del trabalh ","trackedToSentry":"Error amb l’identificant {{eventId}} es estada enregistrada sus nòstre sistèma.","openIssueMessage":"Èrem plan prudents per inclure pas d’informacions de la scèna vòstra sus l’error. Se vòstra scèna es pas privada, volgatz considerar de perseguir sus nòstre Volgatz inclure las informacions çai-jos en las copiant e pegant a l’issue GitHub.","sceneContent":"Contengut de la scèna :"},"roomDialog":{"desc_intro":"Podètz convidar lo monde a vòstra scèna actuala per participar amb vos.","desc_privacy":"Vos en fagatz pas, la session utiliza lo chiframent del cap a la fin, çò que dessenetz demorarà privat. Mai nòstres servidors poiràn pas veire vòstra creacion.","button_startSession":"Començar la session","button_stopSession":"Arrestar la session","desc_inProgressIntro":"La session de collaboracion es ara en cors.","desc_shareLink":"Partejatz aqueste ligam amb lo monde amb qui volètz collaborar :","desc_exitSession":"Arrestar la session vos desconnectarà de la sala, mas poiretz contunhar de trabalhar a la scèna, en local. Notatz qu’aquò afectarà pas los autres, e poiràn collaborar a lor version.","shareTitle":"Rejonhètz una session collaborativa sus Excalidraw"},"errorDialog":{"title":"Error"},"exportDialog":{"disk_title":"Salvar al disc","disk_details":"Exportar las donadas de la scèna cap a un fichièr que podètz importar mai tard.","disk_button":"Salvar al fichièr","link_title":"Ligam de partejar","link_details":"Exportar coma un ligam de lectura sola.","link_button":"Exportar en ligam","excalidrawplus_description":"Enregistrar la scèna dins vòstre espaci de trabalh Excalidraw+.","excalidrawplus_button":"Exportar","excalidrawplus_exportError":"Export impossibla cap a Excalidraw+ pel moment..."},"helpDialog":{"blog":"Legir nòstre blog","click":"clic","deepSelect":"Seleccion prigonda","deepBoxSelect":"Seleccionar demest un grop e empacha lo desplaçament","curvedArrow":"Sageta corba","curvedLine":"Linha corba","documentation":"Documentacion","doubleClick":"doble clic","drag":"lisar","editor":"Editor","editLineArrowPoints":"","editText":"","github":"Problèma trobat ? Senhalatz-lo","howto":"Seguissètz nòstras guidas","or":"o","preventBinding":"Empachar la fixacion de sagetas","tools":"Aisinas","shortcuts":"Acorchis clavièr","textFinish":"Terminar l’edicion (editor de tèxt)","textNewLine":"Apondre linha novèl (editor de tèxt)","title":"Ajuda","view":"Vista","zoomToFit":"Zoomar per veire totes los elements","zoomToSelection":"Zoomar la seleccion","toggleElementLock":"Verrolhar/Desverrolhar la seleccion","movePageUpDown":"Desplaçar la pagina ennaut/enbàs","movePageLeftRight":"Desplaçar la pagina a esquèrra/drecha"},"clearCanvasDialog":{"title":"Escafar canabàs"},"publishDialog":{"title":"Publicar la bibliotèca","itemName":"Nom de l’element","authorName":"Nom de l’autor","githubUsername":"Nom d’utilizaire GitHub","twitterUsername":"Nom d’utilizaire Twitter","libraryName":"Nom de la bibliotèca","libraryDesc":"Descripcion de la bibliotèca","website":"Site web","placeholder":{"authorName":"Vòstre nom o nom d’utilizaire","libraryName":"Nom de vòstra bibliotèca","libraryDesc":"Descripcion de vòstra bibliotèca per ajudar lo monde a comprendre son utilizacion","githubHandle":"GitHub handle(opcional), per poder modificar la bibliotèca un còp enviada per repassa","twitterHandle":"Nom d’utilizaire Twitter (opcional), per saber qual mercejar quand ne parlam sus Twitter","website":"Ligam cap a vòstre site web personal o endacòm mai (opcional)"},"errors":{"required":"Requerit","website":"Picatz una URL valida"},"noteDescription":"Enviatz vòstra bibliotèca per èsser compresa al repertòri public de bibliotècaper que los autres l’utilizen dins lor dessenhs.","noteGuidelines":"Qualqu’un deu aprovar la bibliotèca manualament per començar. Volgatz legir las linhas directrises abans de sometre. Vos farà mestièr un compte GitHub per comunicar e realizar de modificacions se demandadas, mas es pas complètament obligatòri.","noteLicense":"En sometent, acceptatz que la bibliotèca siá publicada sota la Licéncia MIT, que significa en brèu que qual que siá pòt l’utilizar sens cap de restriccion.","noteItems":"Cada element de bibliotèca deu aver un nom pròpri per èsser filtrable. Los elements de bibliotèca seguentas seràn incluses :","atleastOneLibItem":"Volgatz seleccionar almens un element de bibliotèca per començar","republishWarning":"Nòta : d’unes elements seleccionats son marcats ja coma publicats/enviats. Deuriatz sonque tornar enviar los elements pendent l’actualizacion d’una bibliotèca existenta o un mandadís."},"publishSuccessDialog":{"title":"Bibliotèca somesa","content":"Mercés {{authorName}}. Vòstre bibliotèca es estada somesa per repassa. Podètz seguir l’avançamentaquí"},"confirmDialog":{"resetLibrary":"Reïnicializar la bibliotèca","removeItemsFromLib":"Tirar los elements seleccionats de la bibliotèca"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"Vòstres dessenhs son chifrats del cap a la fin en consequéncia los servidors d’Excalidraw los veiràn pas jamai.","link":"Article de blòg sul chiframent del cap a la fin dins Excalidraw"},"stats":{"angle":"Angle","element":"Element","elements":"Elements","height":"Nautor","scene":"Scèna","selected":"Seleccionat","storage":"Emmagazinatge","title":"Estatisticas pels nerds","total":"Total","version":"Version","versionCopy":"Clicar per copiar","versionNotAvailable":"Version pas disponibla","width":"Largor"},"toast":{"addedToLibrary":"Apondut a la bibliotèca","copyStyles":"Estiles copiats.","copyToClipboard":"Copiats al quichapapièrs.","copyToClipboardAsPng":"{{exportSelection}} copiat coma PNG ({{exportColorScheme}})","fileSaved":"Fichièr enregistrat.","fileSavedToFilename":"Enregistrat jos {filename}","canvas":"canabàs","selection":"seleccion","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Transparéncia","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"Totas las donadas son enregistradas dins vòstre navegador.","center_heading_plus":"Voliatz puslèu utilizar Excalidraw+ a la plaça ?","menuHint":"Exportar, preferéncias, lengas, ..."},"defaults":{"menuHint":"Exportar, preferéncias, e mai...","center_heading":"Diagram. Tot. Simplament.","toolbarHint":"Prenètz un esplech e començatz de dessenhar !","helpHint":"Acorchis e ajuda"}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/pa-IN-json-90a2b3775bd7d8983def.js b/public/excalidraw/excalidraw-assets-dev/locales/pa-IN-json-90a2b3775bd7d8983def.js
new file mode 100644
index 0000000..898dc87
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/pa-IN-json-90a2b3775bd7d8983def.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/pa-IN-json"],{
+
+/***/ "../../locales/pa-IN.json":
+/*!********************************!*\
+ !*** ../../locales/pa-IN.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"ਪੇਸਟ ਕਰੋ","pasteAsPlaintext":"ਸਾਦੇ ਪਾਠ ਵਜੋਂ ਪੇਸਟ ਕਰੋ","pasteCharts":"ਚਾਰਟ ਪੇਸਟ ਕਰੋ","selectAll":"ਸਾਰੇ ਚੁਣੋ","multiSelect":"ਐਲੀਮੈਂਟ ਨੂੰ ਚੋਣ ਵਿੱਚ ਜੋੜੋ","moveCanvas":"ਕੈਨਵਸ ਹਿਲਾਓ","cut":"ਕੱਟੋ","copy":"ਕਾਪੀ ਕਰੋ","copyAsPng":"ਕਲਿੱਪਬੋਰਡ \'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕਰੋ","copyAsSvg":"ਕਲਿੱਪਬੋਰਡ \'ਤੇ SVG ਵਜੋਂ ਕਾਪੀ ਕਰੋ","copyText":"ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਪਾਠ ਵਜੋਂ ਕਾਪੀ ਕਰੋ","bringForward":"ਅੱਗੇ ਲਿਆਓ","sendToBack":"ਸਭ ਤੋਂ ਪਿੱਛੇ ਭੇਜੋ","bringToFront":"ਸਭ ਤੋਂ ਅੱਗੇ ਲਿਆਓ","sendBackward":"ਪਿੱਛੇ ਭੇਜੋ","delete":"ਮਿਟਾਓ","copyStyles":"ਸਟਾਇਲ ਕਾਪੀ ਕਰੋ","pasteStyles":"ਸਟਾਇਲ ਪੇਸਟ ਕਰੋ","stroke":"ਰੇਖਾ","background":"ਬੈਕਗਰਾਉਂਡ","fill":"ਭਰਨਾ","strokeWidth":"ਰੇਖਾ ਦੀ ਚੌੜਾਈ","strokeStyle":"ਰੇਖਾ ਦਾ ਸਟਾਇਲ","strokeStyle_solid":"ਠੋਸ","strokeStyle_dashed":"ਡੈਸ਼ ਵਾਲੀ","strokeStyle_dotted":"ਬਿੰਦੀਆਂ ਵਾਲੀ","sloppiness":"ਬੇਤਰਤੀਬੀ","opacity":"ਅਪਾਰਦਰਸ਼ਤਾ","textAlign":"ਲਿਖਤ ਇਕਸਾਰਤਾ","edges":"ਕਿਨਾਰੇ","sharp":"ਤਿੱਖੇ","round":"ਗੋਲ","arrowheads":"ਤੀਰ ਦੇ ਸਿਰੇ","arrowhead_none":"ਕੋਈ ਨਹੀਂ","arrowhead_arrow":"ਤੀਰ","arrowhead_bar":"ਡੰਡੀ","arrowhead_dot":"ਬਿੰਦੀ","arrowhead_triangle":"ਤਿਕੋਣ","fontSize":"ਫੌਂਟ ਅਕਾਰ","fontFamily":"ਫੌਂਟ ਪਰਿਵਾਰ","addWatermark":"\\"Excalidraw ਨਾਲ ਬਣਾਇਆ\\" ਜੋੜੋ","handDrawn":"ਹੱਥਲਿਖਤ","normal":"ਆਮ","code":"ਕੋਡ","small":"ਛੋਟਾ","medium":"ਮੱਧਮ","large":"ਵੱਡਾ","veryLarge":"ਬਹੁਤ ਵੱਡਾ","solid":"ਠੋਸ","hachure":"ਤਿਰਛੀਆਂ ਗਰਿੱਲਾਂ","zigzag":"ਵਿੰਗ-ਤੜਿੰਗ","crossHatch":"ਜਾਲੀ","thin":"ਪਤਲੀ","bold":"ਮੋਟੀ","left":"ਖੱਬੇ","center":"ਵਿਚਕਾਰ","right":"ਸੱਜੇ","extraBold":"ਬਹੁਤ ਮੋਟੀ","architect":"ਭਵਨ ਨਿਰਮਾਣਕਾਰੀ","artist":"ਕਲਾਕਾਰ","cartoonist":"ਕਾਰਟੂਨਿਸਟ","fileTitle":"ਫਾਈਲ ਦਾ ਨਾਂ","colorPicker":"ਰੰਗ ਚੋਣਕਾਰ","canvasColors":"ਕੈਨਵਸ \'ਤੇ ਵਰਤਿਆ","canvasBackground":"ਕੈਨਵਸ ਦਾ ਬੈਕਗਰਾਉਂਡ","drawingCanvas":"ਡਰਾਇੰਗ ਕੈਨਵਸ","layers":"ਪਰਤਾਂ","actions":"ਕਾਰਵਾਈਆਂ","language":"ਭਾਸ਼ਾ","liveCollaboration":"ਲਾਇਵ ਸਹਿਯੋਗ...","duplicateSelection":"ਡੁਪਲੀਕੇਟ ਬਣਾਓ","untitled":"ਬੇ-ਸਿਰਨਾਵਾਂ","name":"ਨਾਂ","yourName":"ਤੁਹਾਡਾ ਨਾਂ","madeWithExcalidraw":"Excalidraw ਨਾਲ ਬਣਾਇਆ","group":"ਚੋਣ ਦਾ ਗਰੁੱਪ ਬਣਾਓ","ungroup":"ਚੋਣ ਦਾ ਗਰੁੱਪ ਤੋੜੋ","collaborators":"ਸਹਿਯੋਗੀ","showGrid":"ਜਾਲੀ ਦਿਖਾਓ","addToLibrary":"ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਜੋੜੋ","removeFromLibrary":"ਲਾਇਬ੍ਰੇਰੀ \'ਚੋਂ ਹਟਾਓ","libraryLoadingMessage":"ਲਾਇਬ੍ਰੇਰੀ ਲੋਡ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…","libraries":"ਲਾਇਬ੍ਰੇਰੀਆਂ ਬਰਾਉਜ਼ ਕਰੋ","loadingScene":"ਦ੍ਰਿਸ਼ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…","align":"ਇਕਸਾਰ","alignTop":"ਉੱਪਰ ਇਕਸਾਰ ਕਰੋ","alignBottom":"ਹੇਠਾਂ ਇਕਸਾਰ ਕਰੋ","alignLeft":"ਖੱਬੇ ਇਕਸਾਰ ਕਰੋ","alignRight":"ਸੱਜੇ ਇਕਸਾਰ ਕਰੋ","centerVertically":"ਲੇਟਵੇਂ ਵਿਚਕਾਰ ਕਰੋ","centerHorizontally":"ਖੜ੍ਹਵੇਂ ਵਿਚਕਾਰ ਕਰੋ","distributeHorizontally":"ਖੜ੍ਹਵੇਂ ਇਕਸਾਰ ਵੰਡੋ","distributeVertically":"ਲੇਟਵੇਂ ਇਕਸਾਰ ਵੰਡੋ","flipHorizontal":"ਲੇਟਵੇਂ ਪਾਸੇ ਪਲਟੋ","flipVertical":"ਖੜ੍ਹਵੇਂ ਪਾਸੇ ਪਲਟੋ","viewMode":"ਦੇਖਣ ਵਾਲਾ ਮੋਡ","share":"ਸਾਂਝਾ ਕਰੋ","showStroke":"ਰੇਖਾ ਦਾ ਰੰਗ ਚੋਣਕਾਰ ਦਿਖਾਓ","showBackground":"ਬੈਕਗਰਾਉਂਡ ਦਾ ਰੰਗ ਚੋਣਕਾਰ ਦਿਖਾਓ","toggleTheme":"ਥੀਮ ਬਦਲੋ","personalLib":"ਨਿੱਜੀ ਲਾਇਬ੍ਰੇਰੀ","excalidrawLib":"ਐਕਸਕਲੀਡਰਾਅ ਲਾਇਬ੍ਰੇਰੀ","decreaseFontSize":"ਫੌਂਟ ਦਾ ਅਕਾਰ ਘਟਾਓ","increaseFontSize":"ਫੌਂਟ ਦਾ ਅਕਾਰ ਵਧਾਓ","unbindText":"ਪਾਠ ਨੂੰ ਵੱਖ ਕਰੋ","bindText":"ਪਾਠ ਨੂੰ ਕੰਟੇਨਰ ਨਾਲ ਬੰਨ੍ਹੋ","createContainerFromText":"ਪਾਠ ਨੂੰ ਕੰਟੇਨਰ ਵਿੱਚ ਇਕੱਠਾ ਕਰੋ","link":{"edit":"ਕੜੀ ਸੋਧੋ","editEmbed":"","create":"ਕੜੀ ਬਣਾਓ","createEmbed":"","label":"ਕੜੀ","labelEmbed":"","empty":""},"lineEditor":{"edit":"ਪੰਕਤੀ ਸੋਧੋ","exit":"ਪੰਕਤੀ ਸੋਧਕ \'ਤੋਂ ਬਾਹਰ ਨਿਕਲੋ"},"elementLock":{"lock":"ਲਾਕ ਕਰੋ","unlock":"ਅਨਲਾਕ ਕਰੋ","lockAll":"ਸਭ ਲਾਕ ਕਰੋ","unlockAll":"ਸਭ ਅਨਲਾਕ ਕਰੋ"},"statusPublished":"ਪ੍ਰਕਾਸ਼ਤ ਹੈ","sidebarLock":"ਸਾਈਡਬਾਰ ਨੂੰ ਖੁੱਲ੍ਹਾ ਰੱਖੋ","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"ਹਾਲੇ ਤੱਕ ਕੋਈ ਚੀਜ ਜੋੜੀ ਨਹੀਂ ਗਈ...","hint_emptyLibrary":"ਇੱਥੇ ਆਈਟਮ ਜੋੜਨ ਲਈ ਉਸਨੂੰ ਕੈਨਵਸ ‘ਤੇ ਚੁਣੋ, ਜਾਂ ਹੇਠਾਂ ਪਬਲਿਕ ਰਿਪਾਜ਼ੀਟਰੀ ‘ਚੋਂ ਲਾਇਬ੍ਰੇਰੀ ਸਥਾਪਤ ਕਰੋ।","hint_emptyPrivateLibrary":"ਇੱਥੇ ਆਈਟਮ ਜੋੜਨ ਲਈ ਉਸਨੂੰ ਕੈਨਵਸ ‘ਤੇ ਚੁਣੋ।"},"buttons":{"clearReset":"ਕੈਨਵਸ ਰੀਸੈੱਟ ਕਰੋ","exportJSON":"ਫਾਈਲ ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ","exportImage":"ਤਸਵੀਰ ਨਿਰਯਾਤ ਕਰੋ...","export":"ਇਸ ਵਿੱਚ ਸਾਂਭੋ...","copyToClipboard":"ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕਰੋ","save":"ਮੌਜੂਦਾ ਫਾਈਲ ਵਿੱਚ ਸਾਂਭੋ","saveAs":"ਇਸ ਵਜੋਂ ਸਾਂਭੋ","load":"ਖੋਲ੍ਹੋ","getShareableLink":"ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ ਲਵੋ","close":"ਬੰਦ ਕਰੋ","selectLanguage":"ਭਾਸ਼ਾ ਚੁਣੋ","scrollBackToContent":"ਸਮੱਗਰੀ \'ਤੇ ਵਾਪਸ ਸਕਰੋਲ ਕਰੋ","zoomIn":"ਜ਼ੂਮ ਵਧਾਓ","zoomOut":"ਜ਼ੂਮ ਘਟਾਓ","resetZoom":"ਜ਼ੂਮ ਰੀਸੈੱਟ ਕਰੋ","menu":"ਮੇਨੂ","done":"ਹੋ ਗਿਆ","edit":"ਸੋਧੋ","undo":"ਅਣਕੀਤਾ ਕਰੋ","redo":"ਮੁੜ-ਕਰੋ","resetLibrary":"ਲਾਇਬ੍ਰੇਰੀ ਰੀਸੈੱਟ ਕਰੋ","createNewRoom":"ਨਵਾਂ ਕਮਰਾ ਬਣਾਓ","fullScreen":"ਪੂਰੀ ਸਕਰੀਨ","darkMode":"ਡਾਰਕ ਮੋਡ","lightMode":"ਲਾਇਟ ਮੋਡ","zenMode":"ਜ਼ੈੱਨ ਮੋਡ","objectsSnapMode":"","exitZenMode":"ਜ਼ੈੱਨ ਮੋਡ \'ਚੋਂ ਬਾਹਰ ਨਿਕਲੋ","cancel":"ਰੱਦ ਕਰੋ","clear":"ਸਾਫ਼ ਕਰੋ","remove":"ਹਟਾਓ","embed":"","publishLibrary":"ਪ੍ਰਕਾਸ਼ਤ ਕਰੋ","submit":"ਜਮ੍ਹਾ ਕਰਵਾਓ","confirm":"ਪੁਸ਼ਟੀ ਕਰੋ","embeddableInteractionButton":""},"alerts":{"clearReset":"ਇਹ ਸਾਰਾ ਕੈਨਵਸ ਸਾਫ ਕਰ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?","couldNotCreateShareableLink":"ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ ਨਹੀਂ ਬਣਾ ਸਕੇ।","couldNotCreateShareableLinkTooBig":"ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ ਨਹੀਂ ਬਣਾ ਸਕੇ: ਦ੍ਰਿਸ਼ ਬਹੁਤ ਵੱਡਾ ਹੈ","couldNotLoadInvalidFile":"ਨਜਾਇਜ਼ ਫਾਈਲ ਲੋਡ ਨਹੀਂ ਕਰ ਸਕੇ","importBackendFailed":"ਬੈਕਐੱਨਡ ਤੋਂ ਆਯਾਤ ਕਰਨ ਵਿੱਚ ਅਸਫਲ ਰਹੇ।","cannotExportEmptyCanvas":"ਖਾਲੀ ਕੈਨਵਸ ਨੂੰ ਨਿਰਯਾਤ ਨਹੀਂ ਕਰ ਸਕਦੇ।","couldNotCopyToClipboard":"ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।","decryptFailed":"ਡਾਟਾ ਡੀਕਰਿਪਟ ਨਹੀਂ ਕਰ ਸਕੇ।","uploadedSecurly":"ਅੱਪਲੋਡ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਸ਼ਨ ਨਾਲ ਸੁਰੱਖਿਅਤ ਕੀਤੀ ਹੋਈ ਹੈ, ਜਿਸਦਾ ਮਤਲਬ ਇਹ ਹੈ ਕਿ Excalidraw ਸਰਵਰ ਅਤੇ ਤੀਜੀ ਧਿਰ ਦੇ ਬੰਦੇ ਸਮੱਗਰੀ ਨੂੰ ਪੜ੍ਹ ਨਹੀਂ ਸਕਦੇ।","loadSceneOverridePrompt":"ਬਾਹਰੀ ਡਰਾਇੰਗ ਨੂੰ ਲੋਡ ਕਰਨਾ ਤੁਹਾਡੀ ਮੌਜੂਦਾ ਸਮੱਗਰੀ ਦੀ ਥਾਂ ਲੈ ਲਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?","collabStopOverridePrompt":"ਇਜਲਾਸ ਨੂੰ ਰੋਕਣਾ ਪਿਛਲੀ ਲੋਕਲ ਸਾਂਭੀ ਡਰਾਇੰਗ ਦੀ ਥਾਂ ਲੈ ਲਵੇਗਾ। ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?\\n\\n(ਜੇ ਤੁਸੀਂ ਆਪਣੀ ਲੋਕਲ ਡਰਾਇੰਗ ਨੂੰ ਬਰਕਰਾਰ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ ਤਾਂ ਇਹ ਕਰਨ ਦੀ ਬਜਾਏ ਬੱਸ ਆਪਣਾ ਟੈਬ ਬੰਦ ਕਰ ਦਿਉ।)","errorAddingToLibrary":"ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਸਮੱਗਰੀ ਨਹੀਂ ਜੋੜ ਸਕੇ","errorRemovingFromLibrary":"ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚੋਂ ਸਮੱਗਰੀ ਨਹੀਂ ਹਟਾ ਸਕੇ","confirmAddLibrary":"ਇਹ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ {{numShapes}} ਆਕ੍ਰਿਤੀ(ਆਂ) ਨੂੰ ਜੋੜ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?","imageDoesNotContainScene":"ਇਸ ਤਸਵੀਰ ਵਿੱਚ ਦ੍ਰਿਸ਼ ਦਾ ਕੋਈ ਵੀ ਡਾਟਾ ਨਜ਼ਰ ਨਹੀਂ ਆ ਰਿਹਾ। ਕੀ ਤੁਸੀਂ ਨਿਰਯਾਤ ਕਰਦੇ ਸਮੇਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਮੜ੍ਹਣਾ ਸਮਰੱਥ ਕੀਤਾ ਸੀ?","cannotRestoreFromImage":"ਇਸ ਤਸਵੀਰ ਫਾਈਲ ਤੋਂ ਦ੍ਰਿਸ਼ ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ","invalidSceneUrl":"ਦਿੱਤੀ ਗਈ URL \'ਚੋਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਆਯਾਤ ਨਹੀਂ ਕਰ ਸਕੇ। ਇਹ ਜਾਂ ਤਾਂ ਖਰਾਬ ਹੈ, ਜਾਂ ਇਸ ਵਿੱਚ ਜਾਇਜ਼ Excalidraw JSON ਡਾਟਾ ਸ਼ਾਮਲ ਨਹੀਂ ਹੈ।","resetLibrary":"ਇਹ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਸਾਫ ਕਰ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?","removeItemsFromsLibrary":"ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚੋਂ {{count}} ਚੀਜ਼(-ਜ਼ਾਂ) ਮਿਟਾਉਣੀਆਂ ਹਨ?","invalidEncryptionKey":"ਇਨਕਰਿਪਸ਼ਨ ਕੁੰਜੀ 22 ਅੱਖਰਾਂ ਦੀ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ। ਲਾਇਵ ਸਹਿਯੋਗ ਬੰਦ ਹੈ।","collabOfflineWarning":"ਕੋਈ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਨਹੀਂ ਹੈ\\nਤੁਹਾਡੀਆਂ ਤਬਦੀਲੀਆਂ ਸਾਂਭੀਆਂ ਨਹੀਂ ਜਾਣਗੀਆਂ।"},"errors":{"unsupportedFileType":"ਫਾਈਲ ਦੀ ਕਿਸਮ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ।","imageInsertError":"ਚਿੱਤਰ ਸ਼ਾਮਲ ਨਹੀਂ ਜਾ ਸਕਿਆ, ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ...","fileTooBig":"ਫਾਈਲ ਬਹੁਤ ਜ਼ਿਆਦਾ ਵੱਡੀ ਹੈ। ਵੱਧ-ਤੋਂ-ਵੱਧ ਪ੍ਰਵਾਨਤ ਅਕਾਰ {{maxSize}} ਹੈ।","svgImageInsertError":"SVG ਤਸਵੀਰ ਸ਼ਾਮਲ ਨਹੀਂ ਕਰ ਸਕੇ। SVG ਮਾਰਕ-ਅੱਪ ਨਜਾਇਜ਼ ਲੱਗ ਰਿਹਾ ਹੈ।","failedToFetchImage":"","invalidSVGString":"SVG ਨਜਾਇਜ਼ ਹੈ।","cannotResolveCollabServer":"","importLibraryError":"ਲਾਇਬ੍ਰੇਰੀ ਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"ਚੋਣਕਾਰ","image":"ਤਸਵੀਰ ਸ਼ਾਮਲ ਕਰੋ","rectangle":"ਆਇਤ","diamond":"ਹੀਰਾ","ellipse":"ਅੰਡਾਕਾਰ","arrow":"ਤੀਰ","line":"ਲਕੀਰ","freedraw":"ਵਾਹੋ","text":"ਪਾਠ","library":"ਲਾਇਬ੍ਰੇਰੀ","lock":"ਡਰਾਇੰਗ ਤੋਂ ਬਾਅਦ ਵੀ ਚੁਣੇ ਹੋਏ ਸੰਦ ਨੂੰ ਸਰਗਰਮ ਰੱਖੋ ","penMode":"ਪੈੱਨ ਮੋਡ - ਟੱਚ ਤੋਂ ਬਚਾਉਂਦਾ ਹੈ","link":"","eraser":"ਰਬੜ","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"ਕੈਨਵਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ","selectedShapeActions":"ਚੁਣੀ ਆਕ੍ਰਿਤੀ ਦੀਆਂ ਕਾਰਵਾਈਆਂ","shapes":"ਆਕ੍ਰਿਤੀਆਂ"},"hints":{"canvasPanning":"","linearElement":"ਇੱਕ ਤੋਂ ਜ਼ਿਆਦਾ ਬਿੰਦੂਆਂ ਲਈ ਕਲਿੱਕ ਕਰਕੇ ਸ਼ੁਰੂਆਤ ਕਰੋ, ਇਕਹਿਰੀ ਲਕੀਰ ਲਈ ਘਸੀਟੋ","freeDraw":"ਕਲਿੱਕ ਕਰਕੇ ਘਸੀਟੋ, ਪੂਰਾ ਹੋਣ \'ਤੇ ਛੱਡ ਦਿਉ","text":"ਨੁਸਖਾ: ਤੁਸੀਂ ਚੋਣਕਾਰ ਸੰਦ ਰਾਹੀਂ ਕਿਤੇ ਵੀ ਡਬਲ-ਕਲਿੱਕ ਕਰਕੇ ਵੀ ਪਾਠ ਜੋੜ ਸਕਦੇ ਹੋ","embeddable":"","text_selected":"ਪਾਠ ਨੂੰ ਸੋਧਣ ਲਈ ਡਬਲ-ਕਲਿੱਕ ਕਰੋ ਜਾਂ ਐਂਟਰ ਦਬਾਓ","text_editing":"ਸੋਧ ਮੁਕੰਮਲ ਕਰਨ ਲਈ ਐਸਕੇਪ (Esc) ਜਾਂ Ctrl-ਜਾਂ-Cmd+ਐਂਟਰ (enter) ਦਬਾਓ","linearElementMulti":"ਮੁਕੰਮਲ ਕਰਨ ਲਈ ਆਖਰੀ ਬਿੰਦੂ \'ਤੇ ਕਲਿੱਕ ਕਰੋ ਜਾਂ ਇਸਕੇਪ ਜਾਂ ਐਂਟਰ ਦਬਾਓ","lockAngle":"ਤੁਸੀਂ SHIFT ਦਬਾਈ ਰੱਖ ਕੇ ਕੋਣਾਂ ਨੂੰ ਕਾਬੂ ਕਰ ਸਕਦੇ ਹੋ","resize":"ਤੁਸੀਂ ਅਕਾਰ ਬਦਲਦੇ ਸਮੇਂ SHIFT ਦਬਾਈ ਰੱਖ ਕੇ ਅਨੁਪਾਤ ਨੂੰ ਕਾਬੂ ਕਰ ਸਕਦੇ ਹੋ, ਵਿਚਕਾਰ ਤੋਂ ਅਕਾਰ ਬਦਲਣ ਲਈ ALT ਦਬਾਓ","resizeImage":"","rotate":"ਤੁਸੀਂ ਘੁਮਾਉਂਦੇ ਹੋਏ SHIFT ਦਬਾਈ ਰੱਖ ਕੇ ਕੋਣਾਂ ਨੂੰ ਕਾਬੂ ਕਰ ਸਕਦੇ ਹੋ","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"ਆਪਣੀ ਲਾਇਬ੍ਰੇਰੀ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ","bindTextToElement":"ਪਾਠ ਜੋੜਨ ਲਈ ਐੰਟਰ ਦਬਾਓ","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"ਝਲਕ ਨਹੀਂ ਦਿਖਾ ਸਕਦੇ","canvasTooBig":"ਸ਼ਾਇਦ ਕੈਨਵਸ ਬਹੁਤ ਜ਼ਿਆਦਾ ਵੱਡਾ ਹੈ।","canvasTooBigTip":"ਨੁਸਖਾ: ਸਭ ਤੋਂ ਦੂਰ ਸਥਿੱਤ ਐਲੀਮੈਂਟਾਂ ਨੂੰ ਥੋੜ੍ਹਾ ਜਿਹਾ ਨੇੜੇ ਲਿਆ ਕੇ ਦੇਖੋ।"},"errorSplash":{"headingMain":"ਕੋਈ ਸਮੱਸਿਆ ਖੜ੍ਹੀ ਹੋਈ। ਕਰਕੇ ਦੇਖੋ।","clearCanvasMessage":"ਜੇ ਮੁੜ-ਲੋਡ ਕਰਨਾ ਕੰਮ ਨਾ ਕਰੇ, ਤਾਂ ਇਹ ਕਰਕੇ ਦੇਖੋ ","clearCanvasCaveat":" ਇਹ ਸਾਰਾ ਕੰਮ ਗਵਾ ਦੇਵੇਗਾ ","trackedToSentry":"ਸੂਚਕ {{eventId}} ਵਾਲੀ ਸਮੱਸਿਆ ਸਾਡੇ ਸਿਸਟਮ \'ਤੇ ਟਰੈਕ ਕੀਤੀ ਗਈ ਸੀ।","openIssueMessage":"ਅਸੀਂ ਬੜੇ ਸਾਵਧਾਨ ਸੀ ਕਿ ਗਲਤੀ ਵਿੱਚ ਤੁਹਾਡੇ ਦ੍ਰਿਸ਼ ਦੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਨਾ ਕਰੀਏ। ਜੇ ਤੁਹਾਡਾ ਦ੍ਰਿਸ਼ ਨਿੱਜੀ ਨਹੀਂ ਹੈ ਤਾਂ ਇਸ \'ਤੇ ਸਾਡੇ ਨਾਲ ਸੰਪਰਕ ਕਰੋ ਜੀ ਹੇਠਾਂ ਦਿੱਤੀ ਜਾਣਕਾਰੀ ਨੂੰ ਕਾਪੀ ਕਰਕੇ ਗਿੱਟਹੱਬ ਮੁੱਦੇ ਵਿੱਚ ਪੇਸਟ ਕਰਕੇ ਸ਼ਾਮਲ ਕਰੋ ਜੀ।","sceneContent":"ਦ੍ਰਿਸ਼ ਦੀ ਸਮੱਗਰੀ:"},"roomDialog":{"desc_intro":"ਤੁਸੀਂ ਲੋਕਾਂ ਨੂੰ ਆਪਣੇ ਨਾਲ ਮੌਜੂਦਾ ਦ੍ਰਿਸ਼ \'ਤੇ ਸਹਿਯੋਗ ਕਰਨ ਲਈ ਸੱਦਾ ਭੇਜ ਸਕਦੇ ਹੋ।","desc_privacy":"ਫਿਕਰ ਨਾ ਕਰੋ, ਇਜਲਾਸ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਸ਼ਨ ਵਰਤਦਾ ਹੈ, ਸੋ ਜੋ ਕੁਝ ਵੀ ਤੁਸੀਂ ਵਾਹੁੰਦੇ ਹੋ ਉਹ ਨਿੱਜੀ ਹੀ ਰਹਿੰਦਾ ਹੈ। ਇੱਥੋਂ ਤੱਕ ਕਿ ਸਾਡੇ ਸਰਵਰ ਵੀ ਨਹੀਂ ਜਾਣ ਸਕਣਗੇ ਕਿ ਤੁਸੀਂ ਕੀ ਬਣਾਇਆ ਹੈ।","button_startSession":"ਇਜਲਾਸ ਸ਼ੁਰੂ ਕਰੋ","button_stopSession":"ਇਜਲਾਸ ਰੋਕੋ","desc_inProgressIntro":"ਲਾਇਵ ਸਹਿਯੋਗ ਇਜਲਾਸ ਹੁਣ ਚੱਲ ਰਿਹਾ ਹੈ।","desc_shareLink":"ਇਸ ਲਿੰਕ ਨੂੰ ਉਹਨਾਂ ਨਾਲ ਸਾਂਝਾ ਕਰੋ ਜਿਹਨਾਂ ਨਾਲ ਤੁਸੀਂ ਸਹਿਯੋਗ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ:","desc_exitSession":"ਇਜਲਾਸ ਨੂੰ ਰੋਕਣਾ ਤੁਹਾਡਾ ਕਮਰੇ ਨਾਲੋਂ ਨਾਤਾ ਤੋੜ ਦੇਵੇਗਾ, ਪਰ ਤੁਸੀਂ ਸਥਾਨਕ ਪੱਧਰ \'ਤੇ ਦ੍ਰਿਸ਼ ਨਾਲ ਕੰਮ ਕਰਨਾ ਜਾਰੀ ਰੱਖ ਸਕੋਗੇ। ਇਹ ਧਿਆਨ \'ਚ ਰੱਖੋ ਕਿ ਇਹ ਬਾਕੀ ਲੋਕਾਂ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਨਹੀਂ ਕਰੇਗਾ , ਅਤੇ ਉਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਸੰਸਕਰਨ \'ਤੇ ਸਹਿਯੋਗ ਕਰਨ ਦੇ ਕਾਬਲ ਹੋਣਗੇ।","shareTitle":"Excalidraw \'ਤੇ ਲਾਈਵ ਇਜਲਾਸ ਦਾ ਹਿੱਸਾ ਬਣੋ"},"errorDialog":{"title":"ਗਲਤੀ"},"exportDialog":{"disk_title":"ਡਿਸਕ ਵਿੱਚ ਸਾਂਭੋ","disk_details":"ਦ੍ਰਿਸ਼ ਦਾ ਡਾਟਾ ਫਾਈਲ ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ ਜਿੱਥੋਂ ਤੁਸੀਂ ਇਸਨੂੰ ਬਾਅਦ ਵਿੱਚ ਆਯਾਤ ਕਰ ਸਕਦੇ ਹੋ।","disk_button":"ਫਾਈਲ ਵਿੱਚ ਸਾਂਭੋ","link_title":"ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ","link_details":"ਸਿਰਫ ਦੇਖੇ-ਜਾਣ ਵਾਲੀ ਲਿੰਕ ਵਜੋਂ ਨਿਰਯਾਤ ਕਰੋ।","link_button":"ਲਿੰਕ ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ","excalidrawplus_description":"ਆਪਣੇ ਦ੍ਰਿਸ਼ ਦੇ ਡਾਟੇ ਨੂੰ Excalidraw+ ਵਰਕਸਪੇਸ ਵਿੱਚ ਸਾਂਭੋ।","excalidrawplus_button":"ਨਿਰਯਾਤ ਕਰੋ","excalidrawplus_exportError":"ਇਸ ਸਮੇਂ Excalidraw+ ਵਿੱਚ ਨਿਰਯਾਤ ਨਹੀਂ ਕਰ ਸਕੇ..."},"helpDialog":{"blog":"ਸਾਡਾ ਬਲੌਗ ਪੜ੍ਹੋ","click":"ਕਲਿੱਕ","deepSelect":"","deepBoxSelect":"","curvedArrow":"ਵਿੰਗਾ ਤੀਰ","curvedLine":"ਵਿੰਗੀ ਲਕੀਰ","documentation":"ਕਾਗਜ਼ਾਤ","doubleClick":"ਡਬਲ-ਕਲਿੱਕ","drag":"ਘਸੀਟੋ","editor":"ਸੋਧਕ","editLineArrowPoints":"","editText":"","github":"ਕੋਈ ਸਮੱਸਿਆ ਲੱਭੀ? ਜਮ੍ਹਾਂ ਕਰਵਾਓ","howto":"ਸਾਡੀਆਂ ਗਾਈਡਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ","or":"ਜਾਂ","preventBinding":"ਤੀਰ ਬੱਝਣਾ ਰੋਕੋ","tools":"ਟੂਲ","shortcuts":"ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ","textFinish":"ਸੋਧਣਾ ਮੁਕੰਮਲ ਕਰੋ (ਪਾਠ ਸੋਧਕ)","textNewLine":"ਨਵੀਂ ਪੰਕਤੀ ਜੋੜੋ (ਪਾਠ ਸੋਧਕ)","title":"ਮਦਦ","view":"ਦਿੱਖ","zoomToFit":"ਸਾਰੇ ਐਲੀਮੈਂਟਾਂ ਨੂੰ ਫਿੱਟ ਕਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ","zoomToSelection":"ਚੋਣ ਤੱਕ ਜ਼ੂਮ ਕਰੋ","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":"ਕੈਨਵਸ ਨੂੰ ਸਾਫ਼ ਕਰੋ"},"publishDialog":{"title":"ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਪ੍ਰਕਾਸ਼ਤ ਕਰੋ","itemName":"ਚੀਜ਼ ਦਾ ਨਾਂ","authorName":"ਲੇਖਕ ਦਾ ਨਾਂ","githubUsername":"ਗਿੱਟਹੱਬ ਵਰਤੋਂਕਾਰ ਨਾਂ","twitterUsername":"ਟਵਿੱਟਰ ਦਾ ਵਰਤੋਂਕਾਰ-ਨਾਂ","libraryName":"ਲਾਇਬ੍ਰੇਰੀ ਦਾ ਨਾਂ","libraryDesc":"ਲਾਇਬ੍ਰੇਰੀ ਦਾ ਵੇਰਵਾ","website":"ਵੈੱਬਸਾਇਟ","placeholder":{"authorName":"ਤੁਹਾਡਾ ਨਾਂ ਜਾਂ ਵਰਤੋਂਕਾਰ-ਨਾਂ","libraryName":"ਤੁਹਾਡੀ ਲਾਇਬਰ੍ਰੀ ਦਾ ਨਾਂ","libraryDesc":"ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਦਾ ਵੇਰਵਾ ਤਾਂ ਜੋ ਲੋਕਾਂ ਨੂੰ ਇਸ ਤੋੰਂ ਇਸਦੀ ਵਰਤੋਂ ਕਰਨ ਸਬੰਧੀ ਮਦਦ ਮਿਲ ਸਕੇ","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"ਲੋੜੀਂਦਾ","website":"ਜਾਇਜ਼ URL ਭਰੋ"},"noteDescription":"ਹੋਰ ਲੋਕਾਂ ਵੱਲੋਂ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਵਰਤਣ ਲਈ ਸਕਣ ਇਸ ਲਈਜਨਤਕ ਲਾਇਬ੍ਰੇਰੀ ਦੀ ਰਿਪਾਜ਼ੀਟਰੀ ਵਿੱਚ ਆਪਣੀ ਲਾਇਬ੍ਰੇਰੀ ਸ਼ਾਮਲ ਕਰਵਾਉਣ ਲਈ ਜਮ੍ਹਾ ਕਰਵਾਓ","noteGuidelines":"ਦਿਸ਼ਾ ਨਿਰਦੇਸ਼","noteLicense":"MIT ਲਾਇਸੈਂਸ, ","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"ਲਾਇਬ੍ਰੇਰੀ ਜਮ੍ਹਾਂ ਕਰਵਾਈ","content":"ਧੰਨਵਾਦ {{authorName}} ਜੀਉ। ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਸਮੀਖਿਆ ਲਈ ਭੇਜ ਦਿੱਤਾ ਗਿਆ ਹੈ। ਤੁਸੀਂ ਉਸਦੀ ਸਥਿਤੀ ਇੱਥੇ ਦੇਖ ਸਕਦੇ ਹੋ।"},"confirmDialog":{"resetLibrary":"ਲਾਇਬ੍ਰੇਰੀ ਰੀਸੈੱਟ ਕਰੋ","removeItemsFromLib":"ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚੋਂ ਚੁਣੀਆਂ ਹੋਈਆਂ ਆਈਟਮਾਂ ਹਟਾਓ"},"imageExportDialog":{"header":"ਤਸਵੀਰ ਨਿਰਯਾਤ ਕਰੋ","label":{"withBackground":"ਪਿਛੋਕੜ","onlySelected":"ਸਿਰਫ ਚੁਣੇ ਹੋਏ","darkMode":"ਡਾਰਕ ਮੋਡ","embedScene":"ਦ੍ਰਿਸ਼ ਮੜ੍ਹੋ","scale":"ਸਕੇਲ","padding":"ਪੈਡਿੰਗ"},"tooltip":{"embedScene":""},"title":{"exportToPng":"PNG ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ","exportToSvg":"SVG ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ","copyPngToClipboard":"PNG ਨੂੰ ਕਲਿੱਪੋਬਰਡ ‘ਤੇ ਕਾਪੀ ਕਰੋ"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"ਗੱਤੇ \'ਤੇ ਕਾਪੀ ਕਰੋ"}},"encrypted":{"tooltip":"ਤੁਹਾਡੀ ਡਰਾਇੰਗਾਂ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਟ ਕੀਤੀਆਂ ਹੋਈਆਂ ਹਨ, ਇਸ ਲਈ Excalidraw ਦੇ ਸਰਵਰ ਉਹਨਾਂ ਨੂੰ ਕਦੇ ਵੀ ਨਹੀਂ ਦੇਖਣਗੇ।","link":"Excalidraw ਵਿੱਚ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕ੍ਰਿਪਸ਼ਨ \'ਤੇ ਬਲੌਗ ਸੰਪਾਦਨਾ"},"stats":{"angle":"ਕੋਣ","element":"ਐਲੀਮੈਂਟ","elements":"ਐਲੀਮੈਂਟ","height":"ਉਚਾਈ","scene":"ਦ੍ਰਿਸ਼","selected":"ਚੁਣੇ","storage":"ਸਟੋਰੇਜ","title":"ਪੜਾਕੂਆਂ ਲਈ ਅੰਕੜੇ","total":"ਕੁੱਲ","version":"ਸੰਸਕਰਨ","versionCopy":"ਕਾਪੀ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ","versionNotAvailable":"ਸੰਸਕਰਨ ਉਪਲਬਧ ਨਹੀਂ ਹੈ","width":"ਚੌੜਾਈ"},"toast":{"addedToLibrary":"ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਜੋੜਿਆ","copyStyles":"ਕਾਪੀ ਕੀਤੇ ਸਟਾਇਲ।","copyToClipboard":"ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ।","copyToClipboardAsPng":"{{exportSelection}} ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕੀਤਾ ({{exportColorScheme}})","fileSaved":"ਫਾਈਲ ਸਾਂਭੀ ਗਈ।","fileSavedToFilename":"{filename} ਵਿੱਚ ਸਾਂਭੀ","canvas":"ਕੈਨਵਸ","selection":"ਚੋਣ","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"ਪਾਰਦਰਸ਼ੀ","black":"ਕਾਲੀ","white":"ਸਫ਼ੈਦ","red":"ਲਾਲ","pink":"ਗੁਲਾਬੀ","grape":"ਅੰਗੂਰੀ","violet":"ਜਾਮਣੀ","gray":"ਸੁਰਮਈ","blue":"ਨੀਲਾ","cyan":"ਫਿਰੋਜੀ","teal":"ਟੀਲ","green":"ਹਰਾ","yellow":"ਪੀਲਾ","orange":"ਸੰਤਰੀ","bronze":"ਕਾਂਸੇਰੰਗਾ"},"welcomeScreen":{"app":{"center_heading":"ਤੁਹਾਡਾ ਸਾਰਾ ਡਾਟਾ ਤੁਹਾਡੇ ਲੋਕਲ ਬਰਾਉਜ਼ਰ ਵਿੱਚ ਸਾਂਭਿਆ ਹੋਇਆ ਹੈ।","center_heading_plus":"","menuHint":"ਨਿਰਯਾਤ, ਤਰਜੀਹਾਂ, ਭਾਸ਼ਾਵਾਂ, …"},"defaults":{"menuHint":"ਨਿਰਯਾਤ, ਤਰਜੀਹਾਂ, ਅਤੇ ਹੋਰ ਵੀ ਬਹੁਤ ਕੁਝ…","center_heading":"ਡਾਇਆਗ੍ਰਾਮਾਂ। ਕੀਤੀਆਂ। ਸੁਖਾਲੀਆਂ।","toolbarHint":"","helpHint":"ਸ਼ਾਰਟਕੱਟ ਤੇ ਮਦਦ"}},"colorPicker":{"mostUsedCustomColors":"ਸਭ ਤੋਂ ਵੱਧ ਵਰਤੇ ਜਾਣ ਵਾਲੇ ਕਸਟਮ ਰੰਗ","colors":"ਰੰਗ","shades":"ਸ਼ੇਡਾਂ","hexCode":"ਹੈਕਸ ਕੋਡ","noShades":"ਇਸ ਰੰਗ ਦੀ ਕੋਈ ਸ਼ੇਡ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/pl-PL-json-9bb55330d5aaf336646e.js b/public/excalidraw/excalidraw-assets-dev/locales/pl-PL-json-9bb55330d5aaf336646e.js
new file mode 100644
index 0000000..93620f2
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/pl-PL-json-9bb55330d5aaf336646e.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/pl-PL-json"],{
+
+/***/ "../../locales/pl-PL.json":
+/*!********************************!*\
+ !*** ../../locales/pl-PL.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Wklej","pasteAsPlaintext":"Wklej jako zwykły tekst","pasteCharts":"Wklej wykresy","selectAll":"Zaznacz wszystko","multiSelect":"Dodaj element do zaznaczenia","moveCanvas":"Przesuń obszar roboczy","cut":"Wytnij","copy":"Kopiuj","copyAsPng":"Skopiuj do schowka jako plik PNG","copyAsSvg":"Skopiuj do schowka jako plik SVG","copyText":"Skopiuj do schowka jako tekst","bringForward":"Przenieś wyżej","sendToBack":"Przenieś na spód","bringToFront":"Przenieś na wierzch","sendBackward":"Przenieś niżej","delete":"Usuń","copyStyles":"Kopiuj style","pasteStyles":"Wklej style","stroke":"Kolor obramowania","background":"Kolor wypełnienia","fill":"Wypełnienie","strokeWidth":"Grubość obramowania","strokeStyle":"Styl obrysu","strokeStyle_solid":"Pełny","strokeStyle_dashed":"Kreskowany","strokeStyle_dotted":"Kropkowany","sloppiness":"Styl kreski","opacity":"Przeźroczystość","textAlign":"Wyrównanie tekstu","edges":"Krawędzie","sharp":"Ostry","round":"Zaokrąglij","arrowheads":"Groty","arrowhead_none":"Brak","arrowhead_arrow":"Strzałka","arrowhead_bar":"Kreska","arrowhead_dot":"Kropka","arrowhead_triangle":"Trójkąt","fontSize":"Rozmiar tekstu","fontFamily":"Krój pisma","addWatermark":"Dodaj \\"Zrobione w Excalidraw\\"","handDrawn":"Odręczny","normal":"Normalny","code":"Kod","small":"Mały","medium":"Średni","large":"Duży","veryLarge":"Bardzo duży","solid":"Pełne","hachure":"Linie","zigzag":"Zygzak","crossHatch":"Zakreślone","thin":"Cienkie","bold":"Pogrubione","left":"Do lewej","center":"Do środka","right":"Do prawej","extraBold":"Ekstra pogrubione","architect":"Dokładny","artist":"Artystyczny","cartoonist":"Rysunkowy","fileTitle":"Nazwa pliku","colorPicker":"Paleta kolorów","canvasColors":"Używane na płótnie","canvasBackground":"Kolor dokumentu","drawingCanvas":"Obszar roboczy","layers":"Warstwy","actions":"Akcje","language":"Język","liveCollaboration":"Współpraca w czasie rzeczywistym...","duplicateSelection":"Powiel","untitled":"Bez tytułu","name":"Nazwa","yourName":"Twoje imię","madeWithExcalidraw":"Zrobione w Excalidraw","group":"Zgrupuj wybrane","ungroup":"Rozgrupuj wybrane","collaborators":"Współtwórcy","showGrid":"Pokaż siatkę","addToLibrary":"Dodaj do biblioteki","removeFromLibrary":"Usuń z biblioteki","libraryLoadingMessage":"Wczytywanie biblioteki…","libraries":"Przeglądaj biblioteki","loadingScene":"Wczytywanie sceny…","align":"Wyrównaj","alignTop":"Wyrównaj do góry","alignBottom":"Wyrównaj do dołu","alignLeft":"Wyrównaj do lewej","alignRight":"Wyrównaj do prawej","centerVertically":"Wyśrodkuj w pionie","centerHorizontally":"Wyśrodkuj w poziomie","distributeHorizontally":"Rozłóż poziomo","distributeVertically":"Rozłóż pionowo","flipHorizontal":"Odwróć w poziomie","flipVertical":"Odwróć w pionie","viewMode":"Tryb widoku","share":"Udostępnij","showStroke":"Pokaż próbnik kolorów obrysu","showBackground":"Pokaż próbnik koloru tła","toggleTheme":"Przełącz motyw","personalLib":"Biblioteka prywatna","excalidrawLib":"Biblioteka Excalidraw","decreaseFontSize":"Zmniejsz rozmiar czcionki","increaseFontSize":"Zwiększ rozmiar czcionki","unbindText":"Odłącz tekst od kontenera","bindText":"Połącz tekst z kontenerem","createContainerFromText":"Zawijaj tekst w kontenerze","link":{"edit":"Edytuj łącze","editEmbed":"Edytuj i osadź link","create":"Utwórz łącze","createEmbed":"Stwórz i osadź link","label":"Łącze","labelEmbed":"Podlinkuj i osadź","empty":"Brakujący link"},"lineEditor":{"edit":"Edytuj linię","exit":"Wyjdź z edytora linii"},"elementLock":{"lock":"Zablokuj","unlock":"Odblokuj","lockAll":"Zablokuj wszystko","unlockAll":"Odblokuj wszystko"},"statusPublished":"Opublikowano","sidebarLock":"Panel boczny zawsze otwarty","selectAllElementsInFrame":"Zaznacz wszystkie elementy w ramce","removeAllElementsFromFrame":"Usuń wszystkie elementy z ramki","eyeDropper":"Wybierz kolor z płótna"},"library":{"noItems":"Nie dodano jeszcze żadnych elementów...","hint_emptyLibrary":"Wybierz element na płótnie, aby go tutaj dodać, lub zainstaluj bibliotekę z poniższego publicznego repozytorium.","hint_emptyPrivateLibrary":"Wybierz element, aby dodać go tutaj."},"buttons":{"clearReset":"Wyczyść dokument i zresetuj kolor dokumentu","exportJSON":"Eksportuj do pliku","exportImage":"Eksportuj obraz...","export":"Zapisz jako...","copyToClipboard":"Skopiuj do schowka","save":"Zapisz do bieżącego pliku","saveAs":"Zapisz jako","load":"Otwórz","getShareableLink":"Udostępnij","close":"Zamknij","selectLanguage":"Wybierz język","scrollBackToContent":"Wróć do obszaru roboczego","zoomIn":"Powiększ","zoomOut":"Pomniejsz","resetZoom":"Zresetuj powiększenie","menu":"Menu","done":"Gotowe","edit":"Edytuj","undo":"Cofnij","redo":"Przywróć","resetLibrary":"Resetuj bibliotekę","createNewRoom":"Utwórz nowy pokój","fullScreen":"Pełny ekran","darkMode":"Ciemny motyw","lightMode":"Jasny motyw","zenMode":"Tryb Zen","objectsSnapMode":"Przyciąganie do obiektów","exitZenMode":"Wyjdź z trybu Zen","cancel":"Anuluj","clear":"Wyczyść","remove":"Usuń","embed":"Przełącz osadzenie","publishLibrary":"Opublikuj","submit":"Prześlij","confirm":"Zatwierdź","embeddableInteractionButton":"Kliknij, aby wejść w interakcję"},"alerts":{"clearReset":"To spowoduje usunięcie wszystkiego z dokumentu. Czy chcesz kontynuować?","couldNotCreateShareableLink":"Wystąpił błąd przy generowaniu linka do udostępniania.","couldNotCreateShareableLinkTooBig":"Nie można utworzyć linku do udostępnienia: scena jest za duża","couldNotLoadInvalidFile":"Nie udało się otworzyć pliku. Wybrany plik jest nieprawidłowy.","importBackendFailed":"Wystąpił błąd podczas importowania pliku.","cannotExportEmptyCanvas":"Najpierw musisz coś narysować, aby zapisać dokument.","couldNotCopyToClipboard":"Nie udało się skopiować do schowka.","decryptFailed":"Nie udało się odszyfrować danych.","uploadedSecurly":"By zapewnić Ci prywatność, udostępnianie projektu jest zabezpieczone szyfrowaniem end-to-end, co oznacza, że poza tobą i osobą z którą podzielisz się linkiem, nikt nie ma dostępu do tego co udostępniasz.","loadSceneOverridePrompt":"Wczytanie zewnętrznego rysunku zastąpi istniejącą zawartość. Czy chcesz kontynuować?","collabStopOverridePrompt":"Zatrzymanie sesji nadpisze poprzedni, zapisany lokalnie rysunek. Czy jesteś pewien?\\n\\n(Jeśli chcesz zachować swój lokalny rysunek, po prostu zamknij zakładkę przeglądarki.)","errorAddingToLibrary":"Nie udało się dodać elementu do biblioteki","errorRemovingFromLibrary":"Nie udało się usunąć elementu z biblioteki","confirmAddLibrary":"To doda {{numShapes}} kształtów do twojej biblioteki. Jesteś pewien?","imageDoesNotContainScene":"Ten obraz nie zawiera żadnych informacji o scenie. Czy włączyłeś osadzanie sceny podczas eksportu?","cannotRestoreFromImage":"Scena nie mogła zostać przywrócona z pliku obrazu","invalidSceneUrl":"Nie udało się zaimportować sceny z podanego adresu URL. Jest ona wadliwa lub nie zawiera poprawnych danych Excalidraw w formacie JSON.","resetLibrary":"To wyczyści twoją bibliotekę. Jesteś pewien?","removeItemsFromsLibrary":"Usunąć {{count}} element(ów) z biblioteki?","invalidEncryptionKey":"Klucz szyfrowania musi składać się z 22 znaków. Współpraca na żywo jest wyłączona.","collabOfflineWarning":"Brak połączenia z Internetem.\\nTwoje zmiany nie zostaną zapisane!"},"errors":{"unsupportedFileType":"Nieobsługiwany typ pliku.","imageInsertError":"Nie udało się wstawić obrazu. Spróbuj ponownie później...","fileTooBig":"Plik jest zbyt duży. Maksymalny dozwolony rozmiar to {{maxSize}}.","svgImageInsertError":"Nie udało się wstawić obrazu SVG. Znacznik SVG wygląda na nieprawidłowy.","failedToFetchImage":"Nie udało się załadować obrazu.","invalidSVGString":"Nieprawidłowy SVG.","cannotResolveCollabServer":"Nie można połączyć się z serwerem współpracy w czasie rzeczywistym. Proszę odświeżyć stronę i spróbować ponownie.","importLibraryError":"Wystąpił błąd w trakcie ładowania biblioteki","collabSaveFailed":"Nie udało się zapisać w bazie danych. Jeśli problemy nie ustąpią, zapisz plik lokalnie, aby nie utracić swojej pracy.","collabSaveFailed_sizeExceeded":"Nie udało się zapisać w bazie danych — dokument jest za duży. Zapisz plik lokalnie, aby nie utracić swojej pracy.","brave_measure_text_error":{"line1":"Wygląda na to, że używasz przeglądarki Brave z włączonym ustawieniem Agressively Block Fingerprinting.","line2":"Może to doprowadzić do złamania elementów tekstu na rysunkach.","line3":"Zdecydowanie zalecamy wyłączenie tego ustawienia. Możesz wykonać te kroki, aby to zrobić.","line4":"Jeśli wyłączenie tego ustawienia nie naprawia wyświetlania elementów tekstowych, zgłoś problem na naszym GitHubie lub napisz do nas na Discordzie"},"libraryElementTypeError":{"embeddable":"Elementy osadzone nie mogą zostać dodane do biblioteki.","image":"Dodawania obrazów do biblioteki nadejdzie wkrótce!"}},"toolBar":{"selection":"Zaznaczenie","image":"Wstaw obraz","rectangle":"Prostokąt","diamond":"Romb","ellipse":"Elipsa","arrow":"Strzałka","line":"Linia","freedraw":"Rysuj","text":"Tekst","library":"Biblioteka","lock":"Zablokuj wybrane narzędzie","penMode":"Tryb pióra — zapobiegaj dotknięciom","link":"Dodaj/aktualizuj link dla wybranego kształtu","eraser":"Gumka","frame":"Ramka","embeddable":"Osadzenie z internetu","laser":"Wskaźnik laserowy","hand":"Ręka (narzędzie do przesuwania)","extraTools":"Więcej narzędzi"},"headings":{"canvasActions":"Narzędzia","selectedShapeActions":"Wybrane narzędzie","shapes":"Kształty"},"hints":{"canvasPanning":"Aby przesunąć płótno, przytrzymaj kółko myszy lub spację podczas przeciągania, albo użyj narzędzia ręki","linearElement":"Naciśnij, aby zrobić punkt, przeciągnij, aby narysować linię","freeDraw":"Naciśnij i przeciągnij by rysować, puść kiedy skończysz","text":"Wskazówka: możesz również dodać tekst klikając dwukrotnie gdziekolwiek za pomocą narzędzia zaznaczania","embeddable":"Kliknij i przeciągnij, aby stworzyć osadzenie strony","text_selected":"Kliknij dwukrotnie lub naciśnij ENTER, aby edytować tekst","text_editing":"Naciśnij Escape lub Ctrl (Cmd w macOS) + ENTER, aby zakończyć edycję","linearElementMulti":"Aby zakończyć krzywą, ponownie kliknij w ostatni punkt, bądź naciśnij Esc albo Enter","lockAngle":"Możesz ograniczyć kąt trzymając SHIFT","resize":"Możesz zachować proporcję trzymająć wcisnięty SHIFT, przytrzymaj ALT by zmienić rozmiar względem środka","resizeImage":"Możesz zmienić rozmiar swobodnie trzymając SHIFT,\\nprzytrzymaj ALT, aby przeskalować względem środka obiektu","rotate":"Możesz obracać element w równych odstępach trzymając wciśnięty SHIFT","lineEditor_info":"Przytrzymaj CtrlOrCmd i kliknij dwukrotnie lub naciśnij CtrlOrCmd + Enter, aby edytować punkty","lineEditor_pointSelected":"Naciśnij przycisk Delete, aby usunąć punkt. Ctrl/Cmd+D, aby go zduplikować. Przeciągnij, aby go przenieść","lineEditor_nothingSelected":"Wybierz punkt do edycji (przytrzymaj SHIFT, aby wybrać wiele),\\nlub przytrzymaj Alt i kliknij, aby dodać nowe punkty","placeImage":"Kliknij, aby umieścić obraz, lub kliknij i przeciągnij, aby ustawić jego rozmiar ręcznie","publishLibrary":"Opublikuj własną bibliotekę","bindTextToElement":"Wciśnij enter, aby dodać tekst","deepBoxSelect":"Przytrzymaj CtrlOrCmd, aby wybrać w obrębie grupy i uniknąć przeciągania","eraserRevert":"Przytrzymaj Alt, aby przywrócić elementy oznaczone do usunięcia","firefox_clipboard_write":"Ta funkcja może być włączona poprzez ustawienie flagi \\"dom.events.asyncClipboard.clipboardItem\\" na \\"true\\". Aby zmienić flagi przeglądarki w Firefox, odwiedź stronę \\"about:config\\".","disableSnapping":"Przytrzymaj Ctrl lub Cmd, aby wyłączyć przyciąganie"},"canvasError":{"cannotShowPreview":"Nie można wyświetlić podglądu","canvasTooBig":"Obszar roboczy może być za duży.","canvasTooBigTip":"Wskazówka: spróbuj nieco zbliżyć najdalej wysunięte elementy."},"errorSplash":{"headingMain":"Wystąpił błąd. Spróbuj ","clearCanvasMessage":"Jeśli odświeżenie strony nie zadziałało, spróbuj ","clearCanvasCaveat":" Pamiętaj tylko, że spowoduje to utratę całej twojej pracy ","trackedToSentry":"Błąd o identyfikatorze {{eventId}} został zaraportowany w naszym systemie.","openIssueMessage":"Szanujemy twoją prywatność i raport nie zawierał żadnych danych dotyczących tego nad czym pracowałeś, natomiast jeżeli jesteś w stanie podzielić się tym nad czym pracowałeś, prosimy o dodatkowy raport poprzez Prosimy o dołączenie poniższej informacji poprzez skopiowanie jej i umieszczenie jej w zgłoszeniu na portalu GitHub.","sceneContent":"Zawartość dokumentu:"},"roomDialog":{"desc_intro":"Będziesz w stanie pracować wraz z osobami które zaprosisz do współpracy.","desc_privacy":"By zapewnić Ci prywatność, sesja współpracy na żywo jest zabezpieczona szyfrowaniem end-to-end, co oznacza, że poza tobą i osobami z którymi podzielisz się linkiem, nikt nie ma dostępu do tego co będziecie tworzyć.","button_startSession":"Rozpocznij sesję","button_stopSession":"Zakończ sesję","desc_inProgressIntro":"Sesja współpracy na żywo właśnie się rozpoczęła.","desc_shareLink":"Udostępnij ten link osobom, z którymi chcesz współpracować:","desc_exitSession":"Zakończenie sesji spowoduje odłączenie ciebie od pokoju, ale nadal będziesz mógł lokalnie kontynuować pracę. Zauważ, że osoby z którymi współpracowałeś nadal będą mogły współpracować.","shareTitle":"Dołącz do sesji współpracy na żywo w Excalidraw"},"errorDialog":{"title":"Wystąpił błąd"},"exportDialog":{"disk_title":"Zapisz na dysku","disk_details":"Eksportuj dane sceny do pliku, z którego możesz importować później.","disk_button":"Zapisz do pliku","link_title":"Link do udostępnienia","link_details":"Eksportuj jako link tylko do odczytu.","link_button":"Wygeneruj link","excalidrawplus_description":"Zapisz scenę do swojego obszaru roboczego Excalidraw+.","excalidrawplus_button":"Eksportuj","excalidrawplus_exportError":"W tej chwili nie można wyeksportować do Excalidraw+..."},"helpDialog":{"blog":"Przeczytaj na naszym blogu","click":"kliknięcie","deepSelect":"Wybór w obrębie grupy","deepBoxSelect":"Wybór w obrębie grupy i unikanie przeciągania","curvedArrow":"Zakrzywiona strzałka","curvedLine":"Zakrzywiona linia","documentation":"Dokumentacja","doubleClick":"podwójne kliknięcie","drag":"przeciągnij","editor":"Edytor","editLineArrowPoints":"Edytuj punkty linii/strzałki","editText":"Edytuj tekst/dodaj etykietę","github":"Znalazłeś problem? Prześlij","howto":"Skorzystaj z instrukcji","or":"lub","preventBinding":"Zapobiegaj wiązaniu strzałek","tools":"Narzędzia","shortcuts":"Skróty klawiszowe","textFinish":"Zakończ edycję (edytor tekstu)","textNewLine":"Dodaj nowy wiersz (edytor tekstu)","title":"Pomoc","view":"Widok","zoomToFit":"Powiększ, aby wyświetlić wszystkie elementy","zoomToSelection":"Przybliż do zaznaczenia","toggleElementLock":"Zablokuj/odblokuj zaznaczenie","movePageUpDown":"Przesuń stronę w górę/w dół","movePageLeftRight":"Przenieś stronę w lewo/prawo"},"clearCanvasDialog":{"title":"Wyczyść płótno"},"publishDialog":{"title":"Opublikuj bibliotekę","itemName":"Nazwa elementu","authorName":"Nazwa autora","githubUsername":"Nazwa użytkownika na GitHubie","twitterUsername":"Nazwa użytkownika Twitter","libraryName":"Nazwa biblioteki","libraryDesc":"Opis biblioteki","website":"Strona internetowa","placeholder":{"authorName":"Twoje imię lub nazwa użytkownika","libraryName":"Nazwa twojej biblioteki","libraryDesc":"Opis twojej biblioteki, aby pomóc innym zrozumieć jej działanie","githubHandle":"Uchwyt GitHub (opcjonalny), dzięki czemu możesz edytować bibliotekę po przesłaniu do sprawdzenia","twitterHandle":"Nazwa użytkownika w serwisie Twitter (opcjonalna), aby wiedzieć kogo oznaczyć przy promowaniu na Twitterze","website":"Link do Twojej osobistej strony internetowej lub gdzie indziej (opcjonalnie)"},"errors":{"required":"Wymagane","website":"Wprowadź prawidłowy adres URL"},"noteDescription":"dla innych osób do wykorzystania w swoich rysunkach.","noteGuidelines":"Biblioteka musi być najpierw zatwierdzona ręcznie. Przeczytaj wytyczne","noteLicense":"Wysyłając zgadzasz się, że biblioteka zostanie opublikowana pod Licencja MIT, w skrócie, każdy może z nich korzystać bez ograniczeń.","noteItems":"Każdy element biblioteki musi mieć własną nazwę, aby był filtrowalny. Uwzględnione zostaną następujące elementy biblioteki:","atleastOneLibItem":"Proszę wybrać co najmniej jeden element biblioteki, by rozpocząć","republishWarning":"Uwaga: niektóre z wybranych elementów są oznaczone jako już opublikowane/wysłane. Powinieneś ponownie przesłać elementy tylko wtedy, gdy aktualizujesz istniejącą bibliotekę lub zgłoszenie."},"publishSuccessDialog":{"title":"Biblioteka została przesłana","content":"Dziękujemy {{authorName}}. Twoja biblioteka została przesłana do sprawdzenia. Możesz śledzić jej stantutaj"},"confirmDialog":{"resetLibrary":"Zresetuj Bibliotekę","removeItemsFromLib":"Usuń wybrane elementy z biblioteki"},"imageExportDialog":{"header":"Eksportuj obraz","label":{"withBackground":"Tło","onlySelected":"Tylko wybrane","darkMode":"Tryb ciemny","embedScene":"Osadź scenę","scale":"Skala","padding":"Dopełnienie"},"tooltip":{"embedScene":"Dane sceny zostaną zapisane w eksportowanym pliku PNG/SVG tak, aby scena mogła zostać z niego przywrócona.\\nZwiększy to rozmiar eksportowanego pliku."},"title":{"exportToPng":"Zapisz jako PNG","exportToSvg":"Zapisz jako SVG","copyPngToClipboard":"Skopiuj do schowka jako PNG"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Skopiuj do schowka"}},"encrypted":{"tooltip":"Twoje rysunki są zabezpieczone szyfrowaniem end-to-end, tak więc nawet w Excalidraw nie jesteśmy w stanie zobaczyć tego co tworzysz.","link":"Wpis na blogu dotyczący szyfrowania end-to-end w Excalidraw"},"stats":{"angle":"Kąt","element":"Element","elements":"Elementy","height":"Wysokość","scene":"Scena","selected":"Zaznaczenie","storage":"Pamięć","title":"Statystyki dla nerdów","total":"Łącznie","version":"Wersja","versionCopy":"Kliknij, aby skopiować","versionNotAvailable":"Wersja niedostępna","width":"Szerokość"},"toast":{"addedToLibrary":"Dodano do biblioteki","copyStyles":"Skopiowano style.","copyToClipboard":"Skopiowano do schowka.","copyToClipboardAsPng":"Skopiowano {{exportSelection}} do schowka jako PNG\\n({{exportColorScheme}})","fileSaved":"Zapisano plik.","fileSavedToFilename":"Zapisano jako {filename}","canvas":"płótno","selection":"zaznaczenie","pasteAsSingleElement":"Użyj {{shortcut}}, aby wkleić jako pojedynczy element,\\nlub wklej do istniejącego edytora tekstu","unableToEmbed":"Osadzenie tego linku jest obecnie niedozwolone. Zgłoś propozycję na portalu GitHub, aby dodać go do listy dozwolonych wyjątków","unrecognizedLinkFormat":"Osadzony link ma niewłaściwy format. Spróbuj wkleić całą zawartość pola \\"embed\\" z oryginalnej strony."},"colors":{"transparent":"Przezroczysty","black":"Czarny","white":"Biały","red":"Czerwony","pink":"Różowy","grape":"Winogronowy","violet":"Fioletowy","gray":"Szary","blue":"Niebieski","cyan":"Cyjanowy","teal":"Turkusowy","green":"Zielony","yellow":"Żółty","orange":"Pomarańczowy","bronze":"Brązowy"},"welcomeScreen":{"app":{"center_heading":"Wszystkie dane są zapisywane lokalnie w przeglądarce.","center_heading_plus":"Czy zamiast tego chcesz przejść do Excalidraw+?","menuHint":"Eksportuj, preferencje, języki..."},"defaults":{"menuHint":"Eksportuj, preferencje i więcej...","center_heading":"Schematy uproszczone.","toolbarHint":"Wybierz narzędzie i zacznij rysować!","helpHint":"Skróty klawiaturowe i pomoc"}},"colorPicker":{"mostUsedCustomColors":"Najczęściej używane kolory","colors":"Kolory","shades":"Odcienie","hexCode":"Kod HEX","noShades":"Brak dostępnych odcieni dla tego koloru"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Eksportuj jako obraz","button":"Eksportuj jako obraz","description":"Eksportuj zawartość sceny jako obraz z możliwością importowania."},"saveToDisk":{"title":"Zapisz na dysku","button":"Zapisz na dysku","description":"Eksportuj zawartość sceny jako plik z możliwością importowania."},"excalidrawPlus":{"title":"Excalidraw+","button":"Eksportuj do Excalidraw+","description":"Zapisz scenę do swojego obszaru roboczego Excalidraw+."}},"modal":{"loadFromFile":{"title":"Wczytaj z pliku","button":"Wczytaj z pliku","description":"Wczytanie z pliku nadpisze istniejącą zawartość. Możesz najpierw utworzyć kopię zapasową swojego rysunku, używając jednej z poniższych opcji."},"shareableLink":{"title":"Wczytaj z linku","button":"Nadpisz moją zawartość","description":"Wczytanie zewnętrznego pliku nadpisze istniejącą zawartość. Możesz najpierw utworzyć kopię zapasową swojego rysunku, używając jednej z poniższych opcji."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/pt-BR-json-3635e753c1b6e5b681fa.js b/public/excalidraw/excalidraw-assets-dev/locales/pt-BR-json-3635e753c1b6e5b681fa.js
new file mode 100644
index 0000000..ea80ec5
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/pt-BR-json-3635e753c1b6e5b681fa.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/pt-BR-json"],{
+
+/***/ "../../locales/pt-BR.json":
+/*!********************************!*\
+ !*** ../../locales/pt-BR.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Colar","pasteAsPlaintext":"Colar como texto sem formatação","pasteCharts":"Colar gráficos","selectAll":"Selecionar tudo","multiSelect":"Adicionar elemento à seleção","moveCanvas":"Mover tela","cut":"Recortar","copy":"Copiar","copyAsPng":"Copiar para a área de transferência como PNG","copyAsSvg":"Copiar para a área de transferência como SVG","copyText":"Copiar para área de transferência como texto","bringForward":"Trazer para a frente","sendToBack":"Enviar para o fundo","bringToFront":"Trazer para o primeiro plano","sendBackward":"Enviar para trás","delete":"Apagar","copyStyles":"Copiar os estilos","pasteStyles":"Colar os estilos","stroke":"Contorno","background":"Fundo","fill":"Preenchimento","strokeWidth":"Espessura do traço","strokeStyle":"Estilo de traço","strokeStyle_solid":"Sólido","strokeStyle_dashed":"Tracejado","strokeStyle_dotted":"Pontilhado","sloppiness":"Precisão do traço","opacity":"Opacidade","textAlign":"Alinhamento do texto","edges":"Arestas","sharp":"Pontudo","round":"Arredondado","arrowheads":"Pontas","arrowhead_none":"Nenhuma","arrowhead_arrow":"Flecha","arrowhead_bar":"Barra","arrowhead_dot":"Ponto","arrowhead_triangle":"Triângulo","fontSize":"Tamanho da fonte","fontFamily":"Família da fonte","addWatermark":"Adicionar \\"Feito com Excalidraw\\"","handDrawn":"Manuscrito","normal":"Normal","code":"Código","small":"Pequeno","medium":"Médio","large":"Grande","veryLarge":"Muito grande","solid":"Sólido","hachure":"Hachura","zigzag":"Zigue-zague","crossHatch":"Hachura cruzada","thin":"Fino","bold":"Espesso","left":"Esquerda","center":"Centralizar","right":"Direita","extraBold":"Muito espesso","architect":"Arquiteto","artist":"Artista","cartoonist":"Cartunista","fileTitle":"Nome do arquivo","colorPicker":"Seletor de cores","canvasColors":"Usado na tela","canvasBackground":"Fundo da tela","drawingCanvas":"Tela de desenho","layers":"Camadas","actions":"Ações","language":"Idioma","liveCollaboration":"Colaboração ao vivo...","duplicateSelection":"Duplicar","untitled":"Sem título","name":"Nome","yourName":"Seu nome","madeWithExcalidraw":"Feito com Excalidraw","group":"Agrupar seleção","ungroup":"Desagrupar seleção","collaborators":"Colaboradores","showGrid":"Mostrar grade","addToLibrary":"Adicionar à biblioteca","removeFromLibrary":"Remover da biblioteca","libraryLoadingMessage":"Carregando biblioteca…","libraries":"Procurar bibliotecas","loadingScene":"Carregando cena…","align":"Alinhamento","alignTop":"Alinhar ao topo","alignBottom":"Alinhar embaixo","alignLeft":"Alinhar à esquerda","alignRight":"Alinhar à direita","centerVertically":"Centralizar verticalmente","centerHorizontally":"Centralizar horizontalmente","distributeHorizontally":"Distribuir horizontalmente","distributeVertically":"Distribuir verticalmente","flipHorizontal":"Inverter horizontalmente","flipVertical":"Inverter verticalmente","viewMode":"Modo de visualização","share":"Compartilhar","showStroke":"Exibir seletor de cores do traço","showBackground":"Exibir seletor de cores do fundo","toggleTheme":"Alternar tema","personalLib":"Biblioteca Pessoal","excalidrawLib":"Biblioteca do Excalidraw","decreaseFontSize":"Diminuir o tamanho da fonte","increaseFontSize":"Aumentar o tamanho da fonte","unbindText":"Desvincular texto","bindText":"Vincular texto ao contêiner","createContainerFromText":"Envolver texto em um contêiner","link":{"edit":"Editar link","editEmbed":"","create":"Criar link","createEmbed":"","label":"Link","labelEmbed":"","empty":""},"lineEditor":{"edit":"Editar linha","exit":"Sair do editor de linha"},"elementLock":{"lock":"Bloquear","unlock":"Desbloquear","lockAll":"Bloquear tudo","unlockAll":"Desbloquear tudo"},"statusPublished":"Publicado","sidebarLock":"Manter barra lateral aberta","selectAllElementsInFrame":"Selecionar todos os elementos no quadro","removeAllElementsFromFrame":"Remover todos os elementos do quadro","eyeDropper":"Escolher cor da tela"},"library":{"noItems":"Nenhum item adicionado ainda...","hint_emptyLibrary":"Selecione um item na tela para adicioná-lo aqui, ou instale uma biblioteca do repositório público, abaixo.","hint_emptyPrivateLibrary":"Selecione um item na tela para adicioná-lo aqui."},"buttons":{"clearReset":"Limpar o canvas e redefinir a cor de fundo","exportJSON":"Exportar arquivo","exportImage":"Exportar imagem...","export":"Salvar como...","copyToClipboard":"Copiar para o clipboard","save":"Salvar para o arquivo atual","saveAs":"Salvar como","load":"Abrir","getShareableLink":"Obter um link de compartilhamento","close":"Fechar","selectLanguage":"Selecionar idioma","scrollBackToContent":"Voltar para o conteúdo","zoomIn":"Aumentar zoom","zoomOut":"Diminuir zoom","resetZoom":"Redefinir zoom","menu":"Menu","done":"Concluído","edit":"Editar","undo":"Desfazer","redo":"Refazer","resetLibrary":"Redefinir biblioteca","createNewRoom":"Criar nova sala","fullScreen":"Tela cheia","darkMode":"Modo escuro","lightMode":"Modo claro","zenMode":"Modo Zen","objectsSnapMode":"","exitZenMode":"Sair do modo zen","cancel":"Cancelar","clear":"Limpar","remove":"Remover","embed":"","publishLibrary":"Publicar","submit":"Enviar","confirm":"Confirmar","embeddableInteractionButton":""},"alerts":{"clearReset":"Isto irá limpar toda a tela. Você tem certeza?","couldNotCreateShareableLink":"Não foi possível criar um link de compartilhamento.","couldNotCreateShareableLinkTooBig":"Não foi possível criar um link compartilhável: a cena é muito grande","couldNotLoadInvalidFile":"Não foi possível carregar o arquivo inválido","importBackendFailed":"A importação do servidor falhou.","cannotExportEmptyCanvas":"Não é possível exportar um canvas vazio.","couldNotCopyToClipboard":"Não foi possível copiar para a área de transferência.","decryptFailed":"Não foi possível descriptografar os dados.","uploadedSecurly":"O upload foi protegido com criptografia de ponta a ponta, o que significa que o servidor do Excalidraw e terceiros não podem ler o conteúdo.","loadSceneOverridePrompt":"Carregar um desenho externo substituirá o seu conteúdo existente. Deseja continuar?","collabStopOverridePrompt":"Ao interromper a sessão, você substituirá seu desenho anterior, armazenado localmente. Você tem certeza?\\n\\n(Se você deseja manter seu desenho local, simplesmente feche a aba do navegador.)","errorAddingToLibrary":"Não foi possível adicionar o item à biblioteca","errorRemovingFromLibrary":"Não foi possível remover o item da biblioteca","confirmAddLibrary":"Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem certeza?","imageDoesNotContainScene":"Esta imagem parece não conter dados de cenas. Você ativou a incorporação da cena durante a exportação?","cannotRestoreFromImage":"Não foi possível restaurar a cena deste arquivo de imagem","invalidSceneUrl":"Não foi possível importar a cena da URL fornecida. Ela está incompleta ou não contém dados JSON válidos do Excalidraw.","resetLibrary":"Isto limpará a sua biblioteca. Você tem certeza?","removeItemsFromsLibrary":"Excluir {{count}} item(ns) da biblioteca?","invalidEncryptionKey":"A chave de encriptação deve ter 22 caracteres. A colaboração ao vivo está desabilitada.","collabOfflineWarning":"Sem conexão com a internet disponível.\\nSuas alterações não serão salvas!"},"errors":{"unsupportedFileType":"Tipo de arquivo não suportado.","imageInsertError":"Não foi possível inserir imagem. Tente novamente mais tarde...","fileTooBig":"O arquivo é muito grande. O tamanho máximo permitido é {{maxSize}}.","svgImageInsertError":"Não foi possível inserir a imagem SVG. A marcação SVG parece inválida.","failedToFetchImage":"","invalidSVGString":"SVG Inválido.","cannotResolveCollabServer":"Não foi possível conectar-se ao servidor colaborativo. Por favor, recarregue a página e tente novamente.","importLibraryError":"Não foi possível carregar a biblioteca","collabSaveFailed":"Não foi possível salvar no banco de dados do servidor. Se os problemas persistirem, salve o arquivo localmente para garantir que não perca o seu trabalho.","collabSaveFailed_sizeExceeded":"Não foi possível salvar no banco de dados do servidor, a tela parece ser muito grande. Se os problemas persistirem, salve o arquivo localmente para garantir que não perca o seu trabalho.","brave_measure_text_error":{"line1":"Parece que você está usando o navegador Brave com a configuração Bloquear Impressões Digitais no modo agressivo.","line2":"Isso pode acabar quebrando Elementos de Texto em seus desenhos.","line3":"Recomendamos fortemente desativar essa configuração. Você pode acessar o passo a passo sobre como fazer isso.","line4":"Se desativar essa configuração não corrigir a exibição de elementos de texto, por favor abra uma issue em nosso GitHub, ou mande uma mensagem em nosso Discord"},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Seleção","image":"Inserir imagem","rectangle":"Retângulo","diamond":"Losango","ellipse":"Elipse","arrow":"Flecha","line":"Linha","freedraw":"Desenhar","text":"Texto","library":"Biblioteca","lock":"Manter ativa a ferramenta selecionada após desenhar","penMode":"Modo caneta — impede o toque","link":"Adicionar/Atualizar link para uma forma selecionada","eraser":"Borracha","frame":"Ferramenta de quadro","embeddable":"","laser":"","hand":"Mão (ferramenta de rolagem)","extraTools":"Mais ferramentas"},"headings":{"canvasActions":"Ações da tela","selectedShapeActions":"Ações das formas selecionadas","shapes":"Formas"},"hints":{"canvasPanning":"Para mover a tela, segure a roda do mouse ou a barra de espaço enquanto arrasta ou use a ferramenta de mão","linearElement":"Clique para iniciar vários pontos, arraste para uma única linha","freeDraw":"Toque e arraste, solte quando terminar","text":"Dica: você também pode adicionar texto clicando duas vezes em qualquer lugar com a ferramenta de seleção","embeddable":"","text_selected":"Clique duplo ou tecle ENTER para editar o texto","text_editing":"Pressione Esc ou Ctrl/Cmd+ENTER para encerrar a edição","linearElementMulti":"Clique no último ponto ou pressione Escape ou Enter para terminar","lockAngle":"Você pode restringir o ângulo segurando o SHIFT","resize":"Você pode restringir proporções segurando SHIFT enquanto redimensiona,\\nsegure ALT para redimensionar do centro","resizeImage":"Você pode redimensionar livremente segurando SHIFT,\\nsegure ALT para redimensionar a partir do centro","rotate":"Você pode restringir os ângulos segurando SHIFT enquanto gira","lineEditor_info":"Pressione CtrlOuCmd e duplo-clique ou pressione CtrlOuCmd + Enter para editar pontos","lineEditor_pointSelected":"Pressione Delete para remover o(s) ponto(s),\\nCtrl/Cmd+D para duplicar ou arraste para mover","lineEditor_nothingSelected":"Selecione um ponto para editar (segure SHIFT para selecionar vários) ou segure Alt e clique para adicionar novos pontos","placeImage":"Clique para colocar a imagem, ou clique e arraste para definir manualmente o seu tamanho","publishLibrary":"Publicar sua própria biblioteca","bindTextToElement":"Pressione Enter para adicionar o texto","deepBoxSelect":"Segure Ctrl/Cmd para seleção profunda e para evitar arrastar","eraserRevert":"Segure a tecla Alt para inverter os elementos marcados para exclusão","firefox_clipboard_write":"Esse recurso pode ser ativado configurando a opção \\"dom.events.asyncClipboard.clipboardItem\\" como \\"true\\". Para alterar os sinalizadores do navegador no Firefox, visite a página \\"about:config\\".","disableSnapping":""},"canvasError":{"cannotShowPreview":"Não é possível mostrar pré-visualização","canvasTooBig":"A tela pode ser muito grande.","canvasTooBigTip":"Dica: tente aproximar um pouco os elementos mais distantes."},"errorSplash":{"headingMain":"Foi encontrado um erro. Tente ","clearCanvasMessage":"Se recarregar a página não funcionar, tente ","clearCanvasCaveat":" Isso resultará em perda de trabalho ","trackedToSentry":"O erro com o identificador {{eventId}} foi rastreado no nosso sistema.","openIssueMessage":"Fomos muito cautelosos para não incluir suas informações de cena no erro. Se sua cena não for privada, por favor, considere seguir nosso Por favor, inclua informações abaixo, copiando e colando para a issue do GitHub.","sceneContent":"Conteúdo da cena:"},"roomDialog":{"desc_intro":"Você pode convidar pessoas para sua cena atual para colaborar com você.","desc_privacy":"Não se preocupe, a sessão usa criptografia de ponta a ponta; portanto, o que você desenhar permanecerá privado. Nem mesmo nosso servidor poderá ver o que você cria.","button_startSession":"Iniciar sessão","button_stopSession":"Parar sessão","desc_inProgressIntro":"A sessão de colaboração ao vivo está agora em andamento.","desc_shareLink":"Compartilhe este link com qualquer pessoa com quem você queira colaborar:","desc_exitSession":"Interrompendo a sessão você irá se desconectar da sala, mas você poderá continuar trabalhando com a cena localmente. Observe que isso não afetará outras pessoas, e elas ainda poderão colaborar em suas versões.","shareTitle":"Participe de uma sessão ao vivo de colaboração no Excalidraw"},"errorDialog":{"title":"Erro"},"exportDialog":{"disk_title":"Salvar no computador","disk_details":"Exportar os dados da cena para um arquivo que você poderá importar mais tarde.","disk_button":"Salvar em um arquivo","link_title":"Link compartilhável","link_details":"Exportar como link de apenas leitura.","link_button":"Exportar link","excalidrawplus_description":"Salvar a cena na sua área de trabalho Excalidraw+.","excalidrawplus_button":"Exportar","excalidrawplus_exportError":"Não é possível exportar para o Excalidraw+ neste momento..."},"helpDialog":{"blog":"Leia o nosso blog","click":"clicar","deepSelect":"Seleção profunda","deepBoxSelect":"Use a seleção profunda dentro da caixa para previnir arrastar","curvedArrow":"Seta curva","curvedLine":"Linha curva","documentation":"Documentação","doubleClick":"clique duplo","drag":"arrastar","editor":"Editor","editLineArrowPoints":"Editar linha/ponta da seta","editText":"Editar texto / adicionar etiqueta","github":"Encontrou algum problema? Nos informe","howto":"Siga nossos guias","or":"ou","preventBinding":"Evitar fixação de seta","tools":"Ferramentas","shortcuts":"Atalhos de teclado","textFinish":"Encerrar edição (editor de texto)","textNewLine":"Adicionar nova linha (editor de texto)","title":"Ajudar","view":"Visualizar","zoomToFit":"Ampliar para encaixar todos os elementos","zoomToSelection":"Ampliar a seleção","toggleElementLock":"Bloquear/desbloquear seleção","movePageUpDown":"Mover a página para cima/baixo","movePageLeftRight":"Mover a página para esquerda/direita"},"clearCanvasDialog":{"title":"Limpar a tela"},"publishDialog":{"title":"Publicar biblioteca","itemName":"Nome do item","authorName":"Nome do autor","githubUsername":"Nome de usuário do GitHub","twitterUsername":"Nome de usuário do Twitter","libraryName":"Nome da Biblioteca","libraryDesc":"Descrição da biblioteca","website":"Site","placeholder":{"authorName":"Seu nome ou nome de usuário","libraryName":"Nome da sua biblioteca","libraryDesc":"Descrição para ajudar as pessoas a entenderem o uso da sua da sua biblioteca","githubHandle":"Identificador do GitHub (opcional), para que você possa editar a biblioteca depois de enviar para revisão","twitterHandle":"Nome de usuário do Twitter (opcional), para que saibamos quem deve ser creditado se promovermos no Twitter","website":"Link para o seu site pessoal ou outro lugar (opcional)"},"errors":{"required":"Obrigatório","website":"Informe uma URL válida"},"noteDescription":"Envie sua biblioteca para ser incluída no repositório de biblioteca públicapara outras pessoas usarem em seus desenhos.","noteGuidelines":"A biblioteca precisa ser aprovada manualmente primeiro. Por favor leia o orientações antes de enviar. Você precisará de uma conta do GitHub para se comunicar e fazer alterações quando solicitado, mas não é estritamente necessário.","noteLicense":"Ao enviar, você concorda que a biblioteca será publicada sob a Licença MIT, o que, em suma, significa que qualquer pessoa pode utilizá-los sem restrições.","noteItems":"Cada item da biblioteca deve ter seu próprio nome para que seja filtrável. Os seguintes itens da biblioteca serão incluídos:","atleastOneLibItem":"Por favor, selecione pelo menos um item da biblioteca para começar","republishWarning":"Nota: alguns dos itens selecionados estão marcados como já publicado/enviado. Você só deve reenviar itens ao atualizar uma biblioteca existente ou submissão."},"publishSuccessDialog":{"title":"Biblioteca enviada","content":"Obrigado {{authorName}}. Sua biblioteca foi enviada para análise. Você pode acompanhar o statusaqui"},"confirmDialog":{"resetLibrary":"Redefinir biblioteca","removeItemsFromLib":"Remover itens selecionados da biblioteca"},"imageExportDialog":{"header":"Exportar imagem","label":{"withBackground":"Fundo","onlySelected":"Somente selecionados","darkMode":"Modo escuro","embedScene":"Incorporar cena","scale":"Escala","padding":"Margem interna"},"tooltip":{"embedScene":"Os dados da cena serão salvos no arquivo PNG/SVG exportado para que a cena possa ser restaurada a partir dele.\\nIsso aumentará o tamanho do arquivo exportado."},"title":{"exportToPng":"Exportar como PNG","exportToSvg":"Exportar como SVG","copyPngToClipboard":"Copiar PNG para área de transferência"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Copiar para a área de transferência"}},"encrypted":{"tooltip":"Seus desenhos são criptografados de ponta a ponta, então os servidores do Excalidraw nunca os verão.","link":"Publicação de blog com criptografia de ponta a ponta no Excalidraw"},"stats":{"angle":"Ângulo","element":"Elemento","elements":"Elementos","height":"Altura","scene":"Cena","selected":"Selecionado","storage":"Armazenamento","title":"Estatísticas para nerds","total":"Total","version":"Versão","versionCopy":"Clique para copiar","versionNotAvailable":"Versão não disponível","width":"Largura"},"toast":{"addedToLibrary":"Adicionado à biblioteca","copyStyles":"Estilos copiados.","copyToClipboard":"Copiado para área de transferência.","copyToClipboardAsPng":"{{exportSelection}} copiado para a área de transferência como PNG ({{exportColorScheme}})","fileSaved":"Arquivo salvo.","fileSavedToFilename":"Salvo em {filename}","canvas":"tela","selection":"seleção","pasteAsSingleElement":"Use {{shortcut}} para colar como um único elemento,\\nou cole em um editor de texto já existente","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Transparente","black":"Preto","white":"Branco","red":"Vermelho","pink":"Rosa","grape":"Uva","violet":"Violeta","gray":"Cinza","blue":"Azul","cyan":"Ciano","teal":"Verde-azulado","green":"Verde","yellow":"Amarelo","orange":"Laranja","bronze":"Bronze"},"welcomeScreen":{"app":{"center_heading":"Todos os dados são salvos localmente no seu navegador.","center_heading_plus":"Você queria ir para o Excalidraw+ em vez disso?","menuHint":"Exportar, preferências, idiomas..."},"defaults":{"menuHint":"Exportar, preferências e mais...","center_heading":"Diagramas, Feito. Simples.","toolbarHint":"Escolha uma ferramenta e comece a desenhar!","helpHint":"Atalhos e ajuda"}},"colorPicker":{"mostUsedCustomColors":"Cores personalizadas mais usadas","colors":"Cores","shades":"Tons","hexCode":"Código hexadecimal","noShades":"Sem tons disponíveis para essa cor"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Exportar como imagem","button":"Exportar como imagem","description":"Exportar os dados da cena para um arquivo que você poderá importar mais tarde."},"saveToDisk":{"title":"Salvar no computador","button":"Salvar no computador","description":"Exportar os dados da cena para um arquivo que você poderá importar mais tarde."},"excalidrawPlus":{"title":"Excalidraw+","button":"Exportar para Excalidraw+","description":"Salvar a cena na sua área de trabalho Excalidraw+."}},"modal":{"loadFromFile":{"title":"Carregar de arquivo","button":"Carregar de arquivo","description":"Carregar de um arquivo irá substituir o conteúdo existente. Você pode salvar seu desenho primeiro usando uma das opções abaixo."},"shareableLink":{"title":"Carregar de um link","button":"Substituir meu conteúdo","description":"Carregar um desenho externo irá substituir seu conteúdo existente. Você pode salvar seu desenho antes utilizando uma das opções abaixo."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/pt-PT-json-0d3694a92e0134549086.js b/public/excalidraw/excalidraw-assets-dev/locales/pt-PT-json-0d3694a92e0134549086.js
new file mode 100644
index 0000000..1bb0c4e
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/pt-PT-json-0d3694a92e0134549086.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/pt-PT-json"],{
+
+/***/ "../../locales/pt-PT.json":
+/*!********************************!*\
+ !*** ../../locales/pt-PT.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Colar","pasteAsPlaintext":"Colar como texto simples","pasteCharts":"Colar gráficos","selectAll":"Selecionar tudo","multiSelect":"Adicionar elemento à seleção","moveCanvas":"Mover tela","cut":"Cortar","copy":"Copiar","copyAsPng":"Copiar para a área de transferência como PNG","copyAsSvg":"Copiar para a área de transferência como SVG","copyText":"Copiar para Área de Transferência como texto","bringForward":"Trazer para o primeiro plano","sendToBack":"Enviar para o plano de fundo","bringToFront":"Trazer para o primeiro plano","sendBackward":"Enviar para trás","delete":"Apagar","copyStyles":"Copiar os estilos","pasteStyles":"Colar os estilos","stroke":"Contornos","background":"Fundo","fill":"Preenchimento","strokeWidth":"Espessura do traço","strokeStyle":"Estilo de traço","strokeStyle_solid":"Sólido","strokeStyle_dashed":"Tracejado","strokeStyle_dotted":"Pontilhado","sloppiness":"Desleixo","opacity":"Opacidade","textAlign":"Alinhamento do texto","edges":"Arestas","sharp":"Aguçado","round":"Redondo","arrowheads":"Pontas","arrowhead_none":"Nenhuma","arrowhead_arrow":"Seta","arrowhead_bar":"Barra","arrowhead_dot":"Ponto","arrowhead_triangle":"Triângulo","fontSize":"Tamanho da fonte","fontFamily":"Família da fontes","addWatermark":"Adicionar \\"Feito com Excalidraw\\"","handDrawn":"Manuscrito","normal":"Normal","code":"Código","small":"Pequeno","medium":"Médio","large":"Grande","veryLarge":"Muito grande","solid":"Sólido","hachure":"Eclosão","zigzag":"ziguezague","crossHatch":"Sombreado","thin":"Fino","bold":"Espesso","left":"Esquerda","center":"Centralizar","right":"Direita","extraBold":"Muito espesso","architect":"Arquitecto","artist":"Artista","cartoonist":"Caricaturista","fileTitle":"Nome do ficheiro","colorPicker":"Seletor de cores","canvasColors":"Usado na tela","canvasBackground":"Fundo da área de desenho","drawingCanvas":"Área de desenho","layers":"Camadas","actions":"Ações","language":"Idioma","liveCollaboration":"Colaboração ao vivo...","duplicateSelection":"Duplicar","untitled":"Sem título","name":"Nome","yourName":"O seu nome","madeWithExcalidraw":"Feito com Excalidraw","group":"Agrupar seleção","ungroup":"Desagrupar seleção","collaborators":"Colaboradores","showGrid":"Mostrar grelha","addToLibrary":"Adicionar à biblioteca","removeFromLibrary":"Remover da biblioteca","libraryLoadingMessage":"A carregar a biblioteca…","libraries":"Procurar bibliotecas","loadingScene":"A carregar a cena…","align":"Alinhamento","alignTop":"Alinhar ao topo","alignBottom":"Alinhar ao fundo","alignLeft":"Alinhar à esquerda","alignRight":"Alinhar à direita","centerVertically":"Centrar verticalmente","centerHorizontally":"Centrar horizontalmente","distributeHorizontally":"Distribuir horizontalmente","distributeVertically":"Distribuir verticalmente","flipHorizontal":"Inverter horizontalmente","flipVertical":"Inverter verticalmente","viewMode":"Modo de visualização","share":"Partilhar","showStroke":"Mostrar seletor de cores do traço","showBackground":"Mostrar seletor de cores do fundo","toggleTheme":"Alternar tema","personalLib":"Biblioteca pessoal","excalidrawLib":"Biblioteca do Excalidraw","decreaseFontSize":"Reduzir o tamanho do tipo de letra","increaseFontSize":"Aumentar o tamanho do tipo de letra","unbindText":"Desvincular texto","bindText":"Ligar texto ao recipiente","createContainerFromText":"Envolver texto num recipiente","link":{"edit":"Editar ligação","editEmbed":"","create":"Criar ligação","createEmbed":"","label":"Ligação","labelEmbed":"","empty":""},"lineEditor":{"edit":"Editar linha","exit":"Sair do editor de linha"},"elementLock":{"lock":"Bloquear","unlock":"Desbloquear","lockAll":"Bloquear todos","unlockAll":"Desbloquear todos"},"statusPublished":"Publicado","sidebarLock":"Manter a barra lateral aberta","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Ainda não foram adicionados nenhuns itens...","hint_emptyLibrary":"Seleccione um item na tela para adicioná-lo aqui, ou então instale uma biblioteca do repositório público abaixo.","hint_emptyPrivateLibrary":"Seleccione um item na tela para adicioná-lo aqui."},"buttons":{"clearReset":"Limpar a área de desenho e redefinir a cor de fundo","exportJSON":"Exportar para ficheiro","exportImage":"Exportar imagem...","export":"Guardar para...","copyToClipboard":"Copiar para o clipboard","save":"Guardar no ficheiro atual","saveAs":"Guardar como","load":"Abrir","getShareableLink":"Obter um link de partilha","close":"Fechar","selectLanguage":"Selecionar idioma","scrollBackToContent":"Voltar ao conteúdo","zoomIn":"Aumentar zoom","zoomOut":"Diminuir zoom","resetZoom":"Redefinir zoom","menu":"Menu","done":"Concluído","edit":"Editar","undo":"Desfazer","redo":"Refazer","resetLibrary":"Repor a biblioteca","createNewRoom":"Criar nova sala","fullScreen":"Ecrã inteiro","darkMode":"Modo escuro","lightMode":"Modo claro","zenMode":"Modo zen","objectsSnapMode":"","exitZenMode":"Sair do modo zen","cancel":"Cancelar","clear":"Limpar","remove":"Remover","embed":"","publishLibrary":"Publicar","submit":"Enviar","confirm":"Confirmar","embeddableInteractionButton":""},"alerts":{"clearReset":"Isto irá limpar toda a área de desenho. Tem a certeza?","couldNotCreateShareableLink":"Não foi possível criar um link partilhável.","couldNotCreateShareableLinkTooBig":"Não foi possível criar um link partilhável: a cena é muito grande","couldNotLoadInvalidFile":"Não foi possível carregar o ficheiro inválido","importBackendFailed":"A importação do servidor falhou.","cannotExportEmptyCanvas":"Não é possível exportar uma área de desenho vazia.","couldNotCopyToClipboard":"Não foi possível copiar para a área de transferência.","decryptFailed":"Não foi possível desencriptar os dados.","uploadedSecurly":"O upload foi protegido com criptografia de ponta a ponta, o que significa que o servidor do Excalidraw e terceiros não podem ler o conteúdo.","loadSceneOverridePrompt":"Se carregar um desenho externo substituirá o conteúdo existente. Quer continuar?","collabStopOverridePrompt":"Ao interromper a sessão irá substituir o último desenho guardado. Tem a certeza?\\n\\n(Caso queira manter o último desenho, simplesmente feche a janela do navegador.)","errorAddingToLibrary":"Não foi possível adicionar o item à biblioteca","errorRemovingFromLibrary":"Não foi possível remover o item da biblioteca","confirmAddLibrary":"Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem a certeza?","imageDoesNotContainScene":"Esta imagem parece não conter dados de cenas. Ativou a incorporação da cena durante a exportação?","cannotRestoreFromImage":"Não foi possível restaurar a cena deste ficheiro de imagem","invalidSceneUrl":"Não foi possível importar a cena a partir do URL fornecido. Ou está mal formado ou não contém dados JSON do Excalidraw válidos.","resetLibrary":"Isto irá limpar a sua biblioteca. Tem a certeza?","removeItemsFromsLibrary":"Apagar {{count}} item(ns) da biblioteca?","invalidEncryptionKey":"Chave de encriptação deve ter 22 caracteres. A colaboração ao vivo está desativada.","collabOfflineWarning":"Sem ligação à internet disponível.\\nAs suas alterações não serão salvas!"},"errors":{"unsupportedFileType":"Tipo de ficheiro não suportado.","imageInsertError":"Não foi possível inserir a imagem, tente novamente mais tarde...","fileTooBig":"O ficheiro é muito grande. O tamanho máximo permitido é {{maxSize}}.","svgImageInsertError":"Não foi possível inserir a imagem SVG. A marcação SVG parece inválida.","failedToFetchImage":"","invalidSVGString":"SVG inválido.","cannotResolveCollabServer":"Não foi possível fazer a ligação ao servidor colaborativo. Por favor, volte a carregar a página e tente novamente.","importLibraryError":"Não foi possível carregar a biblioteca","collabSaveFailed":"Não foi possível guardar na base de dados de backend. Se os problemas persistirem, guarde o ficheiro localmente para garantir que não perde o seu trabalho.","collabSaveFailed_sizeExceeded":"Não foi possível guardar na base de dados de backend, o ecrã parece estar muito grande. Deve guardar o ficheiro localmente para garantir que não perde o seu trabalho.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Seleção","image":"Inserir imagem","rectangle":"Retângulo","diamond":"Losango","ellipse":"Elipse","arrow":"Flecha","line":"Linha","freedraw":"Desenhar","text":"Texto","library":"Biblioteca","lock":"Manter a ferramenta selecionada ativa após desenhar","penMode":"Modo caneta - impedir toque","link":"Acrescentar/ Adicionar ligação para uma forma seleccionada","eraser":"Borracha","frame":"","embeddable":"","laser":"","hand":"Mão (ferramenta de movimento da tela)","extraTools":""},"headings":{"canvasActions":"Ações da área de desenho","selectedShapeActions":"Ações das formas selecionadas","shapes":"Formas"},"hints":{"canvasPanning":"Para mover a tela, carregue na roda do rato ou na barra de espaço enquanto arrasta, ou use a ferramenta da mão","linearElement":"Clique para iniciar vários pontos, arraste para uma única linha","freeDraw":"Clique e arraste, large quando terminar","text":"Dica: também pode adicionar texto clicando duas vezes em qualquer lugar com a ferramenta de seleção","embeddable":"","text_selected":"Clique duas vezes ou pressione a tecla Enter para editar o texto","text_editing":"Pressione a tecla Escape ou CtrlOrCmd+ENTER para terminar a edição","linearElementMulti":"Clique no último ponto ou pressione Escape ou Enter para terminar","lockAngle":"Pode restringir o ângulo mantendo premida a tecla SHIFT","resize":"Pode restringir as proporções mantendo a tecla SHIFT premida enquanto redimensiona,\\nmantenha a tecla ALT premida para redimensionar a partir do centro","resizeImage":"Pode redimensionar livremente mantendo pressionada a tecla SHIFT,\\nmantenha pressionada a tecla ALT para redimensionar do centro","rotate":"Pode restringir os ângulos mantendo a tecla SHIFT premida enquanto roda","lineEditor_info":"Pressione CtrlOrCmd e faça um duplo-clique ou pressione CtrlOrCmd + Enter para editar pontos","lineEditor_pointSelected":"Carregue na tecla Delete para remover o(s) ponto(s), CtrlOuCmd+D para duplicar, ou arraste para mover","lineEditor_nothingSelected":"Seleccione um ponto para editar (carregue em SHIFT para seleccionar vários),\\nou carregue em Alt e clique para acrescentar novos pontos","placeImage":"Clique para colocar a imagem ou clique e arraste para definir o seu tamanho manualmente","publishLibrary":"Publique a sua própria biblioteca","bindTextToElement":"Carregue Enter para acrescentar texto","deepBoxSelect":"Mantenha a tecla CtrlOrCmd carregada para selecção profunda, impedindo o arrastamento","eraserRevert":"Carregue também em Alt para reverter os elementos marcados para serem apagados","firefox_clipboard_write":"Esta função pode provavelmente ser ativada definindo a opção \\"dom.events.asyncClipboard.clipboardItem\\" como \\"true\\". Para alterar os sinalizadores do navegador no Firefox, visite a página \\"about:config\\".","disableSnapping":""},"canvasError":{"cannotShowPreview":"Não é possível mostrar uma pré-visualização","canvasTooBig":"A área de desenho pode ser muito grande.","canvasTooBigTip":"Dica: tente aproximar um pouco os elementos mais distantes."},"errorSplash":{"headingMain":"Foi encontrado um erro. Tente ","clearCanvasMessage":"Se a recarga não funcionar, tente ","clearCanvasCaveat":" Isso resultará em perda de trabalho ","trackedToSentry":"O erro com o identificador {{eventId}} foi rastreado no nosso sistema.","openIssueMessage":"Fomos muito cautelosos para não incluir suas informações de cena no erro. Se sua cena não for privada, por favor, considere seguir nosso Por favor, inclua informações abaixo, copiando e colando no relatório de erros no GitHub.","sceneContent":"Conteúdo da cena:"},"roomDialog":{"desc_intro":"Pode convidar pessoas para colaborarem na sua cena atual.","desc_privacy":"Não se preocupe, a sessão usa criptografia de ponta-a-ponta, por isso o que desenhar permanecerá privado. Nem mesmo o nosso servidor poderá ver o que cria.","button_startSession":"Iniciar sessão","button_stopSession":"Parar sessão","desc_inProgressIntro":"A sessão de colaboração ao vivo está agora em andamento.","desc_shareLink":"Partilhe este link com qualquer pessoa com quem queira colaborar:","desc_exitSession":"Interrompendo a sessão irá desconectar-se da sala, mas poderá continuar a trabalhar com a cena localmente. Note que isso não afetará outras pessoas e elas ainda poderão colaborar nas versões deles.","shareTitle":"Participe numa sessão de colaboração ao vivo no Excalidraw"},"errorDialog":{"title":"Erro"},"exportDialog":{"disk_title":"Guardar no disco","disk_details":"Exportar os dados da cena para um ficheiro do qual poderá importar mais tarde.","disk_button":"Guardar num ficheiro","link_title":"Link partilhável","link_details":"Exportar como um link de apenas leitura.","link_button":"Exportar para link","excalidrawplus_description":"Guardar a cena no seu espaço de trabalho Excalidraw+","excalidrawplus_button":"Exportar","excalidrawplus_exportError":"Não foi possível exportar para o Excalidraw+ neste momento..."},"helpDialog":{"blog":"Leia o nosso blogue","click":"clicar","deepSelect":"Selecção profunda","deepBoxSelect":"Selecção profunda dentro da caixa, impedindo que seja arrastada","curvedArrow":"Seta curva","curvedLine":"Linha curva","documentation":"Documentação","doubleClick":"clique duplo","drag":"arrastar","editor":"Editor","editLineArrowPoints":"Editar pontos de linha/seta","editText":"Editar texto / adicionar etiqueta","github":"Encontrou algum problema? Informe-nos","howto":"Siga os nossos guias","or":"ou","preventBinding":"Prevenir fixação de seta","tools":"Ferramentas","shortcuts":"Atalhos de teclado","textFinish":"Finalizar edição (editor texto)","textNewLine":"Adicionar nova linha (editor de texto)","title":"Ajuda","view":"Visualizar","zoomToFit":"Ajustar para todos os elementos caberem","zoomToSelection":"Ampliar a seleção","toggleElementLock":"Trancar/destrancar selecção","movePageUpDown":"Mover página para cima / baixo","movePageLeftRight":"Mover página para esquerda / direita"},"clearCanvasDialog":{"title":"Apagar tela"},"publishDialog":{"title":"Publicar biblioteca","itemName":"Nome do item","authorName":"Nome do autor","githubUsername":"Nome de utilizador do GitHub","twitterUsername":"Nome de utilizador no Twitter","libraryName":"Nome da biblioteca","libraryDesc":"Descrição da biblioteca","website":"Página web","placeholder":{"authorName":"Introduza o seu nome ou nome de utilizador","libraryName":"Nome da sua biblioteca","libraryDesc":"Descrição da sua biblioteca para ajudar as pessoas a entender a utilização dela","githubHandle":"Identificador do GitHub (opcional), para que possa editar a biblioteca depois desta ser enviada para revisão","twitterHandle":"Nome do Twitter (opcional), para que saibamos quem merece os créditos na promoção via Twitter","website":"Ligação para a sua página pessoal ou qualquer outra (opcional)"},"errors":{"required":"Obrigatório","website":"Introduza um URL válido"},"noteDescription":"Envie a sua biblioteca para ser incluída no repositório de bibliotecas públicaspara outras pessoas a poderem usar nos seus próprios desenhos.","noteGuidelines":"A biblioteca precisa ser aprovada manualmente primeiro. Por favor, leia orientações antes de enviar. Vai precisar de uma conta no GitHub para comunicar e fazer alterações se solicitado, mas não é estritamente necessária.","noteLicense":"Ao enviar, concorda que a biblioteca será publicada sob a Licença MIT, o que significa, de forma resumida, que qualquer pessoa pode utilizá-la sem restrições.","noteItems":"Cada item da biblioteca deve ter o seu próprio nome para que este seja pesquisável com filtros. Os seguintes itens da biblioteca serão incluídos:","atleastOneLibItem":"Por favor, seleccione pelo menos um item da biblioteca para começar","republishWarning":"Nota: alguns dos itens seleccionados estão marcados como já publicados/enviados. Só deve reenviar itens ao actualizar uma biblioteca existente ou submissão."},"publishSuccessDialog":{"title":"Biblioteca enviada","content":"Obrigado {{authorName}}. A sua biblioteca foi enviada para análise. Pode acompanhar o statusaqui"},"confirmDialog":{"resetLibrary":"Repor a biblioteca","removeItemsFromLib":"Remover os itens seleccionados da biblioteca"},"imageExportDialog":{"header":"Exportar imagem","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"Cena embutida","scale":"","padding":"Espaçamento"},"tooltip":{"embedScene":""},"title":{"exportToPng":"Exportar em PNG","exportToSvg":"Exportar em SVG","copyPngToClipboard":""},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":""}},"encrypted":{"tooltip":"Os seus desenhos são encriptados de ponta-a-ponta, por isso os servidores do Excalidraw nunca os verão.","link":"Publicação de blogue na encriptação ponta-a-ponta no Excalidraw"},"stats":{"angle":"Ângulo","element":"Elemento","elements":"Elementos","height":"Altura","scene":"Cena","selected":"Selecionado","storage":"Armazenamento","title":"Estatísticas para nerds","total":"Total","version":"Versão","versionCopy":"Clique para copiar","versionNotAvailable":"Versão não disponível","width":"Largura"},"toast":{"addedToLibrary":"Acrescentado à biblioteca","copyStyles":"Estilos copiados.","copyToClipboard":"Copiado para a área de transferência.","copyToClipboardAsPng":"{{exportSelection}} copiado para a área de transferência como PNG\\n({{exportColorScheme}})","fileSaved":"Ficheiro guardado.","fileSavedToFilename":"Guardado como {filename}","canvas":"área de desenho","selection":"seleção","pasteAsSingleElement":"Usar {{shortcut}} para colar como um único elemento,\\nou colar num editor de texto existente","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Transparente","black":"Preto","white":"Branco","red":"Vermelho","pink":"Rosa","grape":"Uva","violet":"Violeta","gray":"Cinza","blue":"Azul","cyan":"","teal":"","green":"Verde","yellow":"Amarelo","orange":"Laranja","bronze":"Bronze"},"welcomeScreen":{"app":{"center_heading":"Todos os dados são guardados no seu navegador local.","center_heading_plus":"Queria antes ir para o Excalidraw+?","menuHint":"Exportar, preferências, idiomas..."},"defaults":{"menuHint":"Exportar, preferências e outros...","center_heading":"Diagramas. Feito. Simples.","toolbarHint":"Escolha uma ferramenta e comece a desenhar!","helpHint":"Atalhos e ajuda"}},"colorPicker":{"mostUsedCustomColors":"","colors":"Cores","shades":"Tons","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"Guardar no disco","button":"Guardar no disco","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"Carregar a partir de ficheiro","button":"Carregar a partir de ficheiro","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/ro-RO-json-e83fda16c860c6d0b383.js b/public/excalidraw/excalidraw-assets-dev/locales/ro-RO-json-e83fda16c860c6d0b383.js
new file mode 100644
index 0000000..6892511
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/ro-RO-json-e83fda16c860c6d0b383.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/ro-RO-json"],{
+
+/***/ "../../locales/ro-RO.json":
+/*!********************************!*\
+ !*** ../../locales/ro-RO.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Lipire","pasteAsPlaintext":"Inserare ca text simplu","pasteCharts":"Lipire diagrame","selectAll":"Selectare totală","multiSelect":"Adaugă element la selecție","moveCanvas":"Mutare pânză","cut":"Decupare","copy":"Copiere","copyAsPng":"Copiere în memoria temporară ca PNG","copyAsSvg":"Copiere în memoria temporară ca SVG","copyText":"Copiere în memoria temporară ca text","bringForward":"Aducere în plan apropiat","sendToBack":"Trimitere în ultimul plan","bringToFront":"Aducere în prim plan","sendBackward":"Trimitere în plan secundar","delete":"Ștergere","copyStyles":"Copiere stiluri","pasteStyles":"Lipire stiluri","stroke":"Contur","background":"Fundal","fill":"Umplere","strokeWidth":"Lățimea conturului","strokeStyle":"Stilul conturului","strokeStyle_solid":"Neîntrerupt","strokeStyle_dashed":"Liniuțe","strokeStyle_dotted":"Punctat","sloppiness":"Aspectul trasării","opacity":"Opacitate","textAlign":"Alinierea textului","edges":"Margini","sharp":"Ascuțite","round":"Rotunde","arrowheads":"Vârfuri de săgeată","arrowhead_none":"Niciunul","arrowhead_arrow":"Săgeată","arrowhead_bar":"Bară","arrowhead_dot":"Bulină","arrowhead_triangle":"Triunghi","fontSize":"Dimensiune font","fontFamily":"Familia de fonturi","addWatermark":"Adaugă „Realizat cu Excalidraw”","handDrawn":"Scris de mână","normal":"Normal","code":"Cod","small":"Mică","medium":"Medie","large":"Mare","veryLarge":"Foarte mare","solid":"Plină","hachure":"Hașură","zigzag":"Zigzag","crossHatch":"Hașură transversală","thin":"Subțire","bold":"Îngroșată","left":"Stânga","center":"Centru","right":"Dreapta","extraBold":"Extra îngroșată","architect":"Arhitect","artist":"Artist","cartoonist":"Caricaturist","fileTitle":"Nume de fișier","colorPicker":"Selector de culoare","canvasColors":"Folosite pe pânză","canvasBackground":"Fundalul pânzei","drawingCanvas":"Pânză pentru desenat","layers":"Straturi","actions":"Acțiuni","language":"Limbă","liveCollaboration":"Colaborare în direct...","duplicateSelection":"Duplicare","untitled":"Nedenumit","name":"Nume","yourName":"Numele tău","madeWithExcalidraw":"Realizat cu Excalidraw","group":"Grupare selecție","ungroup":"Degrupare selecție","collaborators":"Colaboratori","showGrid":"Afișare grilă","addToLibrary":"Adăugare la bibliotecă","removeFromLibrary":"Eliminare din bibliotecă","libraryLoadingMessage":"Se încarcă biblioteca…","libraries":"Răsfoiește bibliotecile","loadingScene":"Se încarcă scena…","align":"Aliniere","alignTop":"Aliniere sus","alignBottom":"Aliniere jos","alignLeft":"Aliniere la stânga","alignRight":"Aliniere la dreapta","centerVertically":"Centrare verticală","centerHorizontally":"Centrare orizontală","distributeHorizontally":"Distribuie orizontal","distributeVertically":"Distribuie vertical","flipHorizontal":"Răsturnare orizontală","flipVertical":"Răsturnare verticală","viewMode":"Mod de vizualizare","share":"Distribuie","showStroke":"Afișare selector culoare contur","showBackground":"Afișare selector culoare fundal","toggleTheme":"Comutare temă","personalLib":"Biblioteca personală","excalidrawLib":"Biblioteca Excalidraw","decreaseFontSize":"Micșorează dimensiunea fontului","increaseFontSize":"Mărește dimensiunea fontului","unbindText":"Deconectare text","bindText":"Legare text de container","createContainerFromText":"Încadrare text într-un container","link":{"edit":"Editare URL","editEmbed":"Editare URL și încorporare","create":"Creare URL","createEmbed":"Creare URL și încorporare","label":"URL","labelEmbed":"URL și încorporare","empty":"Nu este setat niciun URL"},"lineEditor":{"edit":"Editare linie","exit":"Părăsire editor de linii"},"elementLock":{"lock":"Blocare","unlock":"Deblocare","lockAll":"Blocare toate","unlockAll":"Deblocare toate"},"statusPublished":"Publicat","sidebarLock":"Păstrează deschisă bara laterală","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":"Alegere culoare din pânză"},"library":{"noItems":"Niciun element adăugat încă...","hint_emptyLibrary":"Selectează un element de pe pânză pentru a-l adăuga aici sau instalează o bibliotecă din depozitul public, de mai jos.","hint_emptyPrivateLibrary":"Selectează un element de pe pânză pentru a-l adăuga aici."},"buttons":{"clearReset":"Resetare pânză","exportJSON":"Exportare la fișiere","exportImage":"Exportare imagine...","export":"Salvare în...","copyToClipboard":"Copiere în memoria temporară","save":"Salvare în fișierul curent","saveAs":"Salvare ca","load":"Deschidere","getShareableLink":"Obține URL partajabil","close":"Închidere","selectLanguage":"Selectare limbă","scrollBackToContent":"Derulare înapoi la conținut","zoomIn":"Apropiere","zoomOut":"Depărtare","resetZoom":"Resetare transfocare","menu":"Meniu","done":"Efectuat","edit":"Edit","undo":"Anulare","redo":"Refacere","resetLibrary":"Resetare bibliotecă","createNewRoom":"Creare cameră nouă","fullScreen":"Ecran complet","darkMode":"Mod întunecat","lightMode":"Mod luminos","zenMode":"Mod zen","objectsSnapMode":"Ancorare la obiecte","exitZenMode":"Ieșire din modul zen","cancel":"Anulare","clear":"Ștergere","remove":"Eliminare","embed":"Comutare încorporare","publishLibrary":"Publicare","submit":"Trimitere","confirm":"Confirmare","embeddableInteractionButton":"Clic pentru interacționare"},"alerts":{"clearReset":"Această opțiune va șterge întreaga pânză. Confirmi?","couldNotCreateShareableLink":"Nu s-a putut crea un URL partajabil.","couldNotCreateShareableLinkTooBig":"Nu s-a putut crea un URL partajabil: scena este prea mare","couldNotLoadInvalidFile":"Fișierul invalid nu a putut fi încărcat","importBackendFailed":"Importarea de la nivel de server a eșuat.","cannotExportEmptyCanvas":"Nu se poate exporta pânza goală.","couldNotCopyToClipboard":"Nu s-a putut copia în memoria temporară.","decryptFailed":"Datele nu au putut fi decriptate.","uploadedSecurly":"Încărcarea a fost securizată prin criptare integrală, însemnând că serverul Excalidraw și terții nu pot citi conținutul.","loadSceneOverridePrompt":"Încărcarea desenului extern va înlocui conținutul existent. Dorești să continui?","collabStopOverridePrompt":"Oprirea sesiunii va suprascrie desenul anterior stocat local. Confirmi alegerea?\\n\\n(Dacă vrei să păstrezi desenul local, pur și simplu închide fila navigatorului în schimb.)","errorAddingToLibrary":"Elementul nu a putut fi adăugat în bibliotecă","errorRemovingFromLibrary":"Elementul nu a putut fi eliminat din bibliotecă","confirmAddLibrary":"Această acțiune va adăuga {{numShapes}} formă(e) la biblioteca ta. Confirmi?","imageDoesNotContainScene":"Această imagine nu pare să conțină date de scenă. Ai activat încorporarea scenei în timpul exportului?","cannotRestoreFromImage":"Scena nu a putut fi restaurată din acest fișier de imagine","invalidSceneUrl":"Scena nu a putut fi importată din URL-ul furnizat. Este fie incorect formată, fie nu conține date JSON Excalidraw valide.","resetLibrary":"Această opțiune va elimina conținutul din bibliotecă. Confirmi?","removeItemsFromsLibrary":"Ștergi {{count}} element(e) din bibliotecă?","invalidEncryptionKey":"Cheia de criptare trebuie să aibă 22 de caractere. Colaborarea în direct este dezactivată.","collabOfflineWarning":"Nu este disponibilă nicio conexiune la internet.\\nModificările nu vor fi salvate!"},"errors":{"unsupportedFileType":"Tip de fișier neacceptat.","imageInsertError":"Imaginea nu a putut fi introdusă. Reîncearcă mai târziu...","fileTooBig":"Fișierul este prea mare. Dimensiunea maximă permisă este de {{maxSize}}.","svgImageInsertError":"Imaginea SVG nu a putut fi introdus. Marcajul SVG pare invalid.","failedToFetchImage":"","invalidSVGString":"SVG invalid.","cannotResolveCollabServer":"Nu a putut fi realizată conexiunea la serverul de colaborare. Reîncarcă pagina și încearcă din nou.","importLibraryError":"Biblioteca nu a putut fi încărcată","collabSaveFailed":"Nu s-a putut salva în baza de date la nivel de server. Dacă problemele persistă, ar trebui să salvezi fișierul la nivel local pentru a te asigura că nu îți pierzi munca.","collabSaveFailed_sizeExceeded":"Nu s-a putut salva în baza de date la nivel de server, întrucât se pare că pânza este prea mare. Ar trebui să salvezi fișierul la nivel local pentru a te asigura că nu îți pierzi munca.","brave_measure_text_error":{"line1":"Se pare că folosești navigatorul Brave cu opțiunea strictă pentru blocarea amprentării.","line2":"Acest lucru poate duce la întreruperea elementelor text din desene.","line3":"Îți recomandăm ferm să dezactivezi această setare. Poți urma acești pași pentru a face acest lucru.","line4":"Dacă dezactivarea acestei setări nu duce la remedierea afișării elementelor text, deschide un tichet de problemă pe pagina noastră de GitHub sau scrie-ne pe Discord"},"libraryElementTypeError":{"embeddable":"Elementele încorporabile nu pot fi adăugate la bibliotecă.","image":"În curând vor putea fi adăugate imagini în bibliotecă!"}},"toolBar":{"selection":"Selecție","image":"Introducere imagine","rectangle":"Dreptunghi","diamond":"Romb","ellipse":"Elipsă","arrow":"Săgeată","line":"Linie","freedraw":"Desenare","text":"Text","library":"Bibliotecă","lock":"Menține activ instrumentul selectat după desenare","penMode":"Mod stilou – împiedică atingerea","link":"Adăugare/actualizare URL pentru forma selectată","eraser":"Radieră","frame":"","embeddable":"Încorporare web","laser":"Indicator laser","hand":"Mână (instrument de panoramare)","extraTools":""},"headings":{"canvasActions":"Acțiuni pentru pânză","selectedShapeActions":"Acțiuni pentru forma selectată","shapes":"Forme"},"hints":{"canvasPanning":"Pentru a muta pânză, ține apăsată rotița mausului sau bara de spațiu sau folosește instrumentul în formă de mână","linearElement":"Dă clic pentru a crea mai multe puncte, glisează pentru a forma o singură linie","freeDraw":"Dă clic pe pânză și glisează cursorul, apoi eliberează-l când ai terminat","text":"Sfat: poți adăuga text și dând dublu clic oriunde cu instrumentul de selecție","embeddable":"Dă clic și trage pentru a crea un cod de încorporare de pagină web","text_selected":"Dă dublu clic sau apasă tasta Enter pentru a edita textul","text_editing":"Apasă tasta Escape sau Ctrl sau Cmd + Enter pentru a finaliza editarea","linearElementMulti":"Dă clic pe ultimul punct sau apasă tasta Escape sau tasta Enter pentru a termina","lockAngle":"Poți constrânge unghiul prin ținerea apăsată a tastei SHIFT","resize":"Poți constrânge proporțiile, ținând apăsată tasta SHIFT în timp ce redimensionezi,\\nține apăsată tasta ALT pentru a redimensiona de la centru","resizeImage":"Poți redimensiona liber ținând apăsată tasta SHIFT,\\nține apăsată tasta ALT pentru a redimensiona din centru","rotate":"Poți constrânge unghiurile, ținând apăsată tasta SHIFT în timp ce rotești","lineEditor_info":"Ține apăsată tasta Ctrl sau Cmd și dă dublu clic sau apasă tasta Ctrl sau Cmd + Enter pentru a edita puncte","lineEditor_pointSelected":"Apasă tasta Delete pentru a elimina punctele,\\ncombinația de taste Ctrl sau Cmd + D pentru a le duplica sau glisează-le pentru a le schimba poziția","lineEditor_nothingSelected":"Selectează un punct pentru a-l edita (ține apăsată tasta SHIFT pentru a selecta mai multe),\\nsau ține apăsată tasta Alt și dă clic pentru a adăuga puncte noi","placeImage":"Dă clic pentru a poziționa imaginea sau dă clic și glisează pentru a seta manual dimensiunea imaginii","publishLibrary":"Publică propria bibliotecă","bindTextToElement":"Apasă tasta Enter pentru a adăuga text","deepBoxSelect":"Ține apăsată tasta Ctrl sau Cmd pentru a efectua selectarea de adâncime și pentru a preveni glisarea","eraserRevert":"Ține apăsată tasta Alt pentru a anula elementele marcate pentru ștergere","firefox_clipboard_write":"Această caracteristică poate fi probabil activată prin setarea preferinței „dom.events.asyncClipboard.clipboardItem” ca „true”. Pentru a schimba preferințele navigatorului în Firefox, accesează pagina „about:config”.","disableSnapping":"Ține apăsat CtrlOrCmd pentru a dezactiva ancorarea"},"canvasError":{"cannotShowPreview":"Nu se poate afișa previzualizarea","canvasTooBig":"Pânza poate fi prea mare.","canvasTooBigTip":"Sfat: încearcă să apropii puțin mai mult elementele cele mai îndepărtate."},"errorSplash":{"headingMain":"A apărut o eroare. Încearcă .","clearCanvasMessage":"Dacă reîncărcarea nu funcționează, încearcă .","clearCanvasCaveat":" Acest lucru va duce la pierderea progresului ","trackedToSentry":"Eroarea cu identificatorul {{eventId}} a fost urmărită în sistemul nostru.","openIssueMessage":"Am luat măsuri de precauție pentru a nu include informații despre scenă în eroare. Dacă scena nu este privată, oferă-ne mai multe informații în . Include informațiile de mai jos copiindu-le și lipindu-le în tichetul cu problemă de pe GitHub.","sceneContent":"Conținutul scenei:"},"roomDialog":{"desc_intro":"Poți invita alte persoane pentru a colabora la scena actuală.","desc_privacy":"Nu te îngrijora. Sesiunea utilizează criptarea integrală, astfel încât orice desenezi va rămâne privat. Nici măcar serverul nostru nu va putea vedea pe ce ai lucrat.","button_startSession":"Pornire sesiune","button_stopSession":"Oprire sesiune","desc_inProgressIntro":"Sesiunea de colaborare în direct este în curs de desfășurare.","desc_shareLink":"Distribuie acest URL persoanelor cu care dorești să colaborezi:","desc_exitSession":"Oprirea sesiunii te va deconecta de la sală, însă vei putea lucra în continuare, pe plan local, cu scena. Reține că această opțiune nu va afecta alte persoane, iar acestea vor putea să colaboreze în continuare pe versiunea lor.","shareTitle":"Alătură-te unei sesiuni de colaborare în direct pe Excalidraw"},"errorDialog":{"title":"Eroare"},"exportDialog":{"disk_title":"Salvare pe disc","disk_details":"Exportă datele scenei pe un fișier din care poți importa mai târziu.","disk_button":"Salvare în fișier","link_title":"URL partajabil","link_details":"Exportă ca URL doar în citire.","link_button":"Exportare în URL","excalidrawplus_description":"Salvează scena în spațiul de lucru Excalidraw+.","excalidrawplus_button":"Exportare","excalidrawplus_exportError":"Excalidraw+ nu a putut fi exportat în acest moment..."},"helpDialog":{"blog":"Citește blogul nostru","click":"clic","deepSelect":"Selectare de adâncime","deepBoxSelect":"Selectare de adâncime în casetă și prevenire glisare","curvedArrow":"Săgeată curbată","curvedLine":"Linie curbată","documentation":"Documentație","doubleClick":"dublu clic","drag":"glisare","editor":"Editor","editLineArrowPoints":"Editare puncte de săgeată/rând","editText":"Editare text/adăugare etichetă","github":"Ai întâmpinat o problemă? Trimite un raport","howto":"Urmărește ghidurile noastre","or":"sau","preventBinding":"Împiedică legarea săgeții","tools":"Instrumente","shortcuts":"Comenzi rapide de la tastatură","textFinish":"Finalizează editarea (editor de text)","textNewLine":"Adaugă o linie nouă (editor de text)","title":"Ajutor","view":"Vizualizare","zoomToFit":"Transfocare pentru a cuprinde totul","zoomToSelection":"Transfocare la selecție","toggleElementLock":"Blocare/deblocare selecție","movePageUpDown":"Deplasare pagină sus/jos","movePageLeftRight":"Deplasare pagină stânga/dreapta"},"clearCanvasDialog":{"title":"Ștergere pânză"},"publishDialog":{"title":"Publicare bibliotecă","itemName":"Denumirea elementului","authorName":"Numele autorului","githubUsername":"Numele de utilizator GitHub","twitterUsername":"Numele de utilizator Twitter","libraryName":"Denumirea bibliotecii","libraryDesc":"Descrierea bibliotecii","website":"Pagină de internet","placeholder":{"authorName":"Numele sau numele tău de utilizator","libraryName":"Numele bibliotecii tale","libraryDesc":"Descrierea bibliotecii tale pentru a ajuta oamenii să înțeleagă utilizarea acesteia","githubHandle":"Numele de utilizator GitHub (opțional), pentru a putea edita biblioteca odată ce este trimisă spre revizuire","twitterHandle":"Numele de utilizator Twitter (opțional), pentru a indica sursa la promovarea pe Twitter","website":"Trimitere către pagina ta personală de internet sau altundeva (opțional)"},"errors":{"required":"Obligatoriu","website":"Introdu un URL valid"},"noteDescription":"Trimite-ți biblioteca pentru a fi inclusă în depozitul de biblioteci publice în vederea utilizării de către alte persoane în desenele lor.","noteGuidelines":"Biblioteca trebuie aprobată manual mai întâi. Citește orientările înainte de trimitere. Vei avea nevoie de un cont GitHub pentru a comunica și efectua modificări, dacă este cazul, însă nu este strict necesar.","noteLicense":"Prin trimiterea bibliotecii, ești de acord că aceasta va fi publicată sub Licența MIT, care, pe scurt, înseamnă că oricine o poate folosi fără restricții.","noteItems":"Fiecare element din bibliotecă trebuie să aibă propriul nume astfel încât să fie filtrabil. Următoarele elemente din bibliotecă vor fi incluse:","atleastOneLibItem":"Selectează cel puțin un element din bibliotecă pentru a începe","republishWarning":"Observație: unele dintre elementele selectate sunt marcate ca fiind deja publicate/trimise. Ar trebui să retrimiți elemente numai atunci când actualizezi o trimitere sau o bibliotecă existentă."},"publishSuccessDialog":{"title":"Bibliotecă trimisă","content":"Îți mulțumim, {{authorName}}. Biblioteca a fost trimisă spre revizuire. Poți urmări starea aici"},"confirmDialog":{"resetLibrary":"Resetare bibliotecă","removeItemsFromLib":"Elimină elementele selectate din bibliotecă"},"imageExportDialog":{"header":"Exportare imagine","label":{"withBackground":"Fundal","onlySelected":"Numai selecția","darkMode":"Mod întunecat","embedScene":"Încorporare scenă","scale":"Scală","padding":"Spațiere"},"tooltip":{"embedScene":"Datele scenei vor fi salvate în fișierul PNG/SVG exportat, astfel că scena va putea fi restaurată din acesta.\\nVa crește dimensiunea fișierului exportat."},"title":{"exportToPng":"Exportare ca PNG","exportToSvg":"Exportare ca SVG","copyPngToClipboard":"Copiere PNG în memoria temporară"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Copiere în memoria temporară"}},"encrypted":{"tooltip":"Desenele tale sunt criptate integral, astfel că serverele Excalidraw nu le vor vedea niciodată.","link":"Articol de blog pe criptarea integrală din Excalidraw"},"stats":{"angle":"Unghi","element":"Element","elements":"Elemente","height":"Înălțime","scene":"Scenă","selected":"Selectate","storage":"Stocare","title":"Statistici pentru pasionați","total":"Total","version":"Versiune","versionCopy":"Clic pentru copiere","versionNotAvailable":"Versiune indisponibilă","width":"Lățime"},"toast":{"addedToLibrary":"Adăugat în bibliotecă","copyStyles":"Stiluri copiate.","copyToClipboard":"Copiat în memoria temporară.","copyToClipboardAsPng":"S-a copiat {{exportSelection}} în memoria temporară sub formă de PNG\\n({{exportColorScheme}})","fileSaved":"Fișier salvat.","fileSavedToFilename":"Salvat în {filename}","canvas":"pânza","selection":"selecția","pasteAsSingleElement":"Folosește {{shortcut}} pentru a insera ca un singur element\\nsau insera într-un editor de text existent","unableToEmbed":"Încorporarea acestui URL nu este permisă momentan. Deschideți un tichet cu probleme pe GitHub pentru a solicita adăugarea acestui URL în lista albă","unrecognizedLinkFormat":"URL-ul pe care l-ai încorporat nu coincide cu formatul așteptat. Încearcă să lipești șirul „de încorporat” furnizat de pagina sursă"},"colors":{"transparent":"Transparent","black":"Negru","white":"Alb","red":"Roșu","pink":"Roz","grape":"Struguriu","violet":"Violet","gray":"Gri","blue":"Albastru","cyan":"Cyan","teal":"Cyan-verde","green":"Verde","yellow":"Galben","orange":"Portocaliu","bronze":"Bronz"},"welcomeScreen":{"app":{"center_heading":"Toate datele tale sunt salvate local în navigatorul tău.","center_heading_plus":"Ai vrut să mergi în schimb la Excalidraw+?","menuHint":"Exportare, preferințe, limbi, ..."},"defaults":{"menuHint":"Exportare, preferințe și mai multe...","center_heading":"Diagrame. Făcute. Simple.","toolbarHint":"Alege un instrument și începe să desenezi!","helpHint":"Comenzi rapide și ajutor"}},"colorPicker":{"mostUsedCustomColors":"Cele mai utilizate culori personalizate","colors":"Culori","shades":"Nuanțe","hexCode":"Cod hexa","noShades":"Nu este disponibilă nicio nuanță pentru această culoare"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Exportare ca imagine","button":"Exportare ca imagine","description":"Exportă datele scenei ca fișier din care poți importa mai târziu."},"saveToDisk":{"title":"Salvare pe disc","button":"Salvare pe disc","description":"Exportă datele scenei pe un fișier din care poți importa mai târziu."},"excalidrawPlus":{"title":"Excalidraw+","button":"Exportare în Excalidraw+","description":"Salvează scena în spațiul de lucru Excalidraw+."}},"modal":{"loadFromFile":{"title":"Încărcare din fișier","button":"Încărcare din fișier","description":"Încărcarea dintr-un fișier va înlocui conținutul existent. Poți face mai întâi o copie de rezervă a desenului folosind una dintre opțiunile de mai jos."},"shareableLink":{"title":"Încărcare din lnk","button":"Înlocuiește conținutul meu","description":"Încărcarea unui desen extern va înlocui conținutul existent. Poți face mai întâi o copie de rezervă a desenului folosind una dintre opțiunile de mai jos."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/ru-RU-json-ddc13261ce5d864d36a9.js b/public/excalidraw/excalidraw-assets-dev/locales/ru-RU-json-ddc13261ce5d864d36a9.js
new file mode 100644
index 0000000..7baf25e
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/ru-RU-json-ddc13261ce5d864d36a9.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/ru-RU-json"],{
+
+/***/ "../../locales/ru-RU.json":
+/*!********************************!*\
+ !*** ../../locales/ru-RU.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Вставить","pasteAsPlaintext":"Вставить как обычный текст","pasteCharts":"Вставить диаграммы","selectAll":"Выбрать всё","multiSelect":"Добавить элемент в выделенный фрагмент","moveCanvas":"Переместить холст","cut":"Вырезать","copy":"Копировать","copyAsPng":"Скопировать в буфер обмена как PNG","copyAsSvg":"Скопировать в буфер обмена как SVG","copyText":"Скопировать в буфер обмена как текст","bringForward":"Переместить вперед","sendToBack":"На задний план","bringToFront":"На передний план","sendBackward":"Переместить назад","delete":"Удалить","copyStyles":"Скопировать стили","pasteStyles":"Вставить стили","stroke":"Обводка","background":"Фон","fill":"Заливка","strokeWidth":"Толщина штриха","strokeStyle":"Стиль обводки","strokeStyle_solid":"Сплошная","strokeStyle_dashed":"Пунктирная","strokeStyle_dotted":"Точечная","sloppiness":"Стиль обводки","opacity":"Непрозрачность","textAlign":"Выравнивание текста","edges":"Края","sharp":"Острые","round":"Скругленные","arrowheads":"Стрелка","arrowhead_none":"Нет","arrowhead_arrow":"Cтрелка","arrowhead_bar":"Черта","arrowhead_dot":"Точка","arrowhead_triangle":"Треугольник","fontSize":"Размер шрифта","fontFamily":"Семейство шрифтов","addWatermark":"Добавить «Создано в Excalidraw»","handDrawn":"От руки","normal":"Обычный","code":"Код","small":"Малый","medium":"Средний","large":"Большой","veryLarge":"Очень большой","solid":"Однотонная","hachure":"Штрихованная","zigzag":"Зигзаг","crossHatch":"Перекрестная","thin":"Тонкая","bold":"Жирная","left":"Слева","center":"Центр","right":"Справа","extraBold":"Очень жирная","architect":"Архитектор","artist":"Художник","cartoonist":"Карикатурист","fileTitle":"Имя файла","colorPicker":"Выбор цвета","canvasColors":"Используется на холсте","canvasBackground":"Фон холста","drawingCanvas":"Полотно","layers":"Слои","actions":"Действия","language":"Язык","liveCollaboration":"Онлайн взаимодействие...","duplicateSelection":"Дубликат","untitled":"Безымянный","name":"Имя","yourName":"Ваше имя","madeWithExcalidraw":"Сделано в Excalidraw","group":"Сгруппировать выделение","ungroup":"Разделить выделение","collaborators":"Участники","showGrid":"Показать сетку","addToLibrary":"Добавить в библиотеку","removeFromLibrary":"Удалить из библиотеки","libraryLoadingMessage":"Загрузка библиотеки…","libraries":"Просмотреть библиотеки","loadingScene":"Загрузка сцены…","align":"Выровнять","alignTop":"Выровнять по верхнему краю","alignBottom":"Выровнять по нижнему краю","alignLeft":"Выровнять по левому краю","alignRight":"Выровнять по правому краю","centerVertically":"Центрировать по вертикали","centerHorizontally":"Центрировать по горизонтали","distributeHorizontally":"Распределить по горизонтали","distributeVertically":"Распределить по вертикали","flipHorizontal":"Переворот по горизонтали","flipVertical":"Переворот по вертикали","viewMode":"Вид","share":"Поделиться","showStroke":"Показать выбор цвета обводки","showBackground":"Показать выбор цвета фона","toggleTheme":"Переключить тему","personalLib":"Личная библиотека","excalidrawLib":"Библиотека Excalidraw","decreaseFontSize":"Уменьшить шрифт","increaseFontSize":"Увеличить шрифт","unbindText":"Отвязать текст","bindText":"Привязать текст к контейнеру","createContainerFromText":"Поместить текст в контейнер","link":{"edit":"Редактировать ссылку","editEmbed":"","create":"Создать ссылку","createEmbed":"","label":"Ссылка","labelEmbed":"","empty":""},"lineEditor":{"edit":"Редактирование строки","exit":"Выход из редактора строки"},"elementLock":{"lock":"Блокировать","unlock":"Разблокировать","lockAll":"Заблокировать все","unlockAll":"Разблокировать все"},"statusPublished":"Опубликовано","sidebarLock":"Держать боковую панель открытой","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":"Взять образец цвета с холста"},"library":{"noItems":"Пока ничего не добавлено...","hint_emptyLibrary":"Выберите объект на холсте, чтобы добавить его сюда, или установите библиотеку из публичного репозитория ниже.","hint_emptyPrivateLibrary":"Выберите объект на холсте, чтобы добавить его сюда."},"buttons":{"clearReset":"Очистить холст и сбросить цвет фона","exportJSON":"Сохранить в","exportImage":"Экспортировать изображение...","export":"Сохранить как...","copyToClipboard":"Скопировать в буфер обмена","save":"Сохранить в текущий файл","saveAs":"Сохранить как","load":"Открыть","getShareableLink":"Получить доступ по ссылке","close":"Закрыть","selectLanguage":"Выбрать язык","scrollBackToContent":"Вернуться к содержимому","zoomIn":"Увеличить","zoomOut":"Уменьшить","resetZoom":"Сбросить масштаб","menu":"Меню","done":"Готово","edit":"Изменить","undo":"Шаг назад","redo":"Шаг вперед","resetLibrary":"Сброс библиотеки","createNewRoom":"Создать новую комнату","fullScreen":"Полный экран","darkMode":"Темная тема","lightMode":"Светлая тема","zenMode":"Режим Дзен","objectsSnapMode":"Привязка к объектам","exitZenMode":"Выключить режим концентрации внимания","cancel":"Отменить","clear":"Очистить","remove":"Удалить","embed":"","publishLibrary":"Опубликовать","submit":"Отправить","confirm":"Подтвердить","embeddableInteractionButton":""},"alerts":{"clearReset":"Это очистит весь холст. Вы уверены?","couldNotCreateShareableLink":"Не удалось создать общедоступную ссылку.","couldNotCreateShareableLinkTooBig":"Нельзя создать ссылку, чтобы поделиться. Сцена слишком большая","couldNotLoadInvalidFile":"Не удалось загрузить недопустимый файл","importBackendFailed":"Не удалось импортировать из бэкэнда.","cannotExportEmptyCanvas":"Не может экспортировать пустой холст.","couldNotCopyToClipboard":"Не удалось скопировать в буфер обмена.","decryptFailed":"Не удалось расшифровать данные.","uploadedSecurly":"Загружаемые данные защищена сквозным шифрованием, что означает, что сервер Excalidraw и третьи стороны не могут прочитать содержимое.","loadSceneOverridePrompt":"Загрузка рисунка приведёт к замене имеющегося содержимого. Вы хотите продолжить?","collabStopOverridePrompt":"Остановка сессии перезапишет ваш предыдущий, локально сохранённый рисунок. Вы уверены? \\n\\n(Если вы хотите оставить ваш локальный рисунок, просто закройте вкладку браузера)","errorAddingToLibrary":"Не удалось добавить объект в библиотеку","errorRemovingFromLibrary":"Не удалось удалить объект из библиотеки","confirmAddLibrary":"Будет добавлено {{numShapes}} фигур в вашу библиотеку. Продолжить?","imageDoesNotContainScene":"Это изображение не содержит данных сцены. Вы включили встраивание сцены во время экспорта?","cannotRestoreFromImage":"Сцена не может быть восстановлена из этого изображения","invalidSceneUrl":"Невозможно импортировать сцену с предоставленного URL. Неверный формат, или не содержит верных Excalidraw JSON данных.","resetLibrary":"Это очистит вашу библиотеку. Вы уверены?","removeItemsFromsLibrary":"Удалить {{count}} объект(ов) из библиотеки?","invalidEncryptionKey":"Ключ шифрования должен состоять из 22 символов. Одновременное редактирование отключено.","collabOfflineWarning":"Отсутствует интернет-соединение.\\nВаши изменения не будут сохранены!"},"errors":{"unsupportedFileType":"Неподдерживаемый тип файла.","imageInsertError":"Не удалось вставить изображение. Попробуйте позже...","fileTooBig":"Очень большой файл. Максимально разрешенный размер {{maxSize}}.","svgImageInsertError":"Не удалось вставить изображение SVG. Разметка SVG выглядит недействительной.","failedToFetchImage":"Не удалось получить изображение.","invalidSVGString":"Некорректный SVG.","cannotResolveCollabServer":"Не удалось подключиться к серверу совместного редактирования. Перезагрузите страницу и повторите попытку.","importLibraryError":"Не удалось загрузить библиотеку","collabSaveFailed":"Не удалось сохранить в базу данных. Если проблема повторится, нужно будет сохранить файл локально, чтобы быть уверенным, что вы не потеряете вашу работу.","collabSaveFailed_sizeExceeded":"Не удалось сохранить в базу данных. Похоже, что холст слишком большой. Нужно сохранить файл локально, чтобы быть уверенным, что вы не потеряете вашу работу.","brave_measure_text_error":{"line1":"Похоже, вы используете браузер Brave с включенной опцией Агрессивно блокировать отслеживание.","line2":"Это может привести к поломке Текстовых объектов на рисунке.","line3":"Мы настоятельно рекомендуем отключить эту настройку. Для этого нужно выполнить эти шаги.","line4":"Если отключение этой настройки не исправит отображение текстовых объектов, создайте issue на нашем GitHub или напишите нам в Discord"},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Выделение области","image":"Вставить изображение","rectangle":"Прямоугольник","diamond":"Ромб","ellipse":"Эллипс","arrow":"Cтрелка","line":"Линия","freedraw":"Чертить","text":"Текст","library":"Библиотека","lock":"Сохранять выбранный инструмент активным после рисования","penMode":"Режим пера - предотвращение касания","link":"Добавить/обновить ссылку для выбранной фигуры","eraser":"Ластик","frame":"","embeddable":"","laser":"Лазерная указка","hand":"Рука (перемещение холста)","extraTools":""},"headings":{"canvasActions":"Операции холста","selectedShapeActions":"Операции выбранной фигуры","shapes":"Фигуры"},"hints":{"canvasPanning":"Чтобы двигать холст, удерживайте колесо мыши или пробел во время перетаскивания, или используйте инструмент \\"Рука\\"","linearElement":"Нажмите, чтобы начать несколько точек, перетащите для одной линии","freeDraw":"Нажмите и перетаскивайте, отпустите по завершении","text":"Совет: при выбранном инструменте выделения дважды щёлкните в любом месте, чтобы добавить текст","embeddable":"","text_selected":"Дважды щелкните мышью или нажмите ENTER, чтобы редактировать текст","text_editing":"Нажмите Escape либо Ctrl или Cmd + ENTER для завершения редактирования","linearElementMulti":"Кликните на последней точке или нажмите Escape или Enter чтобы закончить","lockAngle":"Вы можете ограничить угол удерживая SHIFT","resize":"Вы можете ограничить пропорции, удерживая SHIFT во время изменения размеров,\\nудерживайте ALT чтобы изменить размер из центра","resizeImage":"Вы можете свободно изменять размеры, удерживая кнопку SHIFT,\\nудерживайте кнопку ALT, чтобы изменять размер относительно центра","rotate":"Вы можете ограничить углы, удерживая SHIFT во время вращения","lineEditor_info":"Удерживайте CtrlOrCmd и дважды кликните или нажмите CtrlOrCmd + Enter для редактирования точек","lineEditor_pointSelected":"Нажмите Delete для удаления точки (точек),\\nCtrl+D или Cmd+D для дублирования, перетащите для перемещения","lineEditor_nothingSelected":"Выберите точку для редактирования (удерживайте SHIFT выбора нескольких точек),\\nили удерживайте Alt и кликните для добавления новых точек","placeImage":"Щелкните, чтобы разместить изображение, или нажмите и перетащите, чтобы установить его размер вручную","publishLibrary":"Опубликовать свою собственную библиотеку","bindTextToElement":"Нажмите Enter для добавления текста","deepBoxSelect":"Удерживайте Ctrl или Cmd для глубокого выделения, чтобы предотвратить перетаскивание","eraserRevert":"Удерживайте Alt, чтобы вернуть элементы, отмеченные для удаления","firefox_clipboard_write":"Эта функция может быть включена при изменении значения флага \\"dom.events.asyncClipboard.clipboardItem\\" на \\"true\\". Чтобы изменить флаги браузера в Firefox, посетите страницу \\"about:config\\".","disableSnapping":""},"canvasError":{"cannotShowPreview":"Не удается отобразить предпросмотр","canvasTooBig":"Сцена слишком большая.","canvasTooBigTip":"Совет: попробуйте сблизить элементы рисунка."},"errorSplash":{"headingMain":"Возникла ошибка. Попробуйте ","clearCanvasMessage":"Если перезагрузка страницы не помогла, попробуйте ","clearCanvasCaveat":" Текущая работа будет утеряна ","trackedToSentry":"Ошибка с идентификатором {{eventId}} отслеживается в нашей системе.","openIssueMessage":"Для безопасности информация о вашей сцене не включена в ошибку. Если в сцене нет ничего конфиденциального, пожалуйста следуйте нашим Пожалуйста, приложите информацию ниже, скопировав и вставив её, в issue GitHub.","sceneContent":"Содержание сцены:"},"roomDialog":{"desc_intro":"Вы можете пригласить людей в текущую сцену для совместной работы.","desc_privacy":"Не беспокойтесь — во время сеанса используется сквозное шифрование. Всё, что вы нарисуете, останется конфиденциальным и не будет доступно даже нашему серверу.","button_startSession":"Начать сеанс","button_stopSession":"Завершить сеанс","desc_inProgressIntro":"Сеанс совместной работы запущен.","desc_shareLink":"Поделитесь этой ссылкой со всеми участниками:","desc_exitSession":"Завершив сеанс, вы выйдете из комнаты, но сможете продолжить работать с документом локально. Это не повлияет на работу других пользователей — они смогут продолжить совместную работу с их версией документа.","shareTitle":"Присоединиться к активной совместной сессии на Excalidraw"},"errorDialog":{"title":"Ошибка"},"exportDialog":{"disk_title":"Сохранить на диск","disk_details":"Экспортировать данные сцены в файл, из которого можно импортировать позже.","disk_button":"Сохранить в файл","link_title":"Поделитесь ссылкой","link_details":"Экспорт ссылки только для чтения.","link_button":"Экспорт в ссылку","excalidrawplus_description":"Сохраните сцену в ваше рабочее пространство Excalidraw+.","excalidrawplus_button":"Экспорт","excalidrawplus_exportError":"Не удалось экспортировать в Excalidraw+ на данный момент..."},"helpDialog":{"blog":"Прочитайте наш блог","click":"нажать","deepSelect":"Глубокое выделение","deepBoxSelect":"Глубокое выделение рамкой, и предотвращение перетаскивания","curvedArrow":"Изогнутая стрелка","curvedLine":"Изогнутая линия","documentation":"Документация","doubleClick":"двойной клик","drag":"перетащить","editor":"Редактор","editLineArrowPoints":"Редактировать концы линий/стрелок","editText":"Редактировать текст / добавить метку","github":"Нашли проблему? Отправьте","howto":"Следуйте нашим инструкциям","or":"или","preventBinding":"Предотвращать привязку стрелок","tools":"Инструменты","shortcuts":"Горячие клавиши","textFinish":"Закончить редактирование (текстовый редактор)","textNewLine":"Добавить новую строку (текстовый редактор)","title":"Помощь","view":"Просмотр","zoomToFit":"Отмастштабировать, чтобы поместились все элементы","zoomToSelection":"Увеличить до выделенного","toggleElementLock":"Заблокировать/разблокировать выделение","movePageUpDown":"Сдвинуть страницу вверх/вниз","movePageLeftRight":"Сдвинуть страницу вправо/влево"},"clearCanvasDialog":{"title":"Очистить холст"},"publishDialog":{"title":"Опубликовать библиотеку","itemName":"Название объекта","authorName":"Имя автора","githubUsername":"Имя пользователя GitHub","twitterUsername":"Имя пользователя в Twitter","libraryName":"Название библиотеки","libraryDesc":"Описание библиотеки","website":"Веб-сайт","placeholder":{"authorName":"Ваше имя или имя пользователя","libraryName":"Название вашей библиотеки","libraryDesc":"Описание вашей библиотеки, которое поможет людям понять её назначение","githubHandle":"Имя пользователя GitHub (необязательно), чтобы вы смогли редактировать библиотеку после её отправки на проверку","twitterHandle":"Имя пользователя в Twitter (необязательно), чтобы мы знали, кого упомянуть при продвижении в Twitter","website":"Ссылка на ваш личный или какой-то другой сайт (необязательно)"},"errors":{"required":"Обязательно","website":"Введите допустимый URL-адрес"},"noteDescription":"Отправить вашу библиотеку для включения в хранилище публичных библиотек, чтобы другие люди могли использовать объекты из вашей библиотеки в своих рисунках.","noteGuidelines":"Библиотека должна быть подтверждена вручную. Пожалуйста, прочтите рекомендации перед отправкой. Вам понадобится учетная запись GitHub, чтобы общаться и вносить изменения при необходимости, но это не обязательно.","noteLicense":"Выполняя отправку, вы соглашаетесь с тем, что библиотека будет опубликована под лицензией MIT, , что, вкратце, означает, что каждый может использовать её без ограничений.","noteItems":"Каждый объект в библиотеке должен иметь свое собственное имя, чтобы по нему можно было фильтровать. Следующие объекты библиотеки будут включены:","atleastOneLibItem":"Пожалуйста, выберите хотя бы один объект в библиотеке, чтобы начать","republishWarning":"Примечание: некоторые из выбранных элементов помечены как уже опубликованные/отправленные. Вы должны повторно отправить элементы только при обновлении существующей библиотеки или сдаче работы."},"publishSuccessDialog":{"title":"Библиотека отправлена","content":"Благодарим вас, {{authorName}}. Ваша библиотека была отправлена на проверку. Вы можете отслеживать статусздесь"},"confirmDialog":{"resetLibrary":"Сброс библиотеки","removeItemsFromLib":"Удалить выбранные объекты из библиотеки"},"imageExportDialog":{"header":"Экспортировать изображение","label":{"withBackground":"Фон","onlySelected":"Только выделенное","darkMode":"Темная тема","embedScene":"Встроить сцену","scale":"Масштаб","padding":"Отступ"},"tooltip":{"embedScene":"Сцена будет сохранена в PNG/SVG файл так, чтобы всю сцену можно будет восстановить из этого файла. Это увеличит размер файла."},"title":{"exportToPng":"Экспорт в PNG","exportToSvg":"Экспорт в SVG","copyPngToClipboard":"Скопировать PNG в буфер обмена"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Скопировать в буфер обмена"}},"encrypted":{"tooltip":"Ваши данные защищены сквозным (End-to-end) шифрованием. Серверы Excalidraw никогда не получат доступ к ним.","link":"Запись блога о сквозном шифровании в Excalidraw"},"stats":{"angle":"Угол","element":"Элемент","elements":"Элементы","height":"Высота","scene":"Сцены","selected":"Выбран","storage":"Хранилище","title":"Статистика для ботаников","total":"Всего","version":"Версия","versionCopy":"Копировать","versionNotAvailable":"Версия не доступна","width":"Ширина"},"toast":{"addedToLibrary":"Добавлено в библиотеку","copyStyles":"Скопированы стили.","copyToClipboard":"Скопировано в буфер обмена.","copyToClipboardAsPng":"{{exportSelection}} скопировано как PNG ({{exportColorScheme}})","fileSaved":"Файл сохранён.","fileSavedToFilename":"Сохранено в {filename}","canvas":"холст","selection":"выделение","pasteAsSingleElement":"Используйте {{shortcut}}, чтобы вставить один объект,\\nили вставьте в существующий текстовый редактор","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Прозрачный","black":"Чёрный","white":"Белый","red":"Красный","pink":"Розовый","grape":"Виноградный","violet":"Фиолетовый","gray":"Серый","blue":"Синий","cyan":"Голубой","teal":"Бирюзовый","green":"Зелёный","yellow":"Жёлтый","orange":"Оранжевый","bronze":"Бронзовый"},"welcomeScreen":{"app":{"center_heading":"Все ваши данные сохраняются локально в вашем браузере.","center_heading_plus":"Хотите перейти на Excalidraw+?","menuHint":"Экспорт, настройки, языки, ..."},"defaults":{"menuHint":"Экспорт, настройки и другое...","center_heading":"Диаграммы. Просто.","toolbarHint":"Выберите инструмент и начните рисовать!","helpHint":"Сочетания клавиш и помощь"}},"colorPicker":{"mostUsedCustomColors":"Часто используемые пользовательские цвета","colors":"Цвета","shades":"Оттенки","hexCode":"Шестнадцатеричный код","noShades":"Нет доступных оттенков для этого цвета"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Экспортировать как изображение","button":"Экспортировать как изображение","description":""},"saveToDisk":{"title":"Сохранить на диск","button":"Сохранить на диск","description":""},"excalidrawPlus":{"title":"Excalidraw+","button":"Экспорт в Excalidraw+","description":""}},"modal":{"loadFromFile":{"title":"Загрузить из файла","button":"Загрузить из файла","description":""},"shareableLink":{"title":"Загрузить по ссылке","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/si-LK-json-16eb66dbfc6c55fc85b1.js b/public/excalidraw/excalidraw-assets-dev/locales/si-LK-json-16eb66dbfc6c55fc85b1.js
new file mode 100644
index 0000000..ddc6331
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/si-LK-json-16eb66dbfc6c55fc85b1.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/si-LK-json"],{
+
+/***/ "../../locales/si-LK.json":
+/*!********************************!*\
+ !*** ../../locales/si-LK.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"අලවන්න","pasteAsPlaintext":"","pasteCharts":"ප්රස්ථාරය","selectAll":"සියල්ලම","multiSelect":"තෝරා ගැනීමට අංගය එකතු කරන්න","moveCanvas":"කැන්වසය චලනය කරන්න","cut":"කපන්න","copy":"පිටපත් කරන්න","copyAsPng":"PNG ලෙස පිටපත් කරන්න","copyAsSvg":"SVG ලෙස පිටපත් කරන්න","copyText":"","bringForward":"ඉදිරියට ගෙන්න","sendToBack":"පසුපසටම ගෙනියන්න","bringToFront":"ඉදිරියටම ගෙන්න","sendBackward":"පසුපසට ගෙනියන්න","delete":"මකන්න","copyStyles":"","pasteStyles":"","stroke":"","background":"","fill":"","strokeWidth":"","strokeStyle":"","strokeStyle_solid":"","strokeStyle_dashed":"","strokeStyle_dotted":"","sloppiness":"","opacity":"","textAlign":"","edges":"","sharp":"","round":"","arrowheads":"","arrowhead_none":"","arrowhead_arrow":"","arrowhead_bar":"","arrowhead_dot":"","arrowhead_triangle":"","fontSize":"","fontFamily":"","addWatermark":"","handDrawn":"","normal":"","code":"","small":"","medium":"","large":"","veryLarge":"ඉතා විශාල","solid":"විශාල","hachure":"මධ්යම","zigzag":"","crossHatch":"","thin":"කෙට්ටු","bold":"තද","left":"වම","center":"මැද","right":"දකුණ","extraBold":"ඉතා තද","architect":"වාස්තුවේදීයා","artist":"කලාකරු","cartoonist":"සැකිලිරූකරු","fileTitle":"ගොනු නාමය","colorPicker":"පාට තෝරකය","canvasColors":"","canvasBackground":"කැන්වස පසුබිම","drawingCanvas":"චිත්රක කැන්වසය","layers":"ලේයර","actions":"ක්රියාකාරකම","language":"භාෂාව ","liveCollaboration":"","duplicateSelection":"","untitled":"","name":"නම","yourName":"","madeWithExcalidraw":"","group":"","ungroup":"","collaborators":"","showGrid":"","addToLibrary":"","removeFromLibrary":"","libraryLoadingMessage":"","libraries":"","loadingScene":"","align":"","alignTop":"","alignBottom":"","alignLeft":"","alignRight":"","centerVertically":"","centerHorizontally":"","distributeHorizontally":"","distributeVertically":"","flipHorizontal":"","flipVertical":"","viewMode":"","share":"","showStroke":"","showBackground":"","toggleTheme":"","personalLib":"","excalidrawLib":"","decreaseFontSize":"","increaseFontSize":"","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"","editEmbed":"","create":"","createEmbed":"","label":"","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"","unlock":"","lockAll":"","unlockAll":""},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"","exportJSON":"","exportImage":"","export":"","copyToClipboard":"","save":"","saveAs":"","load":"","getShareableLink":"","close":"","selectLanguage":"","scrollBackToContent":"","zoomIn":"","zoomOut":"","resetZoom":"","menu":"","done":"","edit":"","undo":"","redo":"","resetLibrary":"","createNewRoom":"","fullScreen":"","darkMode":"","lightMode":"","zenMode":"","objectsSnapMode":"","exitZenMode":"","cancel":"","clear":"","remove":"","embed":"","publishLibrary":"","submit":"","confirm":"","embeddableInteractionButton":""},"alerts":{"clearReset":"","couldNotCreateShareableLink":"","couldNotCreateShareableLinkTooBig":"","couldNotLoadInvalidFile":"","importBackendFailed":"","cannotExportEmptyCanvas":"","couldNotCopyToClipboard":"","decryptFailed":"","uploadedSecurly":"","loadSceneOverridePrompt":"","collabStopOverridePrompt":"","errorAddingToLibrary":"","errorRemovingFromLibrary":"","confirmAddLibrary":"","imageDoesNotContainScene":"","cannotRestoreFromImage":"","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"","invalidEncryptionKey":"","collabOfflineWarning":""},"errors":{"unsupportedFileType":"","imageInsertError":"","fileTooBig":"","svgImageInsertError":"","failedToFetchImage":"","invalidSVGString":"","cannotResolveCollabServer":"","importLibraryError":"","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"","image":"","rectangle":"","diamond":"","ellipse":"","arrow":"","line":"","freedraw":"","text":"","library":"","lock":"","penMode":"","link":"","eraser":"","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"","selectedShapeActions":"","shapes":""},"hints":{"canvasPanning":"","linearElement":"","freeDraw":"","text":"","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"","lockAngle":"","resize":"","resizeImage":"","rotate":"","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"","canvasTooBig":"","canvasTooBigTip":""},"errorSplash":{"headingMain":"","clearCanvasMessage":"","clearCanvasCaveat":"","trackedToSentry":"","openIssueMessage":"","sceneContent":""},"roomDialog":{"desc_intro":"","desc_privacy":"","button_startSession":"","button_stopSession":"","desc_inProgressIntro":"","desc_shareLink":"","desc_exitSession":"","shareTitle":""},"errorDialog":{"title":""},"exportDialog":{"disk_title":"","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"","excalidrawplus_exportError":""},"helpDialog":{"blog":"","click":"","deepSelect":"","deepBoxSelect":"","curvedArrow":"","curvedLine":"","documentation":"","doubleClick":"","drag":"","editor":"","editLineArrowPoints":"","editText":"","github":"","howto":"","or":"","preventBinding":"","tools":"","shortcuts":"","textFinish":"","textNewLine":"","title":"","view":"","zoomToFit":"","zoomToSelection":"","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"","githubUsername":"","twitterUsername":"","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"","link":""},"stats":{"angle":"","element":"","elements":"","height":"","scene":"","selected":"","storage":"","title":"","total":"","version":"","versionCopy":"","versionNotAvailable":"","width":""},"toast":{"addedToLibrary":"","copyStyles":"","copyToClipboard":"","copyToClipboardAsPng":"","fileSaved":"","fileSavedToFilename":"","canvas":"","selection":"","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/sk-SK-json-782ead8707f2ad0e8e4e.js b/public/excalidraw/excalidraw-assets-dev/locales/sk-SK-json-782ead8707f2ad0e8e4e.js
new file mode 100644
index 0000000..3b24f72
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/sk-SK-json-782ead8707f2ad0e8e4e.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/sk-SK-json"],{
+
+/***/ "../../locales/sk-SK.json":
+/*!********************************!*\
+ !*** ../../locales/sk-SK.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Vložiť","pasteAsPlaintext":"Vložiť ako obyčajný text","pasteCharts":"Vložiť grafy","selectAll":"Vybrať všetko","multiSelect":"Pridať prvok do výberu","moveCanvas":"Pohyb plátna","cut":"Vystrihnúť","copy":"Kopírovať","copyAsPng":"Kopírovať do schránky ako PNG","copyAsSvg":"Kopírovať do schránky ako SVG","copyText":"Kopírovať do schránky ako text","bringForward":"Presunúť o úroveň dopredu","sendToBack":"Presunúť dozadu","bringToFront":"Presunúť dopredu","sendBackward":"Presunúť o úroveň dozadu","delete":"Vymazať","copyStyles":"Kopírovať štýly","pasteStyles":"Vložiť štýly","stroke":"Obrys","background":"Pozadie","fill":"Výplň","strokeWidth":"Hrúbka obrysu","strokeStyle":"Štýl obrysu","strokeStyle_solid":"Plný","strokeStyle_dashed":"Čiarkovaný","strokeStyle_dotted":"Bodkovaný","sloppiness":"Štylizácia","opacity":"Priehľadnosť","textAlign":"Zarovnanie textu","edges":"Okraje","sharp":"Ostré","round":"Zaokrúhlené","arrowheads":"Zakončenie šípky","arrowhead_none":"Žiadne","arrowhead_arrow":"Šípka","arrowhead_bar":"Čiara","arrowhead_dot":"Bod","arrowhead_triangle":"Trojuholník","fontSize":"Veľkosť písma","fontFamily":"Písmo","addWatermark":"Pridať \\"Vytvorené s Excalidraw\\"","handDrawn":"Ručne písané","normal":"Normálne","code":"Kód","small":"Malé","medium":"Stredné","large":"Veľké","veryLarge":"Veľmi veľké","solid":"Plná","hachure":"Šrafovaná","zigzag":"Cik-cak","crossHatch":"Mriežkovaná","thin":"Tenká","bold":"Hrubá","left":"Doľava","center":"Na stred","right":"Doprava","extraBold":"Veľmi hrubá","architect":"Architekt","artist":"Umelec","cartoonist":"Ilustrátor","fileTitle":"Názov súboru","colorPicker":"Výber farby","canvasColors":"Použité na plátne","canvasBackground":"Pozadie plátna","drawingCanvas":"Kresliace plátno","layers":"Vrstvy","actions":"Akcie","language":"Jazyk","liveCollaboration":"Živá spolupráca...","duplicateSelection":"Duplikovať","untitled":"Bez názvu","name":"Meno","yourName":"Vaše meno","madeWithExcalidraw":"Vytvorené s Excalidraw","group":"Zoskupiť","ungroup":"Zrušiť zoskupenie","collaborators":"Spolupracovníci","showGrid":"Zobraziť mriežku","addToLibrary":"Pridať do knižnice","removeFromLibrary":"Odstrániť z knižnice","libraryLoadingMessage":"Načítavanie knižnice…","libraries":"Prehliadať knižnice","loadingScene":"Načítavanie scény…","align":"Zarovnanie","alignTop":"Zarovnať nahor","alignBottom":"Zarovnať nadol","alignLeft":"Zarovnať doľava","alignRight":"Zarovnať doprava","centerVertically":"Zarovnať zvislo na stred","centerHorizontally":"Zarovnať vodorovne na stred","distributeHorizontally":"Rozmiestniť vodorovne","distributeVertically":"Rozmiestniť zvisle","flipHorizontal":"Prevrátiť vodorovne","flipVertical":"Prevrátiť zvislo","viewMode":"Režim zobrazenia","share":"Zdieľať","showStroke":"Zobraziť výber farby pre obrys","showBackground":"Zobraziť výber farby pre pozadie","toggleTheme":"Prepnúť tému","personalLib":"Moja knižnica","excalidrawLib":"Excalidraw knižnica","decreaseFontSize":"Zmenšiť veľkosť písma","increaseFontSize":"Zväčšiť veľkosť písma","unbindText":"Zrušiť previazanie textu","bindText":"Previazať text s kontajnerom","createContainerFromText":"Zabaliť text do kontajneru","link":{"edit":"Upraviť odkaz","editEmbed":"Editovať a zapustiť odkaz","create":"Vytvoriť odkaz","createEmbed":"Vytvoriť a zapustiť odkaz","label":"Odkaz","labelEmbed":"Zapustiť odkaz","empty":"Nie je nastavený žiaden odkaz"},"lineEditor":{"edit":"Upraviť čiaru","exit":"Ukončiť editovanie čiary"},"elementLock":{"lock":"Zamknúť","unlock":"Odomknúť","lockAll":"Zamknúť všetko","unlockAll":"Odomknúť všetko"},"statusPublished":"Zverejnené","sidebarLock":"Nechať bočný panel otvorený","selectAllElementsInFrame":"Vybrať všetky prvky v ráme","removeAllElementsFromFrame":"Odstrániť všetky prvky z rámu","eyeDropper":"Vybrať farbu z plátna"},"library":{"noItems":"Zatiaľ neboli pridané žiadne položky...","hint_emptyLibrary":"Vyberte položku z plátna pre jej pridanie do knižnice alebo použite knižnicu z verejného zoznamu knižníc nižšie.","hint_emptyPrivateLibrary":"Vyberte položku z plátna pre jej pridanie do knižnice."},"buttons":{"clearReset":"Obnoviť plátno","exportJSON":"Exportovať do súboru","exportImage":"Exportovať obrázok...","export":"Uložiť do...","copyToClipboard":"Kopírovať do schránky","save":"Uložiť do aktuálneho súboru","saveAs":"Uložiť ako","load":"Otvoriť","getShareableLink":"Získať odkaz na zdieľanie","close":"Zavrieť","selectLanguage":"Zvoliť jazyk","scrollBackToContent":"Vrátiť sa späť na obsah","zoomIn":"Priblížiť","zoomOut":"Oddialiť","resetZoom":"Obnoviť priblíženie","menu":"Ponuka","done":"Hotovo","edit":"Upraviť","undo":"Späť","redo":"Znova","resetLibrary":"Obnoviť knižnicu","createNewRoom":"Vytvoriť novú miestnosť","fullScreen":"Celá obrazovka","darkMode":"Tmavý režim","lightMode":"Svetlý režim","zenMode":"Režim zen","objectsSnapMode":"Prichytiť k objektom","exitZenMode":"Zrušiť režim zen","cancel":"Zrušiť","clear":"Vymazať","remove":"Odstrániť","embed":"Prepnúť zapustenie","publishLibrary":"Uverejniť","submit":"Potvrdiť","confirm":"Potvrdiť","embeddableInteractionButton":"Kliknite pre interakciu"},"alerts":{"clearReset":"Týmto sa vyčistí celé plátno. Ste si istí?","couldNotCreateShareableLink":"Nepodarilo sa vytvoriť odkaz na zdieľanie.","couldNotCreateShareableLinkTooBig":"Nepodarilo sa vytvoriť odkaz na zdieľanie: scéna je príliš veľká","couldNotLoadInvalidFile":"Nepodarilo sa načítať nevalidný súbor","importBackendFailed":"Nepdarilo sa importovanie zo serveru.","cannotExportEmptyCanvas":"Nie je možné exportovať prázdne plátno.","couldNotCopyToClipboard":"Kopírovanie do schránky sa nepodarilo.","decryptFailed":"Nepodarilo sa rozšifrovať údaje.","uploadedSecurly":"Nahratie je zabezpečené end-to-end šifrovaním, takže Excalidraw server a tretie strany nedokážu prečítať jeho obsah.","loadSceneOverridePrompt":"Nahratie externej kresby nahradí existujúci obsah. Prajete si pokračovať?","collabStopOverridePrompt":"Ukončenie schôdze nahradí vašu predchádzajúcu lokálne uloženú scénu. Ste si istý?\\n\\n(Ak si chcete ponechať lokálnu scénu, jednoducho iba zavrite kartu prehliadača.)","errorAddingToLibrary":"Nepodarilo sa pridať položku do knižnice","errorRemovingFromLibrary":"Nepodarilo sa odstrániť položku z knižnice","confirmAddLibrary":"Týmto sa pridá {{numShapes}} tvar(ov) do vašej knižnice. Ste si istí?","imageDoesNotContainScene":"Tento obrázok neobsahuje žiadne údaje scény. Zvolili ste možnosť zahrnúť scénu počas exportu?","cannotRestoreFromImage":"Nepodarilo sa obnoviť scénu z tohto obrázkového súboru","invalidSceneUrl":"Nepodarilo sa načítať scénu z poskytnutej URL. Je nevalidná alebo neobsahuje žiadne validné Excalidraw JSON dáta.","resetLibrary":"Týmto vyprázdnite vašu knižnicu. Ste si istý?","removeItemsFromsLibrary":"Odstrániť {{count}} položiek z knižnice?","invalidEncryptionKey":"Šifrovací kľúč musí mať 22 znakov. Živá spolupráca je vypnutá.","collabOfflineWarning":"Internetové pripojenie nie je dostupné.\\nVaše zmeny nebudú uložené!"},"errors":{"unsupportedFileType":"Nepodporovaný typ súboru.","imageInsertError":"Nepodarilo sa vložiť obrázok. Skúste to znova neskôr...","fileTooBig":"Súbor je príliš veľký. Maximálna povolená veľkosť je {{maxSize}}.","svgImageInsertError":"Nepodarilo sa vložiť SVG obrázok. SVG formát je pravdepodobne nevalidný.","failedToFetchImage":"","invalidSVGString":"Nevalidné SVG.","cannotResolveCollabServer":"Nepodarilo sa pripojiť ku kolaboračnému serveru. Prosím obnovte stránku a skúste to znovu.","importLibraryError":"Nepodarilo sa načítať knižnicu","collabSaveFailed":"Uloženie do databázy sa nepodarilo. Ak tento problém pretrváva uložte si váš súbor lokálne aby ste nestratili vašu prácu.","collabSaveFailed_sizeExceeded":"Uloženie do databázy sa nepodarilo, pretože veľkosť plátna je príliš veľká. Uložte si váš súbor lokálne aby ste nestratili vašu prácu.","brave_measure_text_error":{"line1":"Vyzerá to, že používate prehliadač Brave so zapnutým nastavením pre agresívne blokovanie.","line2":"To môže spôsobiť nesprávne zobrazenie textových prvkov vo vašej kresbe.","line3":"Dôrazne odporúčame vypnutie toho nastavenia. Môžete tak spraviť vykonaním týchto krokov.","line4":"Ak vypnutie toho nastavenia nevyrieši problém so zobrazením textových prvkov, prosím ohláste problém na našom GitHub-e alebo nám napíšte na náš Discord"},"libraryElementTypeError":{"embeddable":"Zapustené prvky nie je možné pridať do knižnice.","image":"Podpora pre pridávanie obrázkov do knižnice bude dostupná už čoskoro!"}},"toolBar":{"selection":"Výber","image":"Vložiť obrázok","rectangle":"Obdĺžnik","diamond":"Diamant","ellipse":"Elipsa","arrow":"Šípka","line":"Čiara","freedraw":"Kresliť","text":"Text","library":"Knižnica","lock":"Nechať zvolený nástroj aktívny po skončení kreslenia","penMode":"Režim pera – zabrániť dotyku","link":"Pridať/ Upraviť odkaz pre vybraný tvar","eraser":"Guma","frame":"Nástroj rám","embeddable":"Web Embed","laser":"","hand":"Ruka (nástroj pre pohyb plátna)","extraTools":"Ďalšie nástroje"},"headings":{"canvasActions":"Akcie plátna","selectedShapeActions":"Akcie tvarov z výberu","shapes":"Tvary"},"hints":{"canvasPanning":"Pre pohyb plátna podržte koliesko myši alebo medzerník počas ťahania, alebo použite nástroj ruka","linearElement":"Kliknite na vloženie viacerých bodov, potiahnite na vytvorenie jednej priamky","freeDraw":"Kliknite a ťahajte, pustite na ukončenie","text":"Tip: text môžete pridať aj dvojklikom kdekoľvek, ak je zvolený nástroj výber","embeddable":"Kliknite a ťahajte pre zapustenie webovej stránky","text_selected":"Použite dvojklik alebo stlačte Enter na editáciu textu","text_editing":"Stlačte Escape alebo CtrlOrCmd+ENTER na ukončenie editovania","linearElementMulti":"Kliknite na počiatočný bod alebo stlačte Escape alebo Enter na ukončenie","lockAngle":"Počas rotácie obmedzíte uhol podržaním SHIFT","resize":"Počas zmeny veľkosti zachováte proporcie podržaním SHIFT,\\\\npodržaním ALT meníte veľkosť so zachovaním stredu","resizeImage":"Podržte SHIFT pre voľnú zmenu veľkosti, podržte ALT pre zmenu veľkosti od stredu","rotate":"Počas rotácie obmedzíte uhol podržaním SHIFT","lineEditor_info":"Podržte CtrlOrCmd a kliknite dva krát alebo stlačte CtrlOrCmd + Enter pre editáciu bodov","lineEditor_pointSelected":"Stačte Delete na vymazanie bodu (bodov), CtrlOrCmd+D na duplikovanie, alebo potiahnite na presunutie","lineEditor_nothingSelected":"Zvoľte bod na upravovanie (podržte SHIFT pre zvolenie viacerých bodov) alebo podržte Alt a kliknite na pridanie nového bodu","placeImage":"Kliknite pre umiestnenie obrázka alebo kliknite a ťahajte pre zmenu jeho veľkosti","publishLibrary":"Uverejniť vašu knižnicu","bindTextToElement":"Stlačte enter na pridanie textu","deepBoxSelect":"Podržte CtrlOrCmd na výber v skupine alebo zamedzeniu poťiahnutia","eraserRevert":"Podržte Alt pre prehodenie položiek určených na vymazanie","firefox_clipboard_write":"Táto sa funkcionalita sa dá zapnúť nastavením \\"dom.events.asyncClipboard.clipboardItem\\" na \\"true\\". Pre zmenu nastavení vo Firefox-e otvorte stránku \\"about:config\\".","disableSnapping":"Podržte CtrlOrCmd pre vypnutie prichytávania"},"canvasError":{"cannotShowPreview":"Nie je možné zobraziť náhľad plátna","canvasTooBig":"Plátno je možno príliš veľké.","canvasTooBigTip":"Tip: skúste presunúť najvzdialenejšie prvky bližšie k sebe."},"errorSplash":{"headingMain":"Nastala chyba. Vyskúšajte ","clearCanvasMessage":"Ak obnovenie stránky nepomáha, vyskúšajte ","clearCanvasCaveat":" To bude mať za následok stratu práce ","trackedToSentry":"Chyba s identifikátorom {{eventId}} bola zaznamenaná v našom systéme.","openIssueMessage":"Boli sme veľmi opatrní, aby informácie vašej scény neboli v chybe zaznamenané. Ak vaša scéna nie je súkromná, prosím zvážte pokračovanie na naše Prosím zahrňte informácie nižšie pomocou kopírovania a prilepenia do GitHub issue.","sceneContent":"Obsah scény:"},"roomDialog":{"desc_intro":"Pozvite niekoho do svojej aktuálnej scény a pracujte spoločne.","desc_privacy":"Nemajte obavy, schôdza používa end-to-end šifrovanie, takže všetko čo nakreslíte je súkromné. Dokonca, ani náš server dedokáže prečítať, čo ste vytvorili.","button_startSession":"Začať schôdzu","button_stopSession":"Ukončiť schôdzu","desc_inProgressIntro":"Práve prebieha živá schôdza.","desc_shareLink":"Zdieľajte tento odkaz s osobou, s ktorou chcete spolupracovať:","desc_exitSession":"Ukončenie schôdze vás odpojí z miestnosti, avšak naďalej budete môcť pokračovať v práci na scéne lokálne. Toto neovplyvní ostatných spolupracovníkov a stále budú môcť spolupracovať na ich verzii.","shareTitle":"Pripojiť sa k živej schôdzi na Excalidraw"},"errorDialog":{"title":"Chyba"},"exportDialog":{"disk_title":"Uložiť na disk","disk_details":"Exportovať údaje scény do súboru, z ktorého môžu byť neskôr importované.","disk_button":"Uložiť do súboru","link_title":"Odkaz na zdieľanie","link_details":"Exportovať ako odkaz iba na čítanie.","link_button":"Exportovať ako odkaz","excalidrawplus_description":"Uložiť scénu do vášho Excalidraw+ pracovného priestoru.","excalidrawplus_button":"Exportovať","excalidrawplus_exportError":"Nepodarilo sa vykonať export do Excalidraw+..."},"helpDialog":{"blog":"Prečítajte si náš blog","click":"kliknutie","deepSelect":"Výber v skupine","deepBoxSelect":"Výber v skupine alebo zamedzenie poťiahnutia","curvedArrow":"Zakrivená šípka","curvedLine":"Zakrivená čiara","documentation":"Dokumentácia","doubleClick":"dvojklik","drag":"potiahnutie","editor":"Editovanie","editLineArrowPoints":"Editácia bodov čiary/šípky","editText":"Editácia textu / pridanie štítku","github":"Objavili ste problém? Nahláste ho","howto":"Postupujte podľa naších návodov","or":"alebo","preventBinding":"Zakázať pripájanie šípky","tools":"Nástroje","shortcuts":"Klávesové skratky","textFinish":"Ukončenie editovania (text editor)","textNewLine":"Vložiť nový riadok (text editor)","title":"Pomocník","view":"Zobrazenie","zoomToFit":"Priblížiť aby boli zahrnuté všetky prvky","zoomToSelection":"Priblížiť na výber","toggleElementLock":"Zamknúť/odomknúť vybrané","movePageUpDown":"Posunúť stranu hore/dole","movePageLeftRight":"Posunúť stranu doľava/doprava"},"clearCanvasDialog":{"title":"Vyčistiť plátno"},"publishDialog":{"title":"Uverejniť knižnicu","itemName":"Názov položky","authorName":"Meno autora","githubUsername":"Github užívateľské meno","twitterUsername":"Twitter užívateľské meno","libraryName":"Názov knižnice","libraryDesc":"Popis knižnice","website":"Webová stránka","placeholder":{"authorName":"Vaše meno alebo užívateľské meno","libraryName":"Názov vašej knižnice","libraryDesc":"Popis vašej knižnice, ktorý ostatným pomôže porozumieť jej vhodnému použitiu","githubHandle":"GitHub užívateľské meno (nepovinné), aby ste mohli robiť úpravy po tom, čo bude knižnica uverejnená na schválenie","twitterHandle":"Twitter užívateľské meno (nepovinné), aby sme vedeli komu pripísať zásluhu pri propagovaní cez Twitter","website":"Odkaz na vašu osobnú webovú stránku alebo niekam inam (nepovinné)"},"errors":{"required":"Povinné","website":"Zadajte platnú adresu URL"},"noteDescription":"Uverejnite vašu knižnicu vo verejnom zozname knižnícaby ju aj ostatní mohli použiť v ich náčrtoch.","noteGuidelines":"Knižnica musí byť najprv manuálne schválená. Prosím prečítajte si pokyny pred uverejnením. Budete potrebovať Github účet na komunikáciu a vykonanie zmien, ak budú potrebné, avšak nie je to úplne povinné.","noteLicense":"Potvrdením súhlasíte, že knižnica bude zverejnená s MIT licenciou, čo v skratke znamená, že ju môže použiť hocikto bez obmedzení.","noteItems":"Každá položka v knižnici musí mať svoje vlastné meno, aby sa dala vyhľadať. Súčasťou knižnice budú nasledujúce položky:","atleastOneLibItem":"Začnite prosím zvolením aspoň jednej položky z knižnice","republishWarning":"Poznámka: Niektoré z vybraných položiek sú už označené ako zverejnené. Ich znovu uverejnenie by ste mali vykovať iba vtedy ak aktualizujete už existujúcu knižnicu alebo požiadavku na uverejnenie."},"publishSuccessDialog":{"title":"Knižnica uverejnená","content":"Ďakujeme vám {{authorName}}. Vaša knižnica bola uverejnená na posúdenie. Stav môžete skontrolovaťtu"},"confirmDialog":{"resetLibrary":"Obnoviť knižnicu","removeItemsFromLib":"Odstrániť zvolené položky z knižnice"},"imageExportDialog":{"header":"Exportovať obrázok","label":{"withBackground":"Pozadie","onlySelected":"Iba vybrané","darkMode":"Tmavý režim","embedScene":"Zahrnúť scénu","scale":"Mierka","padding":"Odsadenie"},"tooltip":{"embedScene":"Údaje scény budú uložené do exportovaného PNG/SVG súboru, takže scéna z neho môže byť opäť obnovená.\\nBude to mať za následok zvýšenie veľkosti súboru."},"title":{"exportToPng":"Exportovať do PNG","exportToSvg":"Exportovať do SVG","copyPngToClipboard":"Kopírovať PNG do schránky"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Kopírovať do schránky"}},"encrypted":{"tooltip":"Vaše kresby používajú end-to-end šifrovanie, takže ich Excalidraw server nedokáže prečítať.","link":"Blog o end-to-end šifrovaní v Excalidraw"},"stats":{"angle":"Uhol","element":"Prvok","elements":"Prvky","height":"Výška","scene":"Scéna","selected":"Vybrané","storage":"Úložisko","title":"Štatistiky","total":"Celkom","version":"Verzia","versionCopy":"Kliknutím skopírujete","versionNotAvailable":"Verzia nie je k dispozícii","width":"Šírka"},"toast":{"addedToLibrary":"Pridané do knižnice","copyStyles":"Štýly skopírované.","copyToClipboard":"Skopírované do schránky.","copyToClipboardAsPng":"Kopírovanie {{exportSelection}} do schránky ako PNG prebehlo úspešne\\n({{exportColorScheme}})","fileSaved":"Súbor uložený.","fileSavedToFilename":"Uložený ako {filename}","canvas":"plátna","selection":"výberu","pasteAsSingleElement":"Použitím {{shortcut}} vložte ako samostatný prvok alebo vložte do existujúceho editovaného textu","unableToEmbed":"Zapustenie tejto URL nie je povolené. Vytvorte issue na GitHub-e a požiadajte povolenie tejto URL","unrecognizedLinkFormat":"Odkaz, ktorý sa snažíte zapustiť nie je v očakávanom formáte. Prosím skúste vložiť \'odkaz na zdieľanie\' poskytnutý zdrojovou webovou stránkou"},"colors":{"transparent":"Priehľadná","black":"Čierna","white":"Biela","red":"Červená","pink":"Ružová","grape":"Hroznová fialová","violet":"Fialová","gray":"Sivá","blue":"Modrá","cyan":"Azúrová","teal":"Modrozelená","green":"Zelená","yellow":"Žltá","orange":"Oranžová","bronze":"Bronzová"},"welcomeScreen":{"app":{"center_heading":"Všetky vaše dáta sú uložené lokálne vo vašom prehliadači.","center_heading_plus":"Chceli ste namiesto toho prejsť do Excalidraw+?","menuHint":"Exportovanie, nastavenia, jazyky, ..."},"defaults":{"menuHint":"Exportovanie, nastavenia a ďalšie...","center_heading":"Diagramy. Jednoducho.","toolbarHint":"Zvoľte nástroj a začnite kresliť!","helpHint":"Klávesové skratky a pomocník"}},"colorPicker":{"mostUsedCustomColors":"Najpoužívanejšie vlastné farby","colors":"Farby","shades":"Odtiene","hexCode":"Hex kód","noShades":"Pre túto farbu nie sú dostupné žiadne odtiene"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Exportovať ako obrázok","button":"Exportovať ako obrázok","description":"Exportovať údaje scény ako obrázok, z ktorého môžu byť neskôr importované."},"saveToDisk":{"title":"Uložiť na disk","button":"Uložiť na disk","description":"Exportovať údaje scény do súboru, z ktorého môžu byť neskôr importované."},"excalidrawPlus":{"title":"Excalidraw+","button":"Exportovať ako Excalidraw+","description":"Uložiť scénu do vášho Excalidraw+ pracovného priestoru."}},"modal":{"loadFromFile":{"title":"Načítať zo súboru","button":"Načítať zo súboru","description":"Načítanie zo súboru nahradí váš existujúci obsah. Vašu kresbu môžete zálohovať jednou z nižšie uvedených možností."},"shareableLink":{"title":"Načítať z odkazu","button":"Nahradiť môj obsah","description":"Načítanie externej kresby nahradí váš existujúci obsah. Vašu kresbu môžete zálohovať jednou z nižšie uvedených možností."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/sl-SI-json-82e55cf7cdbdc7d7f959.js b/public/excalidraw/excalidraw-assets-dev/locales/sl-SI-json-82e55cf7cdbdc7d7f959.js
new file mode 100644
index 0000000..33d8183
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/sl-SI-json-82e55cf7cdbdc7d7f959.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/sl-SI-json"],{
+
+/***/ "../../locales/sl-SI.json":
+/*!********************************!*\
+ !*** ../../locales/sl-SI.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Prilepi","pasteAsPlaintext":"Prilepi kot navadno besedilo","pasteCharts":"Prilepi grafikone","selectAll":"Izberi vse","multiSelect":"Dodaj element v izbor","moveCanvas":"Premakni platno","cut":"Izreži","copy":"Kopiraj","copyAsPng":"Kopiraj v odložišče kot PNG","copyAsSvg":"Kopiraj v odložišče kot SVG","copyText":"Kopiraj v odložišče kot besedilo","bringForward":"Postavi naprej","sendToBack":"Pomakni v ozadje","bringToFront":"Pomakni v ospredje","sendBackward":"Pošlji nazaj","delete":"Izbriši","copyStyles":"Kopiraj slog","pasteStyles":"Prilepi slog","stroke":"Poteza","background":"Ozadje","fill":"Polnilo","strokeWidth":"Debelina poteze","strokeStyle":"Slog poteze","strokeStyle_solid":"Polna","strokeStyle_dashed":"Črtkana","strokeStyle_dotted":"Pikasta","sloppiness":"Površnost","opacity":"Prekrivnost","textAlign":"Poravnava besedila","edges":"Robovi","sharp":"Ostri","round":"Okrogli","arrowheads":"Puščice","arrowhead_none":"Brez","arrowhead_arrow":"Puščica","arrowhead_bar":"Palica","arrowhead_dot":"Pika","arrowhead_triangle":"Trikotnik","fontSize":"Velikost pisave","fontFamily":"Družina pisave","addWatermark":"Dodaj \\"Izdelano z Excalidraw\\"","handDrawn":"Ročno narisano","normal":"Običajno","code":"Koda","small":"Majhna","medium":"Srednja","large":"Velika","veryLarge":"Zelo velika","solid":"Polno","hachure":"Šrafura","zigzag":"Cikcak","crossHatch":"Križno","thin":"Tanko","bold":"Krepko","left":"Levo","center":"Sredina","right":"Desno","extraBold":"Ekstra krepko","architect":"Arhitekt","artist":"Umetnik","cartoonist":"Risar","fileTitle":"Ime datoteke","colorPicker":"Izbor barve","canvasColors":"Uporabljeno na platnu","canvasBackground":"Ozadje platna","drawingCanvas":"Platno za risanje","layers":"Plasti","actions":"Dejanja","language":"Jezik","liveCollaboration":"Sodelovanje v živo...","duplicateSelection":"Podvoji","untitled":"Neimenovana","name":"Ime","yourName":"Vaše ime","madeWithExcalidraw":"Izdelano z Excalidraw","group":"Združi izbor","ungroup":"Razdruži izbor","collaborators":"Sodelavci","showGrid":"Prikaži mrežo","addToLibrary":"Dodaj v knjižnico","removeFromLibrary":"Odstrani iz knjižnice","libraryLoadingMessage":"Nalaganje knjižnice ...","libraries":"Brskaj po knjižnicah","loadingScene":"Nalaganje scene...","align":"Poravnava","alignTop":"Poravnaj na vrh","alignBottom":"Poravnaj na dno","alignLeft":"Poravnaj levo","alignRight":"Poravnaj desno","centerVertically":"Navpično na sredini","centerHorizontally":"Vodoravno na sredini","distributeHorizontally":"Porazdeli vodoravno","distributeVertically":"Porazdeli navpično","flipHorizontal":"Obrni vodoravno","flipVertical":"Obrni navpično","viewMode":"Način ogleda","share":"Deli","showStroke":"Prikaži izbirnik barv poteze","showBackground":"Prikaži izbirnik barv ozadja","toggleTheme":"Obrni temo","personalLib":"Osebna knjižnica","excalidrawLib":"Knjižnica Excalidraw","decreaseFontSize":"Zmanjšaj velikost pisave","increaseFontSize":"Povečaj velikost pisave","unbindText":"Veži besedilo","bindText":"Veži besedilo na element","createContainerFromText":"Zavij besedilo v vsebnik","link":{"edit":"Uredi povezavo","editEmbed":"Uredi povezavo in vdelaj","create":"Ustvari povezavo","createEmbed":"Ustvari povezavo in vdelaj","label":"Povezava","labelEmbed":"Povezava in vdelovanje","empty":"Povezava ni nastavljena"},"lineEditor":{"edit":"Uredi črto","exit":"Zapri urejanje črte"},"elementLock":{"lock":"Zakleni","unlock":"Odkleni","lockAll":"Zakleni vse","unlockAll":"Odkleni vse"},"statusPublished":"Objavljeno","sidebarLock":"Obdrži stransko vrstico odprto","selectAllElementsInFrame":"Izberi vse elemente v okvirju","removeAllElementsFromFrame":"Izbriši vse elemente v okvirju","eyeDropper":"Izberi barvo s platna"},"library":{"noItems":"Dodan še ni noben element...","hint_emptyLibrary":"Izberite element na platnu, da ga dodate sem, ali namestite knjižnico iz javnega skladišča spodaj.","hint_emptyPrivateLibrary":"Izberite element na platnu, da ga dodate sem."},"buttons":{"clearReset":"Ponastavi platno","exportJSON":"Izvozi v datoteko","exportImage":"Izvozi sliko...","export":"Shrani v...","copyToClipboard":"Kopiraj v odložišče","save":"Shrani v trenutno datoteko","saveAs":"Shrani kot","load":"Odpri","getShareableLink":"Pridobi povezavo za deljenje","close":"Zapri","selectLanguage":"Izberi jezik","scrollBackToContent":"Pomakni se nazaj na vsebino","zoomIn":"Povečaj","zoomOut":"Pomanjšaj","resetZoom":"Ponastavi povečavo","menu":"Meni","done":"Končano","edit":"Uredi","undo":"Razveljavi","redo":"Ponovi","resetLibrary":"Ponastavi knjižnico","createNewRoom":"Ustvari novo sobo","fullScreen":"Celozaslonski način","darkMode":"Temni način","lightMode":"Svetli način","zenMode":"Način Zen","objectsSnapMode":"Pripenjanje na predmete","exitZenMode":"Zapri način Zen","cancel":"Prekliči","clear":"Počisti","remove":"Odstrani","embed":"Preklopi vdelavo","publishLibrary":"Objavi","submit":"Pošlji","confirm":"Potrdi","embeddableInteractionButton":"Kliknite za interakcijo"},"alerts":{"clearReset":"To bo počistilo celotno platno. Ali ste prepričani?","couldNotCreateShareableLink":"Povezave za deljenje ni bilo mogoče ustvariti.","couldNotCreateShareableLinkTooBig":"Povezave za deljenje ni bilo mogoče ustvariti: scena je prevelika","couldNotLoadInvalidFile":"Neveljavne datoteke ni bilo mogoče naložiti","importBackendFailed":"Uvoz iz zaledja ni uspel.","cannotExportEmptyCanvas":"Izvoz prazne scene ni mogoč.","couldNotCopyToClipboard":"Kopiranje v odložišče ni uspelo.","decryptFailed":"Dešifriranje podatkov ni uspelo.","uploadedSecurly":"Nalaganje je bilo zaščiteno s šifriranjem od konca do konca, kar pomeni, da strežnik Excalidraw in tretje osebe ne morejo brati vsebine.","loadSceneOverridePrompt":"Nalaganje zunanje risbe bo nadomestilo vašo obstoječo vsebino. Ali želite nadaljevati?","collabStopOverridePrompt":"Ustavitev seje bo prepisala vašo prejšnjo, lokalno shranjeno risbo. Ali ste prepričani?\\n\\n(Če želite obdržati lokalno risbo, preprosto zaprite zavihek brskalnika.)","errorAddingToLibrary":"Elementa ni bilo mogoče dodati v knjižnico","errorRemovingFromLibrary":"Elementa ni bilo mogoče izbrisati iz knjižnice","confirmAddLibrary":"S tem boste v vašo knjižnico dodali oblike ({{numShapes}}). Ali ste prepričani?","imageDoesNotContainScene":"Zdi se, da ta slika ne vsebuje podatkov o sceni. Ali ste med izvozom omogočili vdelavo scene?","cannotRestoreFromImage":"Scene ni bilo mogoče obnoviti iz te slikovne datoteke","invalidSceneUrl":"S priloženega URL-ja ni bilo mogoče uvoziti scene. Je napačno oblikovana ali pa ne vsebuje veljavnih podatkov Excalidraw JSON.","resetLibrary":"To bo počistilo vašo knjižnico. Ali ste prepričani?","removeItemsFromsLibrary":"Izbriši elemente ({{count}}) iz knjižnice?","invalidEncryptionKey":"Ključ za šifriranje mora vsebovati 22 znakov. Sodelovanje v živo je onemogočeno.","collabOfflineWarning":"Internetna povezava ni na voljo.\\nVaše spremembe ne bodo shranjene!"},"errors":{"unsupportedFileType":"Nepodprt tip datoteke.","imageInsertError":"Vstavljanje slike ni bilo uspešno. Poskusite ponovno kasneje...","fileTooBig":"Datoteka je prevelika. Največja dovoljena velikost je {{maxSize}}.","svgImageInsertError":"Vstavljanje slike SVG ni uspelo. Oznake SVG so videti neveljavne.","failedToFetchImage":"Pridobivanje slike ni uspelo.","invalidSVGString":"Neveljaven SVG.","cannotResolveCollabServer":"Povezave s strežnikom za sodelovanje ni bilo mogoče vzpostaviti. Ponovno naložite stran in poskusite znova.","importLibraryError":"Nalaganje knjižnice ni uspelo","collabSaveFailed":"Ni bilo mogoče shraniti v zaledno bazo podatkov. Če se težave nadaljujejo, shranite datoteko lokalno, da ne boste izgubili svojega dela.","collabSaveFailed_sizeExceeded":"Ni bilo mogoče shraniti v zaledno bazo podatkov, zdi se, da je platno preveliko. Datoteko shranite lokalno, da ne izgubite svojega dela.","brave_measure_text_error":{"line1":"Videti je, da uporabljate brskalnik Brave z omogočeno nastavitvijo Agresivno blokiranje prstnih odtisov.","line2":"To bi lahko povzročilo motnje v obnašanju besedilnih elementov v vaših risbah.","line3":"Močno priporočamo, da onemogočite to nastavitev. Sledite tem korakom, kako to storiti.","line4":"Če onemogočanje te nastavitve ne popravi prikaza besedilnih elementov, odprite vprašanje na našem GitHubu ali nam pišite na Discord"},"libraryElementTypeError":{"embeddable":"Vdelani elementi ne morejo biti dodani v knjižnico.","image":"Podpora za dodajanje slik v knjižnico prihaja kmalu!"}},"toolBar":{"selection":"Izbor","image":"Vstavi sliko","rectangle":"Pravokotnik","diamond":"Diamant","ellipse":"Elipsa","arrow":"Puščica","line":"Črta","freedraw":"Risanje","text":"Besedilo","library":"Knjižnica","lock":"Ohrani izbrano orodje aktivno po risanju","penMode":"Način peresa - prepreči dotik","link":"Dodaj/posodobi povezavo za izbrano obliko","eraser":"Radirka","frame":"Okvir","embeddable":"Spletna vdelava","laser":"Laserski kazalec","hand":"Roka (orodje za premikanje)","extraTools":"Več orodij"},"headings":{"canvasActions":"Dejanja za platno","selectedShapeActions":"Dejanja za izbrane oblike","shapes":"Oblike"},"hints":{"canvasPanning":"Za premikanje platna med vlečenjem držite kolesce miške ali preslednico ali uporabite orodje roka","linearElement":"Kliknite za začetek več točk, povlecite za posamezno črto","freeDraw":"Kliknite in povlecite, spustite, ko končate","text":"Namig: besedilo lahko dodate tudi z dvoklikom kjer koli z orodjem za izbiro","embeddable":"Kliknite in povlecite, da ustvarite spletno vdelavo","text_selected":"Dvokliknite ali pritisnite tipko Enter, da uredite besedilo","text_editing":"Pritisnite tipko Escape ali CtrlOrCmd+Enter za zaključek urejanja","linearElementMulti":"Kliknite zadnjo točko ali pritisnite Escape ali Enter, da končate","lockAngle":"Kot lahko omejite tako, da držite tipko Shift","resize":"Razmerja lahko omejite tako, da držite tipko Shift med spreminjanjem velikosti. Držite tipko Alt, da spremenite velikost od središča","resizeImage":"Velikost lahko prosto spreminjate tako, da držite tipko Shift. Držite tipko Alt, da spremenite velikost od središča","rotate":"Kote lahko omejite tako, da med vrtenjem držite tipko Shift","lineEditor_info":"Držite CtrlOrCmd in dvokliknite ali pritisnite CtrlOrCmd + Enter za urejanje točk","lineEditor_pointSelected":"Pritisnite tipko Delete, da odstranite točko(e), CtrlOrCmd+D za podvojitev ali povlecite za premikanje","lineEditor_nothingSelected":"Izberite točko za urejanje (pridržite tipko Shift za izbiro več točk), ali držite tipko Alt in kliknite za dodajanje novih točk","placeImage":"Kliknite, da postavite sliko, ali kliknite in povlecite, da ročno nastavite njeno velikost","publishLibrary":"Objavi svojo knjižnico","bindTextToElement":"Pritisnite tipko Enter za dodajanje besedila","deepBoxSelect":"Držite tipko CtrlOrCmd za globoko izbiro in preprečitev vlečenja","eraserRevert":"Pridržite tipko Alt, da razveljavite elemente, označene za brisanje","firefox_clipboard_write":"To funkcijo lahko verjetno omogočite z nastavitvijo zastavice \\"dom.events.asyncClipboard.clipboardItem\\" na \\"true\\". Če želite spremeniti zastavice brskalnika v Firefoxu, obiščite stran \\"about:config\\".","disableSnapping":"Držite CtrlOrCmd, da onemogočite pripenjanje"},"canvasError":{"cannotShowPreview":"Predogleda ni bilo mogoče prikazati","canvasTooBig":"Morda je platno preveliko.","canvasTooBigTip":"Nasvet: poskusite premakniti najbolj oddaljene elemente nekoliko bližje skupaj."},"errorSplash":{"headingMain":"Prišlo je do napake. Poskusite ","clearCanvasMessage":"Če ponovno nalaganje ne deluje, poskusite ","clearCanvasCaveat":" To bo povzročilo izgubo dela ","trackedToSentry":"Napaka z identifikatorjem {{eventId}} smo zabeležili v naš sistem.","openIssueMessage":"Zelo smo bili previdni, da v podatke o napaki nismo vključili vaših podatkov o sceni. Če vaša scena ni zasebna, vas prosimo, da napišete več podrobnosti na našem Prosimo, vključite spodnje informacije tako, da jih kopirate in prilepite v GitHub vprašanje.","sceneContent":"Vsebina scene:"},"roomDialog":{"desc_intro":"Na vašo trenutno sceno lahko povabite osebe, ki bodo sodelovale z vami.","desc_privacy":"Brez skrbi. Seja uporablja šifriranje od konca do konca, tako da bo vse, kar narišete, ostalo zasebno. Niti naš strežnik ne bo mogel videti, kaj si izmislite.","button_startSession":"Začni sejo","button_stopSession":"Ustavi sejo","desc_inProgressIntro":"Seja sodelovanja v živo je v teku.","desc_shareLink":"Delite to povezavo z vsemi, s katerimi želite sodelovati:","desc_exitSession":"Ustavitev seje vas bo odklopila od sobe, vendar boste lahko lokalno nadaljevali delo s sceno. To pa ne bo vplivalo na druge osebe. Druge osebe bodo še vedno lahko sodelovale v svoji različici.","shareTitle":"Pridruži se seji sodelovanja v živo na Excalidraw"},"errorDialog":{"title":"Napaka"},"exportDialog":{"disk_title":"Shrani na disk","disk_details":"Izvozite podatke scene v datoteko, iz katere jo lahko pozneje uvozite.","disk_button":"Shrani v datoteko","link_title":"Povezava za deljenje","link_details":"Izvoz kot povezava samo za branje.","link_button":"Izvoz kot povezava","excalidrawplus_description":"Shrani sceno v svoj delovni prostor Excalidraw+.","excalidrawplus_button":"Izvoz","excalidrawplus_exportError":"Trenutno ni bilo mogoče izvoziti v Excalidraw+..."},"helpDialog":{"blog":"Preberite naš blog","click":"klik","deepSelect":"Globoka izbira","deepBoxSelect":"Globoka izbira znotraj polja in preprečitev vlečenja","curvedArrow":"Ukrivljena puščica","curvedLine":"Ukrivljena črta","documentation":"Dokumentacija","doubleClick":"dvojni klik","drag":"vleci","editor":"Urejevalnik","editLineArrowPoints":"Uredi črto/točke puščice","editText":"Uredi besedilo / dodaj oznako","github":"Ste našli težavo? Pošljite","howto":"Sledite našim vodičem","or":"ali","preventBinding":"Prepreči vezanje puščice","tools":"Orodja","shortcuts":"Bližnjice na tipkovnici","textFinish":"Zaključi urejanje (urejevalnik besedila)","textNewLine":"Dodaj novo vrstico (urejevalnik besedila)","title":"Pomoč","view":"Pogled","zoomToFit":"Približaj na vse elemente","zoomToSelection":"Približaj na izbor","toggleElementLock":"Zakleni/odkleni izbor","movePageUpDown":"Premakni stran gor/dol","movePageLeftRight":"Premakni stran levo/desno"},"clearCanvasDialog":{"title":"Počisti platno"},"publishDialog":{"title":"Objavi knjižnico","itemName":"Ime elementa","authorName":"Ime avtorja","githubUsername":"GitHub uporabniško ime","twitterUsername":"Twitter uporabniško ime","libraryName":"Ime knjižnice","libraryDesc":"Opis knijžnice","website":"Spletna stran","placeholder":{"authorName":"Vaše ime ali uporabniško ime","libraryName":"Ime vaše knjižnice","libraryDesc":"Opis vaše knjižnice, da bodo ljudje lažje razumeli njeno uporabo","githubHandle":"GitHub uporabniško ime (neobvezno), tako da lahko urejate knjižnico potem, ko jo pošljete v pregled","twitterHandle":"Twitter uporabniško ime (neobvezno), tako da vemo, koga omeniti pri promociji prek Twitterja","website":"Povezava na vašo osebno spletno stran ali drugam (neobvezno)"},"errors":{"required":"Obvezno","website":"Vnesite veljaven URL"},"noteDescription":"Predložite svojo knjižnico, da bo vključena v javno skladišče knjižnic,da jih drugi lahko uporabljajo v svojih risbah.","noteGuidelines":"Knjižnica mora biti najprej ročno odobrena. Prosimo vas, da pred oddajanjem preberete naše smernice.Za komunikacijo in spreminjanje po potrebi boste potrebovali račun GitHub, vendar to ni obvezno.","noteLicense":"Z oddajo se strinjate, da bo knjižnica objavljena pod licenco MIT, kar na kratko pomeni, da jo lahko kdorkoli uporablja brez omejitev.","noteItems":"Vsak element knjižnice mora imeti svoje ime, tako da ga je mogoče filtrirati. Vključeni bodo naslednji elementi knjižnice:","atleastOneLibItem":"Za začetek izberite vsaj en element knjižnice","republishWarning":"Opomba: nekateri izbrani predmeti so označeni kot že objavljeni/oddani. Elemente lahko znova oddate samo, ko posodabljate obstoječo knjižnico ali oddajo."},"publishSuccessDialog":{"title":"Knjižnica oddana","content":"{{authorName}}, hvala. Vaša knjižnica je bila poslana v pregled. Stanje lahko spremljatetukaj"},"confirmDialog":{"resetLibrary":"Ponastavi knjižnico","removeItemsFromLib":"Odstran izbrane elemente iz knjižnice"},"imageExportDialog":{"header":"Izvozi sliko","label":{"withBackground":"Ozadje","onlySelected":"Samo izbor","darkMode":"Temni način","embedScene":"Vdelaj sceno","scale":"Povečava","padding":"Odmik"},"tooltip":{"embedScene":"Podatki o sceni bodo shranjeni v izvoženo datoteko PNG/SVG, tako da bo sceno mogoče obnoviti iz nje.\\nTo bo povečalo velikost izvožene datoteke."},"title":{"exportToPng":"Izvozi v PNG","exportToSvg":"Izvozi v SVG","copyPngToClipboard":"Kopiraj PNG v odložišče"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Kopiraj v odložišče"}},"encrypted":{"tooltip":"Vaše risbe so šifrirane od konca do konca, tako da jih strežniki Excalidraw nikoli ne bodo videli.","link":"Blog objava o šifriranju od konca do konca v Excalidraw"},"stats":{"angle":"Kot","element":"Element","elements":"Elementi","height":"Višina","scene":"Scena","selected":"Izbrano","storage":"Shramba","title":"Statistika za napredne uporabnike","total":"Skupaj","version":"Različica","versionCopy":"Kliknite za kopiranje","versionNotAvailable":"Različica ni na voljo","width":"Širina"},"toast":{"addedToLibrary":"Dodano v knjižnico","copyStyles":"Slogi kopirani.","copyToClipboard":"Kopirano v odložišče.","copyToClipboardAsPng":"Kopirano v odložišče kot PNG ({{exportSelection}}, {{exportColorScheme}})","fileSaved":"Datoteka shranjena.","fileSavedToFilename":"Shranjeno v {filename}","canvas":"platno","selection":"izbor","pasteAsSingleElement":"Uporabite {{shortcut}}, da prilepite kot en element,\\n ali prilepite v obstoječ urejevalnik besedil","unableToEmbed":"Vdelava tega URL-ja trenutno ni dovoljena. Ustvarite vprašanje na GitHub-u in prosite za vmestitev URL-ja na seznam dovoljenih","unrecognizedLinkFormat":"Povezava, ki ste jo vdelali, se ne ujema s pričakovano obliko. Poskusite prilepiti niz za vdelavo, ki ste ga prejeli na izvorni strani"},"colors":{"transparent":"Prosojno","black":"Črna","white":"Bela","red":"Rdeča","pink":"Roza","grape":"Grozdje","violet":"Vijolična","gray":"Siva","blue":"Modra","cyan":"Cijan","teal":"Turkizna","green":"Zelena","yellow":"Rumena","orange":"Oranžna","bronze":"Bronasta"},"welcomeScreen":{"app":{"center_heading":"Vsi vaši podatki so shranjeni lokalno v vašem brskalniku.","center_heading_plus":"Ste namesto tega želeli odpreti Excalidraw+?","menuHint":"Izvoz, nastavitve, jeziki, ..."},"defaults":{"menuHint":"Izvoz, nastavitve in več ...","center_heading":"Diagrami. Enostavno.","toolbarHint":"Izberi orodje in začni z risanjem!","helpHint":"Bližnjice in pomoč"}},"colorPicker":{"mostUsedCustomColors":"Najpogosteje uporabljene barve po meri","colors":"Barve","shades":"Odtenki","hexCode":"Hex koda","noShades":"Odtenki za to barvo niso na voljo"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Izvozi kot sliko","button":"Izvozi kot sliko","description":"Izvozite podatke scene kot sliko, iz katere jo lahko pozneje uvozite."},"saveToDisk":{"title":"Shrani na disk","button":"Shrani na disk","description":"Izvozite podatke scene v datoteko, iz katere jo lahko pozneje uvozite."},"excalidrawPlus":{"title":"Excalidraw+","button":"Izvozi v Excalidraw+","description":"Shrani sceno v svoj delovni prostor Excalidraw+."}},"modal":{"loadFromFile":{"title":"Naloži iz datoteke","button":"Naloži iz datoteke","description":"Nalaganje iz datoteke bo prepisalo vašo obstoječo vsebino. Svojo risbo lahko najprej varnostno kopirate z eno od spodnjih možnosti."},"shareableLink":{"title":"Naloži iz povezave","button":"Zamenjaj mojo vsebino","description":"Nalaganje zunanje risbe bo prepisalo vašo obstoječo vsebino. Svojo risbo lahko najprej varnostno kopirate z eno od spodnjih možnosti."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/sv-SE-json-2f362899d3ac4089534f.js b/public/excalidraw/excalidraw-assets-dev/locales/sv-SE-json-2f362899d3ac4089534f.js
new file mode 100644
index 0000000..c5f2548
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/sv-SE-json-2f362899d3ac4089534f.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/sv-SE-json"],{
+
+/***/ "../../locales/sv-SE.json":
+/*!********************************!*\
+ !*** ../../locales/sv-SE.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Klistra in","pasteAsPlaintext":"Klistra som oformaterad text","pasteCharts":"Klistra in diagram","selectAll":"Markera alla","multiSelect":"Lägg till element till markering","moveCanvas":"Flytta canvas","cut":"Klipp ut","copy":"Kopiera","copyAsPng":"Kopiera till urklipp som PNG","copyAsSvg":"Kopiera till urklipp som SVG","copyText":"Kopiera till urklipp som text","bringForward":"Flytta framåt","sendToBack":"Flytta underst","bringToFront":"Flytta främst","sendBackward":"Skicka bakåt","delete":"Ta bort","copyStyles":"Kopiera stil","pasteStyles":"Klistra in stil","stroke":"Linje","background":"Bakgrund","fill":"Fyllnad","strokeWidth":"Linjebredd","strokeStyle":"Linjestil","strokeStyle_solid":"Solid","strokeStyle_dashed":"Streckad","strokeStyle_dotted":"Punktad","sloppiness":"Slarvighet","opacity":"Genomskinlighet","textAlign":"Textjustering","edges":"Kanter","sharp":"Skarp","round":"Rund","arrowheads":"Pilhuvuden","arrowhead_none":"Inga","arrowhead_arrow":"Pil","arrowhead_bar":"Stolpe","arrowhead_dot":"Punkt","arrowhead_triangle":"Triangel","fontSize":"Teckenstorlek","fontFamily":"Teckensnitt","addWatermark":"Lägg till \\"Skapad med Excalidraw\\"","handDrawn":"Handritad","normal":"Normal","code":"Kod","small":"Liten","medium":"Medium","large":"Stor","veryLarge":"Mycket stor","solid":"Solid","hachure":"Skraffering","zigzag":"Sicksack","crossHatch":"Skraffera med kors","thin":"Tunn","bold":"Fet","left":"Vänster","center":"Centrera","right":"Höger","extraBold":"Extra fet","architect":"Arkitekt","artist":"Artist","cartoonist":"Serietecknare","fileTitle":"Filnamn","colorPicker":"Färgväljare","canvasColors":"Används på canvas","canvasBackground":"Canvas-bakgrund","drawingCanvas":"Ritar canvas","layers":"Lager","actions":"Åtgärder","language":"Språk","liveCollaboration":"Samarbeta live...","duplicateSelection":"Duplicera","untitled":"Namnlös","name":"Namn","yourName":"Ditt namn","madeWithExcalidraw":"Skapad med Excalidraw","group":"Gruppera markering","ungroup":"Avgruppera markering","collaborators":"Medarbetare","showGrid":"Visa rutnät","addToLibrary":"Lägg till i biblioteket","removeFromLibrary":"Ta bort från bibliotek","libraryLoadingMessage":"Laddar bibliotek…","libraries":"Bläddra i bibliotek","loadingScene":"Laddar skiss…","align":"Justera","alignTop":"Justera överkant","alignBottom":"Justera underkant","alignLeft":"Justera vänster","alignRight":"Justera höger","centerVertically":"Centrera vertikalt","centerHorizontally":"Centrera horisontellt","distributeHorizontally":"Fördela horisontellt","distributeVertically":"Fördela vertikalt","flipHorizontal":"Vänd horisontellt","flipVertical":"Vänd vertikalt","viewMode":"Visningsläge","share":"Dela","showStroke":"Visa färgväljare för linjefärg","showBackground":"Visa färgväljare för bakgrundsfärg","toggleTheme":"Växla tema","personalLib":"Personligt bibliotek","excalidrawLib":"Excalidraw bibliotek","decreaseFontSize":"Minska fontstorleken","increaseFontSize":"Öka fontstorleken","unbindText":"Koppla bort text","bindText":"Bind texten till behållaren","createContainerFromText":"Radbryt text i en avgränsad yta","link":{"edit":"Redigera länk","editEmbed":"Redigera länk & bädda in","create":"Skapa länk","createEmbed":"Skapa länk & bädda in","label":"Länk","labelEmbed":"Länka & bädda in","empty":"Ingen länk är angiven"},"lineEditor":{"edit":"Redigera linje","exit":"Avsluta linjeredigerare"},"elementLock":{"lock":"Lås","unlock":"Lås upp","lockAll":"Lås alla","unlockAll":"Lås upp alla"},"statusPublished":"Publicerad","sidebarLock":"Håll sidofältet öppet","selectAllElementsInFrame":"Markera alla element i rutan","removeAllElementsFromFrame":"Ta bort alla element från rutan","eyeDropper":"Välj färg från canvas"},"library":{"noItems":"Inga objekt tillagda ännu...","hint_emptyLibrary":"Välj ett objekt på canvasen för att lägga till det här, eller installera ett bibliotek från det publika arkivet, nedan.","hint_emptyPrivateLibrary":"Välj ett objekt på canvasen för att lägga till det här."},"buttons":{"clearReset":"Återställ canvasen","exportJSON":"Exportera till fil","exportImage":"Exportera bild...","export":"Spara till...","copyToClipboard":"Kopiera till urklipp","save":"Spara till aktuell fil","saveAs":"Spara som","load":"Öppna","getShareableLink":"Hämta delbar länk","close":"Stäng","selectLanguage":"Välj språk","scrollBackToContent":"Bläddra tillbaka till innehållet","zoomIn":"Zooma in","zoomOut":"Zooma ut","resetZoom":"Återställ zoom","menu":"Meny","done":"Klart","edit":"Redigera","undo":"Ångra","redo":"Gör om","resetLibrary":"Återställ bibliotek","createNewRoom":"Skapa ett nytt rum","fullScreen":"Helskärm","darkMode":"Mörkt läge","lightMode":"Ljust läge","zenMode":"Zen-läge","objectsSnapMode":"Fäst mot objekt","exitZenMode":"Gå ur zen-läge","cancel":"Avbryt","clear":"Rensa","remove":"Ta bort","embed":"Växla inbäddning","publishLibrary":"Publicera","submit":"Skicka","confirm":"Bekräfta","embeddableInteractionButton":"Klicka för att interagera"},"alerts":{"clearReset":"Detta rensar hela canvasen. Är du säker?","couldNotCreateShareableLink":"Kunde inte skapa delbar länk.","couldNotCreateShareableLinkTooBig":"Kunde inte skapa delbar länk: skissen är för stor","couldNotLoadInvalidFile":"Kunde inte ladda ogiltig fil","importBackendFailed":"Importering från backend misslyckades.","cannotExportEmptyCanvas":"Kan inte exportera tom canvas.","couldNotCopyToClipboard":"Kunde inte kopiera till urklipp.","decryptFailed":"Kunde inte avkryptera data.","uploadedSecurly":"Uppladdning har säkrats med kryptering från ände till ände. vilket innebär att Excalidraw server och tredje part inte kan läsa innehållet.","loadSceneOverridePrompt":"Laddning av extern skiss kommer att ersätta ditt befintliga innehåll. Vill du fortsätta?","collabStopOverridePrompt":"Att stoppa sessionen kommer att skriva över din föregående, lokalt lagrade skiss. Är du säker?\\n\\n(Om du vill behålla din lokala skiss, stäng bara webbläsarfliken istället.)","errorAddingToLibrary":"Kunde inte lägga till objekt i biblioteket","errorRemovingFromLibrary":"Kunde inte ta bort objekt från biblioteket","confirmAddLibrary":"Detta kommer att lägga till {{numShapes}} form(er) till ditt bibliotek. Är du säker?","imageDoesNotContainScene":"Den här bilden verkar inte innehålla någon skissdata. Har du aktiverat inbäddning av skiss under export?","cannotRestoreFromImage":"Skiss kunde inte återställas från denna bildfil","invalidSceneUrl":"Det gick inte att importera skiss från den angivna webbadressen. Antingen har den fel format, eller så innehåller den ingen giltig Excalidraw JSON data.","resetLibrary":"Detta kommer att rensa ditt bibliotek. Är du säker?","removeItemsFromsLibrary":"Ta bort {{count}} objekt från biblioteket?","invalidEncryptionKey":"Krypteringsnyckeln måste vara 22 tecken. Livesamarbetet är inaktiverat.","collabOfflineWarning":"Ingen internetanslutning tillgänglig.\\nDina ändringar kommer inte att sparas!"},"errors":{"unsupportedFileType":"Filtypen stöds inte.","imageInsertError":"Kunde inte infoga bild. Försök igen senare...","fileTooBig":"Filen är för stor. Maximal tillåten storlek är {{maxSize}}.","svgImageInsertError":"Kunde inte infoga SVG-bild. SVG-koden ser ogiltig ut.","failedToFetchImage":"Kunde inte hämta bilden.","invalidSVGString":"Ogiltig SVG.","cannotResolveCollabServer":"Det gick inte att ansluta till samarbets-servern. Ladda om sidan och försök igen.","importLibraryError":"Kunde inte ladda bibliotek","collabSaveFailed":"Det gick inte att spara i backend-databasen. Om problemen kvarstår bör du spara filen lokalt för att se till att du inte förlorar ditt arbete.","collabSaveFailed_sizeExceeded":"Det gick inte att spara till backend-databasen, whiteboarden verkar vara för stor. Du bör spara filen lokalt för att du inte ska förlora ditt arbete.","brave_measure_text_error":{"line1":"Det ser ut som om du använder Brave-webbläsaren med Aggressivt Blockera fingeravtryck inställningen aktiverad.","line2":"Detta kan resultera i trasiga Textelement i dina ritningar.","line3":"Vi rekommenderar starkt att du inaktiverar den här inställningen. Du kan följa dessa steg för att inaktivera den.","line4":"Om inaktivering av denna inställning inte åtgärdar visningen av textelement, öppna ett ärende på vår GitHub, eller skriv till oss på Discord"},"libraryElementTypeError":{"embeddable":"Inbäddbara element kan inte läggas till i biblioteket.","image":"Stöd för att lägga till bilder till biblioteket kommer snart!"}},"toolBar":{"selection":"Markering","image":"Infoga bild","rectangle":"Rektangel","diamond":"Diamant","ellipse":"Ellips","arrow":"Pil","line":"Linje","freedraw":"Rita","text":"Text","library":"Bibliotek","lock":"Håll valt verktyg aktivt efter ritande","penMode":"Pennläge - förhindra touch","link":"Lägg till / Uppdatera länk för en vald form","eraser":"Radergummi","frame":"Rutverktyg","embeddable":"Bädda in (web)","laser":"Laserpekare","hand":"Hand (panoreringsverktyg)","extraTools":"Fler verktyg"},"headings":{"canvasActions":"Canvas-åtgärder","selectedShapeActions":"Valda formåtgärder","shapes":"Former"},"hints":{"canvasPanning":"För att flytta whiteboarden, håll mushjulet eller mellanslagstangenten medan du drar eller använd handverktyget","linearElement":"Klicka för att starta flera punkter, dra för en linje","freeDraw":"Klicka och dra, släpp när du är klar","text":"Tips: du kan också lägga till text genom att dubbelklicka var som helst med markeringsverktyget","embeddable":"Klicka-dra för att skapa en webbplats-inbäddning","text_selected":"Dubbelklicka eller tryck ENTER för att redigera text","text_editing":"Tryck Escape eller CtrlOrCmd + ENTER för att slutföra redigeringen","linearElementMulti":"Klicka på sista punkten eller tryck Escape eller Enter för att avsluta","lockAngle":"Du kan begränsa vinkeln genom att hålla SKIFT","resize":"Du kan behålla proportioner genom att hålla SHIFT medan du ändrar storlek,\\nhåller du ALT ändras storlek relativt mitten","resizeImage":"Du kan ändra storlek fritt genom att hålla SHIFT,\\nhåll ALT för att ändra storlek från mitten","rotate":"Du kan begränsa vinklar genom att hålla SHIFT medan du roterar","lineEditor_info":"Håll Ctrl/Cmd och dubbelklicka eller tryck på Ctrl/Cmd + Enter för att redigera punkter","lineEditor_pointSelected":"Tryck på Ta bort för att ta bort punkt(er), Ctrl + D eller Cmd + D för att duplicera, eller dra för att flytta","lineEditor_nothingSelected":"Välj en punkt att redigera (håll SHIFT för att välja flera),\\neller håll ned Alt och klicka för att lägga till nya punkter","placeImage":"Klicka för att placera bilden, eller klicka och dra för att ställa in dess storlek manuellt","publishLibrary":"Publicera ditt eget bibliotek","bindTextToElement":"Tryck på Enter för att lägga till text","deepBoxSelect":"Håll Ctrl eller Cmd för att djupvälja, och för att förhindra att dra","eraserRevert":"Håll Alt för att återställa de element som är markerade för borttagning","firefox_clipboard_write":"Denna funktion kan sannolikt aktiveras genom att ställa in \\"dom.events.asyncClipboard.clipboardItem\\" flaggan till \\"true\\". För att ändra webbläsarens flaggor i Firefox, besök \\"about:config\\" sidan.","disableSnapping":"Håll Ctrl eller Cmd för att inaktivera fästning"},"canvasError":{"cannotShowPreview":"Kan inte visa förhandsgranskning","canvasTooBig":"Canvasen kan vara för stor.","canvasTooBigTip":"Tips: prova att flytta de mest avlägsna elementen lite närmare varandra."},"errorSplash":{"headingMain":"Ett fel uppstod. Försök ","clearCanvasMessage":"Om omladdning inte fungerar, försök ","clearCanvasCaveat":" Detta kommer att leda till förlust av arbete ","trackedToSentry":"Felet med identifieraren {{eventId}} spårades på vårt system.","openIssueMessage":"Vi var mycket försiktiga med att inte inkludera din skissinformation om felet. Om din skiss inte är privat, vänligen överväga att följa upp på vår Vänligen inkludera information nedan genom att kopiera och klistra in i GitHub-problemet.","sceneContent":"Skissinnehåll:"},"roomDialog":{"desc_intro":"Du kan bjuda in personer till din nuvarande skiss för att samarbeta med dig.","desc_privacy":"Oroa dig inte, sessionen använder kryptering från ände till ände, så vad du än ritar kommer att förbli privat. Inte ens vår server kommer att kunna se vad du skissar.","button_startSession":"Starta sessionen","button_stopSession":"Stoppa session","desc_inProgressIntro":"Nu pågår en live-samarbetssession.","desc_shareLink":"Dela denna länk med någon du vill samarbeta med:","desc_exitSession":"Att avbryta sessionen kommer att koppla bort dig från rummet, men du kommer att kunna fortsätta arbeta med skissen, lokalt. Observera att detta inte påverkar andra människor, och de kommer fortfarande att kunna samarbeta på deras version.","shareTitle":"Delta i en live-samarbetssession på Excalidraw"},"errorDialog":{"title":"Fel"},"exportDialog":{"disk_title":"Spara till disk","disk_details":"Exportera skissdata till en fil som du kan importera från senare.","disk_button":"Spara till fil","link_title":"Delbar länk","link_details":"Exportera som en skrivskyddad länk.","link_button":"Exportera till länk","excalidrawplus_description":"Spara skissen till din Excalidraw+ arbetsyta.","excalidrawplus_button":"Exportera","excalidrawplus_exportError":"Det gick inte att exportera till Excalidraw+ just nu..."},"helpDialog":{"blog":"Läs vår blogg","click":"klicka","deepSelect":"Djupval","deepBoxSelect":"Djupval inom boxen, och förhindra att dra","curvedArrow":"Böjd pil","curvedLine":"Böjd linje","documentation":"Dokumentation","doubleClick":"dubbelklicka","drag":"dra","editor":"Redigerare","editLineArrowPoints":"Redigera linje-/pilpunkter","editText":"Redigera text / lägg till etikett","github":"Hittat ett problem? Rapportera","howto":"Följ våra guider","or":"eller","preventBinding":"Förhindra pilbindning","tools":"Verktyg","shortcuts":"Tangentbordsgenvägar","textFinish":"Slutför redigering (text)","textNewLine":"Lägg till ny rad (text)","title":"Hjälp","view":"Visa","zoomToFit":"Zooma för att rymma alla element","zoomToSelection":"Zooma till markering","toggleElementLock":"Lås/Lås upp valda","movePageUpDown":"Flytta sida upp/ner","movePageLeftRight":"Flytta sida vänster/höger"},"clearCanvasDialog":{"title":"Rensa canvas"},"publishDialog":{"title":"Publicera bibliotek","itemName":"Objektnamn","authorName":"Upphovsmannens namn","githubUsername":"GitHub-användarnamn","twitterUsername":"Twitter-användarnamn","libraryName":"Biblioteksnamn","libraryDesc":"Biblioteksbeskrivning","website":"Webbplats","placeholder":{"authorName":"Ditt namn eller användarnamn","libraryName":"Namn på ditt bibliotek","libraryDesc":"Beskrivning av ditt bibliotek för att hjälpa människor att förstå dess användning","githubHandle":"Github-användarnamn (valfritt), så att du kan redigera biblioteket när du har skickat in det för granskning","twitterHandle":"Twitter-användarnamn (valfritt), så vi vet vem att kreditera när du marknadsför på Twitter","website":"Länk till din personliga webbplats eller någon annan (valfritt)"},"errors":{"required":"Obligatoriskt","website":"Ange en giltig URL"},"noteDescription":"Skicka ditt bibliotek för att inkluderas i det offentliga bibliotekets arkivför andra människor att använda i sina skisser.","noteGuidelines":"Biblioteket måste godkännas manuellt först. Vänligen läs riktlinjerna innan du skickar in. Du behöver ett GitHub-konto för att kommunicera och göra ändringar om så önskas, men det krävs inte.","noteLicense":"Genom att skicka in godkänner du att biblioteket kommer att publiceras under MIT-licens, vilket kort sagt betyder att vem som helst kan använda det utan restriktioner.","noteItems":"Varje objekt måste ha sitt eget namn så att det är filtrerbart. Följande objekt kommer att inkluderas:","atleastOneLibItem":"Välj minst ett biblioteksobjekt för att komma igång","republishWarning":"Obs: några av de markerade objekten är redan markerade som publicerade/skickade. Du bör endast skicka objekt igen när du uppdaterar ett befintligt bibliotek eller inlämning."},"publishSuccessDialog":{"title":"Bibliotek inskickat","content":"Tack {{authorName}}. Ditt bibliotek har skickats för granskning. Du kan följa statushär"},"confirmDialog":{"resetLibrary":"Återställ bibliotek","removeItemsFromLib":"Ta bort markerade objekt från biblioteket"},"imageExportDialog":{"header":"Exportera bild","label":{"withBackground":"Bakgrund","onlySelected":"Endast markerade","darkMode":"Mörkt läge","embedScene":"Bädda in skiss","scale":"Skala","padding":"Utfyllnad"},"tooltip":{"embedScene":"Skissdata kommer att sparas i den exporterade PNG/SVG-filen så att skissen kan återställas från den.\\nKommer att öka exporterad filstorlek."},"title":{"exportToPng":"Exportera till PNG","exportToSvg":"Exportera till SVG","copyPngToClipboard":"Kopiera PNG till urklipp"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Kopiera till urklipp"}},"encrypted":{"tooltip":"Dina skisser är krypterade från ände till ände så Excalidraws servrar kommer aldrig att se dem.","link":"Blogginlägg om kryptering från ände till ände i Excalidraw"},"stats":{"angle":"Vinkel","element":"Element","elements":"Element","height":"Höjd","scene":"Skiss","selected":"Valda","storage":"Lagring","title":"Statistik för nördar","total":"Totalt","version":"Version","versionCopy":"Klicka för att kopiera","versionNotAvailable":"Versionen är inte tillgänglig","width":"Bredd"},"toast":{"addedToLibrary":"Tillagd i biblioteket","copyStyles":"Kopierade stilar.","copyToClipboard":"Kopierad till urklipp.","copyToClipboardAsPng":"Kopierade {{exportSelection}} till urklipp som PNG\\n({{exportColorScheme}})","fileSaved":"Fil sparad.","fileSavedToFilename":"Sparad till {filename}","canvas":"canvas","selection":"markering","pasteAsSingleElement":"Använd {{shortcut}} för att klistra in som ett enda element,\\neller klistra in i en befintlig textredigerare","unableToEmbed":"Att bädda in denna webbadress är för närvarande inte tillåtet. Skapa en problemrapport på GitHub för att begära att webbadressen vitlistas.","unrecognizedLinkFormat":"Länken du bäddade in matchar inte det förväntade formatet. Försök klistra in \'embed\'-strängen som tillhandahålls av källwebbplatsen"},"colors":{"transparent":"Genomskinlig","black":"Svart","white":"Vit","red":"Röd","pink":"Rosa","grape":"Lila","violet":"Violett","gray":"Grå","blue":"Blå","cyan":"Turkos","teal":"Blågrön","green":"Grön","yellow":"Gul","orange":"Orange","bronze":"Brons"},"welcomeScreen":{"app":{"center_heading":"All data sparas lokalt i din webbläsare.","center_heading_plus":"Ville du gå till Excalidraw+ istället?","menuHint":"Exportera, inställningar, språk, ..."},"defaults":{"menuHint":"Exportera, inställningar och mer...","center_heading":"Förenklade. Diagram.","toolbarHint":"Välj ett verktyg & börja rita!","helpHint":"Genvägar & hjälp"}},"colorPicker":{"mostUsedCustomColors":"Mest frekvent använda anpassade färger","colors":"Färger","shades":"Nyanser","hexCode":"Hex-kod","noShades":"Inga nyanser tillgängliga för denna färg"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Exportera som bild","button":"Exportera som bild","description":"Exportera scendata som en bild från vilken du kan importera senare."},"saveToDisk":{"title":"Spara till disk","button":"Spara till disk","description":"Exportera scendata till en fil från vilken du kan importera senare."},"excalidrawPlus":{"title":"Excalidraw+","button":"Exportera till Excalidraw+","description":"Spara skissen till din Excalidraw+ arbetsyta."}},"modal":{"loadFromFile":{"title":"Läs in från fil","button":"Läs in från fil","description":"Laddar från en fil kommer ersätta ditt befintliga innehåll. Du kan säkerhetskopiera din ritning först med hjälp av ett av alternativen nedan."},"shareableLink":{"title":"Läs in från länk","button":"Ersätt mitt innehåll","description":"Inläsning av en extern ritning kommer ersätta ditt befintliga innehåll. Du kan säkerhetskopiera din ritning först genom att använda ett av alternativen nedan."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/ta-IN-json-07623a485202da63a84b.js b/public/excalidraw/excalidraw-assets-dev/locales/ta-IN-json-07623a485202da63a84b.js
new file mode 100644
index 0000000..24e278a
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/ta-IN-json-07623a485202da63a84b.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/ta-IN-json"],{
+
+/***/ "../../locales/ta-IN.json":
+/*!********************************!*\
+ !*** ../../locales/ta-IN.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"ஒட்டு","pasteAsPlaintext":"அலங்காரமின்றி ஒட்டு","pasteCharts":"விளக்கப்படங்களை ஒட்டு","selectAll":"எல்லாம் தேர்ந்தெடு","multiSelect":"உறுப்பைத் தெரிவில் சேர்","moveCanvas":"கித்தானை நகர்த்து","cut":"வெட்டு","copy":"நகலெடு","copyAsPng":"நகலகத்திற்கு PNG ஆக நகலெடு","copyAsSvg":"நகலகத்திற்கு SVG ஆக நகலெடு","copyText":"நகலகத்திற்கு உரையாக நகலெடு","bringForward":"முன்நோக்கி கொண்டுவா","sendToBack":"பின்னே அனுப்பு","bringToFront":"முன்னே கொண்டுவா","sendBackward":"பின்நோக்கி அனுப்பு","delete":"அழி","copyStyles":"ஒயில்களை நகலெடு","pasteStyles":"ஒயில்களை ஒட்டு","stroke":"கீறல்","background":"பின்புலம்","fill":"நிரப்பல்","strokeWidth":"கீறல் அகலம்","strokeStyle":"கீறல் ஒயில்","strokeStyle_solid":"திடமான","strokeStyle_dashed":"கோடிட்ட","strokeStyle_dotted":"புள்ளியிட்ட","sloppiness":"அசட்டுத்தனம்","opacity":"ஒளிபுகாவியல்பு","textAlign":"உரைச் சீரமைப்பு","edges":"விளிம்புகள்","sharp":"கூர்மை","round":"வட்டம்","arrowheads":"அம்புத்தலைகள்","arrowhead_none":"ஏதுமில்லை","arrowhead_arrow":"அம்பு","arrowhead_bar":"பட்டை","arrowhead_dot":"புள்ளி","arrowhead_triangle":"முக்கோணம்","fontSize":"எழுத்துரு அளவு","fontFamily":"எழுத்துரு குடும்பம்","addWatermark":"\\"எக்ஸ்கேலிட்ரா கொண்டு ஆனது\\"-ஐச் சேர்","handDrawn":"கையால்-வரைந்த","normal":"இயல்பு","code":"குறியீடு","small":"சிறிய","medium":"நடுத்தரமான","large":"பெரிய","veryLarge":"மிகப் பெரிய","solid":"திடமான","hachure":"மலைக்குறிக்கோடு","zigzag":"கோணல்மாணல்","crossHatch":"குறுக்குகதவு","thin":"மெல்லிய","bold":"பட்டை","left":"இடது","center":"மையம்","right":"வலது","extraBold":"கூடுதல் பட்டை","architect":"கட்டடக்கலைஞர்","artist":"கலைஞர்","cartoonist":"கேலிச்சித்திர ஓவியர்","fileTitle":"கோப்புப் பெயர்","colorPicker":"நிறத் தேர்வி","canvasColors":"கித்தானில் பயன்படுத்தப்பட்டது","canvasBackground":"கித்தான் பின்னணி","drawingCanvas":"கித்தான் வரைகிறது","layers":"அடுக்குகள்","actions":"செயல்கள்","language":"மொழி","liveCollaboration":"நேரடி கூட்டுப்பணி...","duplicateSelection":"நகலாக்கு","untitled":"தலைப்பற்றது","name":"பெயர்","yourName":"உங்கள் பெயர்","madeWithExcalidraw":"எக்ஸ்கேலிட்ரா கொண்டு ஆனது","group":"தேர்ந்ததை ஒன்றிணை","ungroup":"தேர்ந்ததைப் பிரி","collaborators":"கூட்டுப்பணியினர்","showGrid":"கட்டதைக் காட்டு","addToLibrary":"நூலகத்தில் சேர்","removeFromLibrary":"நூலகத்திலிருந்து நீக்கு","libraryLoadingMessage":"நூலகத்தை ஏற்றுகிறது…","libraries":"நூலகங்களை உலாவு","loadingScene":"காட்சியை ஏற்றுகிறது…","align":"சீரமை","alignTop":"மேலே சீரமை","alignBottom":"கீழே சீரமை","alignLeft":"இடதில் சீரமை","alignRight":"வலதில் சீரமை","centerVertically":"செங்குத்தாக மையப்படுத்து","centerHorizontally":"கிடைமட்டமாக மையப்படுத்து","distributeHorizontally":"கிடைமட்டமாக விநியோகி","distributeVertically":"செங்குத்தாக விநியோகி","flipHorizontal":"கிடைமட்டமாக புரட்டு","flipVertical":"செங்குத்தாக புரட்டு","viewMode":"பார்வை பயன்முறை","share":"பகிர்","showStroke":"கீறல் நிற எடுப்பானைக் காட்டு","showBackground":"பின்னணி நிற எடுப்பானைக் காட்டு","toggleTheme":"தோற்றத்தை நிலைமாற்று","personalLib":"தனக்குரிய நூலகம்","excalidrawLib":"எக்ஸ்கேலிட்ரா நூலகம்","decreaseFontSize":"எழுத்துரு அளவைக் குறை","increaseFontSize":"எழுத்துரு அளவை அதிகரி","unbindText":"உரையைப் பிணைவவிழ்","bindText":"உரையைக் கொள்கலனுக்குப் பிணை","createContainerFromText":"உரையைக் கொள்கலனுள் சுருட்டு","link":{"edit":"தொடுப்பைத் திருத்து","editEmbed":"","create":"தொடுப்பைப் படை","createEmbed":"","label":"தொடுப்பு","labelEmbed":"","empty":""},"lineEditor":{"edit":"தொடுப்பைத் திருத்து","exit":"வரி திருத்தியிலிருந்து வெளியேறு"},"elementLock":{"lock":"பூட்டு","unlock":"பூட்டவிழ்","lockAll":"எல்லாம் பூட்டு","unlockAll":"எல்லாம் பூட்டவிழ்"},"statusPublished":"வெளியிடப்பட்டது","sidebarLock":"பக்கப்பட்டையைத் திறந்தே வை","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":"கித்தானிலிருந்து நிறம் தேர்ந்தெடு"},"library":{"noItems":"இதுவரை உருப்படிகள் சேரக்கப்படவில்லை...","hint_emptyLibrary":"கித்தானிலுள்ள உருப்படியை இங்குச் சேர்க்க தேர்ந்தெடு, அல்லது கீழுள்ள பொது களஞ்சியத்திலிருந்து நூலகத்தை நிறுவு.","hint_emptyPrivateLibrary":"கித்தானிலுள்ள உருப்படியை இங்குச் சேர்க்க தேர்ந்தெடு."},"buttons":{"clearReset":"கித்தானை அகரமாக்கு","exportJSON":"கோப்புக்கு ஏற்றுமதிசெய்","exportImage":"படத்தை ஏற்றுமதிசெய்...","export":"இதில் சேமி...","copyToClipboard":"நகலகத்திற்கு நகலெடு","save":"தற்போதைய கோப்புக்குச் சேமி","saveAs":"இப்படி சேமி","load":"திற","getShareableLink":"பகிரக்கூடிய தொடுப்பைப் பெறு","close":"மூடு","selectLanguage":"மொழியைத் தேர்ந்தெடு","scrollBackToContent":"உருட்டி உள்ளடக்கத்துக்குத் திரும்பு","zoomIn":"பெரிதாக்கு","zoomOut":"சிறிதாக்கு","resetZoom":"உருவளவை அகரமாக்கு","menu":"சிறுபட்டி","done":"முடிந்தது","edit":"திருத்து","undo":"செயல்தவிர்","redo":"மீண்டும்செய்","resetLibrary":"நூலகத்தை அகரமாக்கு","createNewRoom":"புதிய அறையை உருவாக்கு","fullScreen":"முழுத் திரை","darkMode":"கருமை பயன்முறை","lightMode":"வெளிர்ந்த பயன்முறை","zenMode":"ஜென் பயன்முறை","objectsSnapMode":"","exitZenMode":"ஜென் பயன்முறையை விலகு","cancel":"ரத்துசெய்","clear":"துடை","remove":"நீக்கு","embed":"","publishLibrary":"பிரசுரி","submit":"சமர்ப்பி","confirm":"உறுதிசெய்","embeddableInteractionButton":""},"alerts":{"clearReset":"இது முழு கித்தானையும் துடைக்கும். நீங்கள் உறுதியா?","couldNotCreateShareableLink":"பகிரக்கூடிய தொடுப்பை உருவாக்க முடியவில்லை.","couldNotCreateShareableLinkTooBig":"பகிரக்கூடிய தொடுப்பை உருவாக்க முடியவில்லை: காட்சி மிகப்பெரிதாக உள்ளது","couldNotLoadInvalidFile":"செல்லாத கோப்பை ஏற்ற முடியவில்லை","importBackendFailed":"தேகத்திலிருந்து இறக்குமதி தோல்வி.","cannotExportEmptyCanvas":"காலியான கித்தானை ஏற்றுமதிசெய்ய முடியாது.","couldNotCopyToClipboard":"நகலகத்திற்கு நகலெடுக்க முடியவில்லை.","decryptFailed":"தரவை மறைநீக்க முடியவில்லை.","uploadedSecurly":"பதிவேற்றம் இருமுனை மறையாகத்தால் பாதுகாக்கப்பட்டுள்ளது, எனவே எக்ஸ்கேலிட்ரா சேவையகமும் மூன்றாம் தரப்பினரும் உள்ளடக்கத்தை வாசிக்கமுடியாது.","loadSceneOverridePrompt":"வெளிப்புறச்சித்திரமேற்றல் இருக்கிற உள்ளடக்கத்தை இடங்கொள்ளும். தொடர விருப்பமா?","collabStopOverridePrompt":"அமர்வை நிறுத்துதல் முன்னர் அகமாக தேக்கிய உம் சித்திரத்தை மேலெழுதும். நீங்கள் உறுதியா?\\n\\n(உம் அக சித்திரத்தை வைக்கவேண்டுமெனில், சும்மா உலாவி தாவலை மூடுக அதற்குபதிலாக.)","errorAddingToLibrary":"உருப்படியை நூலகத்தில் சேர்க்க இயலா","errorRemovingFromLibrary":"உருப்படியை நூலகத்திலிருந்து நீக்க இயலா","confirmAddLibrary":"இதனால் {{numShapes}} வடிவம்(கள்) உம் நூலகத்தில் சேரும். நீங்கள் உறுதியா?","imageDoesNotContainScene":"இப்படத்தில் காட்சி தரவு ஏதும் இருப்பதுபோல் தெரியவில்லை. ஏற்றுமதியின்போது காட்சி உட்பதிதலை இயக்கினீரா?","cannotRestoreFromImage":"இப்படக்கோப்பிலிருந்து காட்சி மீட்டெடுக்கப்பட முடியாது","invalidSceneUrl":"வழங்கப்பட்ட உரலியிலிருந்து காட்சியை இறக்கவியலா. இது தவறான வடிவத்தில் உள்ளது, அ செல்லத்தக்க எக்ஸ்கேலிட்ரா JSON தரவைக் கொண்டில்லை.","resetLibrary":"இது உங்கள் நுலகத்தைத் துடைக்கும். நீங்கள் உறுதியா?","removeItemsFromsLibrary":"{{count}} உருப்படி(கள்)-ஐ உம் நூலகத்திலிருந்து அழிக்கவா?","invalidEncryptionKey":"மறையாக்க விசை 22 வரியுருக்கள் கொண்டிருக்கவேண்டும். நேரடி கூட்டுப்பணி முடக்கப்பட்டது.","collabOfflineWarning":"இணைய இணைப்பு இல்லை.\\nஉமது மாற்றங்கள் சேமிக்கப்படா!"},"errors":{"unsupportedFileType":"ஆதரிக்கப்படா கோப்பு வகை.","imageInsertError":"படத்தைப் புகுத்தவியலா. பிறகு மீண்டும் முயலவும்...","fileTooBig":"கோப்பு மிகப்பெரிது. அனுமதிக்கப்பட்ட அதிகபட்ச அளவு {{maxSize}}.","svgImageInsertError":"எஸ்விஜி படத்தைப் புகுத்தவியலா. எஸ்விஜியின் மார்க்அப் செல்லாததாக தெரிகிறது.","failedToFetchImage":"","invalidSVGString":"செல்லாத SVG.","cannotResolveCollabServer":"கூட்டுப்பணிச் சேவையகத்துடன் இணைக்க முடியவில்லை. பக்கத்தை மீளேற்றி மீண்டும் முயலவும்.","importLibraryError":"நூலகத்தை ஏற்ற முடியவில்லை","collabSaveFailed":"பின்முனை தரவுத்தளத்தில் சேமிக்க முடியவில்லை. சிக்கல்கள் நீடித்தால், உமது வேலைகளை இழக்காமலிருப்பதை உறுதிசெய்ய உமது கோப்பை உள்ளகத்தில் சேமிக்க வேண்டும்.","collabSaveFailed_sizeExceeded":"பின்முனை தரவுத்தளத்தில் சேமிக்க முடியவில்லை, கித்தான் மிகப்பெரிதாகத் தெரிகிறது. உமது வேலைகளை இழக்காமலிருப்பதை உறுதிசெய்ய உமது கோப்பை உள்ளகத்தில் சேமிக்க வேண்டும்.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"தெரிவு","image":"படத்தைப் புகுத்து","rectangle":"செவ்வகம்","diamond":"வைரம்","ellipse":"நீள்வட்டம்","arrow":"அம்பு","line":"வரி","freedraw":"வரை","text":"உரை","library":"நூலகம்","lock":"தேர்ந்த கருவியை வரைந்த பின்பும் வைத்திரு","penMode":"பேனா - தடுப்பு தொடுதல்","link":"தேர்தெடுத்த வடிவத்திற்குத் தொடுப்பைச் சேர்/ புதுப்பி","eraser":"அழிப்பி","frame":"சட்டகம் கருவி","embeddable":"","laser":"","hand":"கை (பார்வை நகர்கும் கருவி)","extraTools":"மற்ற கருவிகள்"},"headings":{"canvasActions":"கித்தான் செயல்கள்","selectedShapeActions":"தேர்ந்த வடிவம் செயல்கள்","shapes":"வடிவங்கள்"},"hints":{"canvasPanning":"","linearElement":"பல புள்ளிகளைத் துவக்க சொடுக்கு, ஒற்றை வரிக்கு பிடித்திழு","freeDraw":"சொடுக்கி பிடித்திழு, முடித்ததும் விடுவி","text":"துணுக்குதவி: தெரிவு கருவி கொண்டு எங்காவது இரு-சொடுக்கி உரையைச் சேர்க்கலாம்","embeddable":"","text_selected":"உரையைத் திருத்த இரு-சொடுக்கு அ ENTERஐ அழுத்து","text_editing":"திருத்துவதை முடிக்க Escape அ CtrlOrCmd+ENTERஐ அழுத்து","linearElementMulti":"கடைசி புள்ளியில் சொடுக்கு அ முடிக்க Escape அ Enter அழுத்து","lockAngle":"SHIFTஐ அழுத்திப்பிடித்து கோணத்தை வற்புறுத்தலாம்","resize":"மறுஅளவிடுகையில் SHIFTஐ அழுத்திப்பிடித்து விகிதசமத்தை வற்புறுத்தலாம்,\\nமையத்திலிருந்து மறுஅளவிட ALTஐ அழுத்திப்பிடி","resizeImage":"SHIFTஐ நீண்டழுத்தி கட்டற்று அளவுமாற்றலாம்,\\nமையத்திலிருந்து அளவுமாற்ற ALTஐ நீண்டழுத்துக","rotate":"சுழற்றுகையில் SHIFTஐ அழுத்திப்பிடித்து கோணங்களை வற்புறுத்தலாம்","lineEditor_info":"","lineEditor_pointSelected":"புள்ளி(கள்)ஐ நீக்க Deleteஐ அழுத்து,\\nநகலாக்க CtrlOrCmd+D, அ நகர்த்த பிடித்திழு","lineEditor_nothingSelected":"திருத்த புள்ளியைத் தேர்ந்தெடு (பலவற்றை தேர SHIFTஐ அழுத்திப்பிடி),\\nஅ புதிய புள்ளிகளைச் சேர்க்க Altஐ அழுத்திப்பிடித்துச் சொடுக்கு","placeImage":"படத்தை வைக்கச் சொடுக்கு, அ கைமுறையாக அளவு அமைக்க சொடுக்கி பிடித்திழு","publishLibrary":"உம் சொந்த நூலகத்தைப் பிரசுரி","bindTextToElement":"உரையைச் சேர்க்க enterஐ அழுத்து","deepBoxSelect":"ஆழ்ந்துத் தேரவும் பிடித்திழுத்தலைத் தவிர்க்கவும் CtrlOrCmdஐ அழுத்திப்பிடி","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"முன்னோட்டம் காட்ட இயலவில்லை","canvasTooBig":"கித்தான் மிகப்பெரிதாக இருக்கலாம்.","canvasTooBigTip":"துணுக்குதவி: தூரத்திலுள்ள உறுப்புகளைப் நெருக்கமாக நகர்த்தப்பார்."},"errorSplash":{"headingMain":"பிழையைச் சந்தித்தீரா. முயலவும் ","clearCanvasMessage":"மீண்டுமேற்றல் வேலைசெய்யவிட்டால், முயற்சி ","clearCanvasCaveat":" இது வேலையை இழக்கக்கூடும் ","trackedToSentry":"இனங்காணியில் பிழை {{eventId}} எங்கள் இயங்குதளத்தில் தடமறியப்பட்டது.","openIssueMessage":"பிழையில் உம் காட்சி தகவலை உள்ளடக்காமலிருக்க நாங்கள் மிக எச்சரிக்கையாக இருந்தோம். உம் காட்சி தனிப்பட்டதில்லையெனில், பின்தொடர்வதற்கு பரிசீலிக்கவும் எங்கள் கீழுள்ள தகவலை நகலெடுத்து ஒட்டி GitHub சிக்கலுள் உள்ளடக்கவும்.","sceneContent":"காட்சி உள்ளடக்கம்:"},"roomDialog":{"desc_intro":"உம்முடன் கூட்டுப்பணிசெய்ய மக்களை தற்போதைய காட்சிக்கு அழைப்பிடலாம்.","desc_privacy":"வருந்தாதீர், அமர்வு இருமுனை மறையகத்தைப் பயன்படுத்துகிறது, ஆக நீங்கள் வரைவது எதுவும் தனிப்பட்டதாக இருக்கும். எங்கள் சேவையகத்தால் கூட நீங்கள் என்ன செய்ததைப் பார்க்கவியலாது.","button_startSession":"அமர்வைத் துவக்கு","button_stopSession":"அமர்வை நிறுத்து","desc_inProgressIntro":"நேரடி-கூட்டுப்பணி அமர்வு தற்போது செயலிலுள்ளது.","desc_shareLink":"கூட்டுப்பணிபுரிய விரும்பும் எவருனும் இத்தொடுப்பைப் பகிர்க:","desc_exitSession":"அமர்வை நிறுத்தல் உம்மை அறையிலிருந்து துண்டிக்கும், ஆனால் காட்சியுடன் தொடர்ந்து பணிபுரிய உம்மாலியலும், அகமாக. இது பிற மக்களைப் பாதிக்காதென்பதைக் குறி, மற்றும் அவர்களாலவர்களுடைய பதிப்பில் இன்னும் கூட்டுப்பணிபுரியவியலும்.","shareTitle":"எக்ஸ்கேலிட்ராவில் நேரடி கூட்டுப்பணி அமர்வில் சேர்"},"errorDialog":{"title":"பிழை"},"exportDialog":{"disk_title":"வட்டில் சேமி","disk_details":"காட்சித் தரவை நீங்கள் பின்னர் இறக்குமதி செய்யக்கூடிய ஒரு கோப்பிற்கு ஏற்றுமதிசெய்க.","disk_button":"கோப்பில் சேமி","link_title":"பகிரக்கூடிய தொடுப்பு","link_details":"வாசிக்க-மட்டும் தொடுப்பாக ஏற்றுமதிசெய்.","link_button":"தொடுப்புக்கு ஏற்றுமதிசெய்","excalidrawplus_description":"காட்சியை உன் எக்ஸ்கேலிட்ரா பணியிடத்தில் சேமி.","excalidrawplus_button":"ஏற்றுமதி","excalidrawplus_exportError":"இத்தருணத்தில் எக்ஸ்கேலிட்ரா+ க்கு ஏற்றுமதிசெய்ய முடியவில்லை..."},"helpDialog":{"blog":"எமது வலைப்பூவை வாசி","click":"சொடுக்கு","deepSelect":"ஆழ்ந்துத் தேர்","deepBoxSelect":"பெட்டியினுள் ஆழ்ந்துத் தேர், மற்றும் பிடித்திழுத்தலைத் தவிர்","curvedArrow":"வளைந்த அம்பு","curvedLine":"வளைந்த வரி","documentation":"ஆவணமாக்கல்","doubleClick":"இரு-சொடுக்கு","drag":"பிடித்திழு","editor":"திருத்தி","editLineArrowPoints":"","editText":"","github":"சிக்கலைக் கண்டீரா? சமர்ப்பி","howto":"எங்கள் கையேடுகளைப் பின்பற்றுக","or":"அ","preventBinding":"அம்பு பிணைதலைத் தவிர்","tools":"கருவிகள்","shortcuts":"விசைப்பலகை குறுக்குவழிகள்","textFinish":"திருத்துதலை முடி (உரை திருத்தி)","textNewLine":"புதிய வரியைச் சேர் (உரை திருத்தி)","title":"உதவி","view":"பார்","zoomToFit":"அனைத்துறுப்புகளும் பொருந்தும்படி விரிவாக்கு","zoomToSelection":"தெரிவுக்கு விரிவாக்கு","toggleElementLock":"தேர்ந்தெடுப்பைப் பூட்டு/பூட்டவிழ்","movePageUpDown":"மேலே/கீழே நகர்த்தவும்","movePageLeftRight":"இடது/வலது பக்கம் நகர்த்தவும்"},"clearCanvasDialog":{"title":"கித்தானைத் துடை"},"publishDialog":{"title":"நூலகத்தைப் பிரசுரி","itemName":"உருப்படியின் பெயர்","authorName":"ஆசிரியர் பெயர்","githubUsername":"GitHub பயனர்பெயர்","twitterUsername":"டுவிட்டர் பயனர்பெயர்","libraryName":"நூலக பெயர்","libraryDesc":"நூலக விவரிப்பு","website":"வலைத்தளம்","placeholder":{"authorName":"உம் பெயர் அ பயனர்பெயர்","libraryName":"உம் நூலகத்தின் பெயர்","libraryDesc":"உம் நூலகத்தின் விவரிப்பு இதன் பயன்பாட்டை மக்கள் புரிந்துகொள்ளவுதவ","githubHandle":"GitHub கைப்பிடி (விரும்பினால்), ஆதலால் நீங்கள் நூலகத்தை மதிப்பாய்விற்காக சமர்ப்பித்தவுடன் திருத்தமுடியும்","twitterHandle":"டுவிட்டர் பயனர்பெயர் (விரும்பினால்), ஆதலால் டுவிட்டரில் முன்னிறுத்தும்போது யாமெவரைப் புகழ்வதென்றறிவோம்","website":"உமக்குரிய வலைத்தளத்திற்கு அ வேறெங்கிற்குமான தொடுப்பு (விரும்பினால்)"},"errors":{"required":"தேவைப்டுகிறது","website":"செல்லத்தக்க உரலியை உள்ளிடு"},"noteDescription":"உம் நூலகத்தைச் சமர்ப்பி உள்ளடக்குவதற்கு பொது நூலக களஞ்சியத்தில்பிற மக்களவர்களின் சித்திரங்களில் பயன்படுத்த.","noteGuidelines":"நூலகம் முதலில் கைமுறையாக ஒப்புக்கொள்ளப்படவேண்டும். வாசிக்கவும் வழிகாட்டுதல்களைச் சமர்ப்பிக்கும் முன்பு. கோரப்பட்டால் தொடர்புகொள்ள மற்றும் மாற்றங்கள் செய்ய உமக்கொரு GitHub கணக்கு தேவை, ஆனால் அது கண்டிப்பாக தேவையல்ல.","noteLicense":"சமர்ப்பிப்பதனால், நூலகம் இதனடியில் பிரசரிக்கப்பட ஏற்கிறீர்கள் MIT உரிமம், சுருக்கமாக எவருமிதைப் வரையறையின்றி பயன்படுத்தலாமென குறிக்கிறது.","noteItems":"வடிக்கட்டக்கூடியதாகவிருக்க ஒவ்வொரு நூலகவுருப்படிக்கும் சொந்த பெயர் இருக்கவேண்டும். பின்வரும் நூலகவுருப்படிகள் உள்ளடக்கப்படும்:","atleastOneLibItem":"ஆரம்பிக்க ஒரு நூலக உருப்படியையாவது தேர்ந்தெடுக்கவும்","republishWarning":""},"publishSuccessDialog":{"title":"நூலகம் சமர்ப்பிக்கப்பட்டது","content":"நன்றி {{authorName}}. உமது நூலகம் மதிப்பாய்விற்காக சமர்ப்பிக்கப்பட்டது. நிலையை நீங்கள் தடமறியலாம்இங்கே"},"confirmDialog":{"resetLibrary":"நூலகத்தை அகரமாக்கு","removeItemsFromLib":"நூலகத்திலிருந்து தேர்ந்தெடுத்த உருப்படிகளை நீக்கு"},"imageExportDialog":{"header":"படத்தை ஏற்றுமதிதல","label":{"withBackground":"பின்னணி","onlySelected":"தேர்ந்ததை மட்டும்","darkMode":"இருள் பயன்முறை","embedScene":"காட்சியை உட்பொதி","scale":"அளவுகோல்","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"PNGக்கு ஏற்றுமதிசெய்","exportToSvg":"SVGக்கு ஏற்றுமதிசெய்","copyPngToClipboard":""},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":""}},"encrypted":{"tooltip":"உம் சித்திரங்கள் இருமுனை மறையாக்கம் செய்யப்பட்டவையாதலால் எக்ஸ்கேலிட்ராவின் சேவையகங்கள் அவற்றை ஒருபோதும் பார்க்கா.","link":"எக்ஸ்கேலிட்ராவில் இருமுனை மறையாக்கம் மீதான வலைப்பூ இடுகை"},"stats":{"angle":"கோணம்","element":"உறுப்பு","elements":"உறுப்புகள்","height":"உயரம்","scene":"காட்சி","selected":"தேர்ந்தவை","storage":"சேமிப்பகம்","title":"மேதாவிகளுக்கான புள்ளிவிவரங்கள்","total":"மொத்தம்","version":"பதிப்பு","versionCopy":"நகலெடுக்க சொடுக்கு","versionNotAvailable":"பதிப்பு கிடைக்கவில்லை","width":"அகலம்"},"toast":{"addedToLibrary":"நூலகத்தில் சேர்க்கப்பட்டது","copyStyles":"ஒயில்கள் நகலெடுக்கப்பட்டன.","copyToClipboard":"நகலகத்திற்கு நகலெடுக்கப்பட்டது.","copyToClipboardAsPng":"{{exportSelection}}-ஐ நகலகத்திற்கு PNG ஆக நகலெடுத்தது\\n({{exportColorScheme}})","fileSaved":"கோப்பு சேமிக்கப்பட்டது.","fileSavedToFilename":"{filename}-க்கு சேமிக்கப்பட்டது","canvas":"கித்தான்","selection":"தெரிவு","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"ஒளிபுகுத்தன்மை","black":"கருப்பு","white":"வெள்ளை","red":"சிவப்பு","pink":"இளஞ்சிவப்பு","grape":"திராட்சை","violet":"ஊதா","gray":"சாம்பல்","blue":"நீலம்","cyan":"மயில்நிறம்","teal":"டீல்","green":"பச்சை","yellow":"மஞ்சள்","orange":"ஆரஞ்சு","bronze":"வெண்கலம்"},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"எளிமையாக வரைபடங்கள் உருவாக்க!","toolbarHint":"கருவியைத் தேர்ந்தெடு & வரை!","helpHint":"குறுக்குவழிகள் & உதவி"}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/th-TH-json-4e4b97f5f6e905191383.js b/public/excalidraw/excalidraw-assets-dev/locales/th-TH-json-4e4b97f5f6e905191383.js
new file mode 100644
index 0000000..7139f71
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/th-TH-json-4e4b97f5f6e905191383.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/th-TH-json"],{
+
+/***/ "../../locales/th-TH.json":
+/*!********************************!*\
+ !*** ../../locales/th-TH.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"วาง","pasteAsPlaintext":"วางโดยไม่มีการจัดรูปแบบ","pasteCharts":"วางแผนภูมิ","selectAll":"เลือกทั้งหมด","multiSelect":"","moveCanvas":"","cut":"ตัด","copy":"คัดลอก","copyAsPng":"คัดลองไปยังคลิปบอร์ดเป็น PNG","copyAsSvg":"คัดลองไปยังคลิปบอร์ดเป็น SVG","copyText":"คัดลองไปยังคลิปบอร์ดเป็นข้อความ","bringForward":"นำขึ้นข้างบน","sendToBack":"ย้ายไปข้างล่าง","bringToFront":"นำขึ้นข้างหน้า","sendBackward":"ย้ายไปข้างหลัง","delete":"ลบ","copyStyles":"คัดลอกรูปแบบ","pasteStyles":"วางรูปแบบ","stroke":"เส้นขอบ","background":"พื้นหลัง","fill":"เติมสี","strokeWidth":"น้ำหนักเส้นขอบ","strokeStyle":"รูปแบบเส้น","strokeStyle_solid":"เส้นทึบ","strokeStyle_dashed":"เส้นประ","strokeStyle_dotted":"จุด","sloppiness":"ความเลอะเทอะ","opacity":"ความทึบแสง","textAlign":"จัดข้อความ","edges":"ขอบ","sharp":"","round":"","arrowheads":"หัวลูกศร","arrowhead_none":"ไม่มี","arrowhead_arrow":"ลูกศร","arrowhead_bar":"แถบ","arrowhead_dot":"จุด","arrowhead_triangle":"สามเหลี่ยม","fontSize":"ขนาดตัวอักษร","fontFamily":"แบบตัวอักษร","addWatermark":"เพิ่มลายน้ำ \\"สร้างด้วย Excalidraw\\"","handDrawn":"ลายมือ","normal":"ปกติ","code":"โค้ด","small":"เล็ก","medium":"กลาง","large":"ใหญ่","veryLarge":"ใหญ่มาก","solid":"","hachure":"","zigzag":"","crossHatch":"","thin":"บาง","bold":"หนา","left":"ซ้าย","center":"กลาง","right":"ขวา","extraBold":"หนาพิเศษ","architect":"","artist":"ศิลปิน","cartoonist":"","fileTitle":"ชื่อไฟล์","colorPicker":"เลือกสีที่กำหนดเอง","canvasColors":"","canvasBackground":"","drawingCanvas":"","layers":"","actions":"การกระทำ","language":"ภาษา","liveCollaboration":"","duplicateSelection":"ทำสำเนา","untitled":"ไม่มีชื่อ","name":"ชื่อ","yourName":"ชื่อของคุณ","madeWithExcalidraw":"","group":"จัดกลุ่ม","ungroup":"ยกเลิกการจัดกลุ่ม","collaborators":"","showGrid":"แสดงเส้นตาราง","addToLibrary":"เพิ่มไปในคลัง","removeFromLibrary":"นำออกจากคลัง","libraryLoadingMessage":"กำลังโหลดคลัง...","libraries":"","loadingScene":"กำลังโหลดฉาก","align":"จัดตำแหน่ง","alignTop":"จัดชิดด้านบน","alignBottom":"จัดชิดด้านล่าง","alignLeft":"จัดชิดซ้าย","alignRight":"จัดชิดขวา","centerVertically":"กึ่งกลางแนวตั้ง","centerHorizontally":"กึ่งกลางแนวนอน","distributeHorizontally":"กระจายแนวนอน","distributeVertically":"กระจายแนวตั้ง","flipHorizontal":"พลิกแนวนอน","flipVertical":"พลิกแนวตั้ง","viewMode":"โหมดมุมมอง","share":"แชร์","showStroke":"","showBackground":"","toggleTheme":"สลับธีม","personalLib":"คลังของฉัน","excalidrawLib":"คลังของ Excalidraw","decreaseFontSize":"ลดขนาดตัวอักษร","increaseFontSize":"เพิ่มขนาดตัวอักษร","unbindText":"ยกเลิกการผูกติด","bindText":"","createContainerFromText":"","link":{"edit":"แก้ไขลิงก์","editEmbed":"แก้ไขลิงค์และการฝัง","create":"สร้างลิงค์","createEmbed":"สร้างลิงค์และการฝัง","label":"ลิงค์","labelEmbed":"ลิงค์และการฝัง","empty":"ไม่ได้ใส่ลิงค์"},"lineEditor":{"edit":"แก้ไขเส้น","exit":""},"elementLock":{"lock":"ล็อก","unlock":"ปลดล็อก","lockAll":"ล็อกทั้งหมด","unlockAll":"ปลดล็อกทั้งหมด"},"statusPublished":"เผยแพร่","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"ยังไม่มีรายการที่เพิ่มเข้าไปได้","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"รีเซ็ทผืนผ้าใบ","exportJSON":"ส่งออกไปยังไฟล์","exportImage":"ส่งออกเป็นรูปภาพ","export":"บันทึกไปยัง","copyToClipboard":"คัดลอกไปยังคลิปบอร์ด","save":"บันทึกเป็นไฟล์ปัจจุบัน","saveAs":"บันทึกเป็น","load":"เปิด","getShareableLink":"สร้างลิงค์ที่แชร์ได้","close":"ปิด","selectLanguage":"เลือกภาษา","scrollBackToContent":"เลื่อนกลับไปด้านบน","zoomIn":"ซูมเข้า","zoomOut":"ซูมออก","resetZoom":"รีเซ็ตการซูม","menu":"เมนู","done":"เสร็จสิ้น","edit":"แก้ไข","undo":"เลิกทำ","redo":"ทำซ้ำ","resetLibrary":"รีเซ็ตคลัง","createNewRoom":"สร้างห้องใหม่","fullScreen":"เต็มหน้าจอ","darkMode":"โหมดกลางคืน","lightMode":"โหมดกลางวัน","zenMode":"โหมด Zen","objectsSnapMode":"","exitZenMode":"ออกจากโหมด Zen","cancel":"ยกเลิก","clear":"เคลียร์","remove":"ลบ","embed":"สลับการฝัง","publishLibrary":"เผยแพร่","submit":"ตกลง","confirm":"ยืนยัน","embeddableInteractionButton":"คลิกเพื่อปฏิสัมพันธ์"},"alerts":{"clearReset":"","couldNotCreateShareableLink":"ไม่สามารถสร้างลิงค์ได้","couldNotCreateShareableLinkTooBig":"","couldNotLoadInvalidFile":"ไม่สามารถโหลดไฟล์ที่ผิดพลาดได้","importBackendFailed":"เกิดข้อผิดพลาดจากการนำเข้าจากระบบหลังบ้าน","cannotExportEmptyCanvas":"ไม่สามารถนำออกจากผืนผ้าใบที่ว่างเปล่าได้","couldNotCopyToClipboard":"ไม่สามารถคัดลอกไปยังคลิปบอร์ดได้","decryptFailed":"ไม่สามารถถอดรหัสข้อมูลได้","uploadedSecurly":"การอัพโหลดได้ถูกเข้ารหัสแบบ end-to-end หมายความว่าเซิร์ฟเวอร์ของ Excalidraw และบุคคลอื่นไม่สามารถอ่านข้อมูลได้","loadSceneOverridePrompt":"","collabStopOverridePrompt":"","errorAddingToLibrary":"ไม่สามารถเพิ่มรายการเข้าไปในคลังได้","errorRemovingFromLibrary":"ไม่สามารถลบรายการนี้ออกจากคลังได้","confirmAddLibrary":"","imageDoesNotContainScene":"","cannotRestoreFromImage":"","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"","invalidEncryptionKey":"","collabOfflineWarning":""},"errors":{"unsupportedFileType":"ไม่รองรับชนิดของไฟล์นี้","imageInsertError":"ไม่สามารถเพิ่มรูปภาพได้ ลองอีกครั้งในภายหลัง","fileTooBig":"","svgImageInsertError":"","failedToFetchImage":"","invalidSVGString":"ไฟล์ SVG ผิดพลาด","cannotResolveCollabServer":"ไม่สามารถเชื่อต่อกับ collab เซิร์ฟเวอร์ได้ โปรดลองโหลดหน้านี้ใหม่และลองอีกครั้ง","importLibraryError":"","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"การเพิ่มองค์ประกอบที่ฝังยังไม่สามารถเพิ่มเข้าไปในไลบลารีได้","image":"การสนับสนุนสำหรับเพิ่มรูปภาพลงในไลบลารีจะมาในเร็ว ๆ นี้"}},"toolBar":{"selection":"","image":"","rectangle":"สี่เหลี่ยมผืนผ้า","diamond":"","ellipse":"วงรี","arrow":"ลูกศร","line":"","freedraw":"","text":"ข้อความ","library":"คลัง","lock":"","penMode":"","link":"","eraser":"ยางลบ","frame":"","embeddable":"ฝังเว็บ","laser":"","hand":"","extraTools":"เครื่องมืออื่นๆ"},"headings":{"canvasActions":"","selectedShapeActions":"","shapes":"รูปร่าง"},"hints":{"canvasPanning":"","linearElement":"","freeDraw":"","text":"","embeddable":"คลิกและลากเพื่อสร้างการฝังสำหรับเว็บไซต์","text_selected":"คลิกสองครั้งหรือกด ENTER เพื่อแก้ไขข้อความ","text_editing":"กดปุ่ม Esc หรือกด Ctrl, Cmd + Enter เพื่อเสร็จการแก้ไข","linearElementMulti":"คลิกที่จุดสุดท้ายหรือกด Escape หรือ Enter เพื่อเสร็จสิ้น","lockAngle":"","resize":"","resizeImage":"","rotate":"","lineEditor_info":"","lineEditor_pointSelected":"กดปุ่ม Delete เพื่อลบจุด\\nกด Ctrl หรือ Cmd + D เพื่อทำซ้ำหรือลากเพื่อเคลื่อนย้าย","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"","canvasTooBig":"","canvasTooBigTip":""},"errorSplash":{"headingMain":"","clearCanvasMessage":"ถ้าโหลดไม่ได้ ให้ลอง ","clearCanvasCaveat":"","trackedToSentry":"","openIssueMessage":"","sceneContent":""},"roomDialog":{"desc_intro":"","desc_privacy":"","button_startSession":"เริ่มเซสชัน","button_stopSession":"หยุดเซสชัน","desc_inProgressIntro":"","desc_shareLink":"","desc_exitSession":"","shareTitle":""},"errorDialog":{"title":""},"exportDialog":{"disk_title":"","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"","excalidrawplus_exportError":"ไม่สามารถส่งออกไปที่ Excalidraw+ ได้ในขณะนี้"},"helpDialog":{"blog":"อ่านบล็อกของพวกเรา","click":"คลิก","deepSelect":"","deepBoxSelect":"","curvedArrow":"","curvedLine":"","documentation":"","doubleClick":"ดับเบิลคลิก","drag":"ลาก","editor":"","editLineArrowPoints":"","editText":"แก้ไขข้อความ / เพิ่มข้อความ","github":"","howto":"","or":"","preventBinding":"","tools":"","shortcuts":"","textFinish":"","textNewLine":"","title":"ช่วยเหลือ","view":"ดู","zoomToFit":"","zoomToSelection":"","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":"ย้ายหน้าไปด้าน ซ้าย/ขวา"},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"ชื่อเจ้าของ","githubUsername":"ชื่อผู้ใช้ GitHub","twitterUsername":"ชื่อผู้ใช้ Twitter","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"โหมดกลางคืน","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"ส่งออกไปเป็น SVG","exportToSvg":"ส่งออกไปเป็น SVG","copyPngToClipboard":"คัดลอก PNG ไปยังคลิปบอร์ด"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"คัดลอกไปยังคลิปบอร์ด"}},"encrypted":{"tooltip":"","link":""},"stats":{"angle":"","element":"","elements":"","height":"","scene":"","selected":"","storage":"","title":"","total":"","version":"","versionCopy":"","versionNotAvailable":"","width":""},"toast":{"addedToLibrary":"","copyStyles":"","copyToClipboard":"","copyToClipboardAsPng":"","fileSaved":"","fileSavedToFilename":"","canvas":"","selection":"","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"ฟ้าน้ำทะเล","green":"เขียว","yellow":"เหลือง","orange":"ส้ม","bronze":"ทองแดง"},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/tr-TR-json-003be1cf6ebf0b787dec.js b/public/excalidraw/excalidraw-assets-dev/locales/tr-TR-json-003be1cf6ebf0b787dec.js
new file mode 100644
index 0000000..dcdfc3f
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/tr-TR-json-003be1cf6ebf0b787dec.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/tr-TR-json"],{
+
+/***/ "../../locales/tr-TR.json":
+/*!********************************!*\
+ !*** ../../locales/tr-TR.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Yapıştır","pasteAsPlaintext":"Düz metin olarak yapıştır","pasteCharts":"Grafikleri yapıştır","selectAll":"Tümünü seç","multiSelect":"Seçime öge ekle","moveCanvas":"Tuvali taşı","cut":"Kes","copy":"Kopyala","copyAsPng":"Panoya PNG olarak kopyala","copyAsSvg":"Panoya SVG olarak kopyala","copyText":"Panoya metin olarak kopyala","bringForward":"Bir öne getir","sendToBack":"Arkaya gönder","bringToFront":"En öne getir","sendBackward":"Bir geriye gönder","delete":"Sil","copyStyles":"Stilleri kopyala","pasteStyles":"Stilleri yapıştır","stroke":"Vurgu","background":"Arka plan","fill":"Doldur","strokeWidth":"Kontur genişliği","strokeStyle":"Kontur stili","strokeStyle_solid":"Dolu","strokeStyle_dashed":"Kesik çizgili","strokeStyle_dotted":"Noktalı","sloppiness":"Üstün körülük","opacity":"Opaklık","textAlign":"Metin hizala","edges":"Kenarlar","sharp":"Keskin","round":"Yuvarlak","arrowheads":"Ok uçları","arrowhead_none":"Yok","arrowhead_arrow":"Ok","arrowhead_bar":"Çizgi","arrowhead_dot":"Nokta","arrowhead_triangle":"Üçgen","fontSize":"Yazı tipi boyutu","fontFamily":"Yazı tipi ailesi","addWatermark":"\\"Excalidraw ile yapıldı\\" yazısını ekle","handDrawn":"El-yazısı","normal":"Normal","code":"Kod","small":"Küçük","medium":"Orta","large":"Büyük","veryLarge":"Çok geniş","solid":"Dolu","hachure":"Taralı","zigzag":"Zikzak","crossHatch":"Çapraz-taralı","thin":"İnce","bold":"Kalın","left":"Sol","center":"Ortala","right":"Sağ","extraBold":"Ekstra kalın","architect":"Mimar","artist":"Sanatçı","cartoonist":"Karikatürist","fileTitle":"Dosya adı","colorPicker":"Renk seçici","canvasColors":"Tuvalin üzerinde kullanıldı","canvasBackground":"Tuval arka planı","drawingCanvas":"Çizim tuvali","layers":"Katmanlar","actions":"Eylemler","language":"Dil","liveCollaboration":"Canlı ortak çalışma alanı...","duplicateSelection":"Çoğalt","untitled":"Adsız","name":"İsim","yourName":"İsminiz","madeWithExcalidraw":"Excalidraw ile yapıldı","group":"Seçimi grup yap","ungroup":"Seçilen grubu dağıt","collaborators":"Ortaklar","showGrid":"Izgarayı göster","addToLibrary":"Kütüphaneye ekle","removeFromLibrary":"Kütüphaneden kaldır","libraryLoadingMessage":"Kütüphane yükleniyor…","libraries":"Kütüphanelere gözat","loadingScene":"Sahne yükleniyor…","align":"Hizala","alignTop":"Yukarı hizala","alignBottom":"Aşağı hizala","alignLeft":"Sola hizala","alignRight":"Sağa hizala","centerVertically":"Dikeyde ortala","centerHorizontally":"Yatayda ortala","distributeHorizontally":"Yatay dağıt","distributeVertically":"Dikey dağıt","flipHorizontal":"Yatay döndür","flipVertical":"Dikey döndür","viewMode":"Görünüm modu","share":"Paylaş","showStroke":"Kontur için renk seçiciyi göster","showBackground":"Arkaplan için renk seçiciyi göster","toggleTheme":"Temayı etkinleştir/devre dışı bırak","personalLib":"Kişisel Kitaplık","excalidrawLib":"Excalidraw Kitaplığı","decreaseFontSize":"Yazı Tipi Boyutunu Küçült","increaseFontSize":"Yazı Tipi Boyutunu Büyült","unbindText":"Metni çöz","bindText":"Metni taşıyıcıya bağla","createContainerFromText":"Metni bileşen içinde sar","link":{"edit":"Bağlantıyı düzenle","editEmbed":"Bağlantıyı düzenle & yerleştir","create":"Bağlantı oluştur","createEmbed":"Bağlantı oluştur & yerleştir","label":"Bağlantı","labelEmbed":"Bağlantı & yerleştirme","empty":"Herhangi bir bağlantı oluşturulmadı"},"lineEditor":{"edit":"Çizgiyi düzenle","exit":"Çizgi düzenlemeden çık"},"elementLock":{"lock":"Kilitle","unlock":"Kilidi Kaldır","lockAll":"Hepsini kilitle","unlockAll":"Hepsinin kilidini kaldır"},"statusPublished":"Yayınlandı","sidebarLock":"Kenar çubuğu açık kalsın","selectAllElementsInFrame":"Çerçevedeki tüm bileşenleri seç","removeAllElementsFromFrame":"Çerçevedeki tüm bileşenleri sil","eyeDropper":"Tuvalden renk seç"},"library":{"noItems":"Öğe eklenmedi...","hint_emptyLibrary":"Öğelerden birini eklemek için öğeyi seçiniz veya aşağıdaki genel kütüphaneden öğeleri ekleyin.","hint_emptyPrivateLibrary":"Tuvalden bir eleman seçerek sayfaya ekleyin."},"buttons":{"clearReset":"Tuvali sıfırla","exportJSON":"Dosyaya aktar","exportImage":"Resimleri dışa aktar...","export":"Şuraya kaydet...","copyToClipboard":"Panoya kopyala","save":"Geçerli dosyaya kaydet","saveAs":"Farklı kaydet","load":"Aç","getShareableLink":"Paylaşılabilir bağlantı al","close":"Kapat","selectLanguage":"Dil seçin","scrollBackToContent":"İçeriğe geri dön","zoomIn":"Yakınlaştır","zoomOut":"Uzaklaştır","resetZoom":"Yakınlaştırmayı sıfırla","menu":"Menü","done":"Tamam","edit":"Düzenle","undo":"Geri Al","redo":"Yeniden yap","resetLibrary":"Kütüphaneyi sıfırla","createNewRoom":"Yeni oda oluştur","fullScreen":"Tam ekran","darkMode":"Koyu tema","lightMode":"Açık tema","zenMode":"Zen modu","objectsSnapMode":"Nesnelere hizala","exitZenMode":"Zen modundan çık","cancel":"İptal","clear":"Temizle","remove":"Kaldır","embed":"","publishLibrary":"Yayınla","submit":"Gönder","confirm":"Onayla","embeddableInteractionButton":"Etkileşime girmek için tıkla"},"alerts":{"clearReset":"Tuvalin tamamı temizlenecek. Emin misiniz?","couldNotCreateShareableLink":"Paylaşılabilir bağlantı oluşturulamadı.","couldNotCreateShareableLinkTooBig":"Paylaşılabilir bağlantı oluşturulamadı: sahne çok büyük","couldNotLoadInvalidFile":"Bilinmeyen dosya yüklenemiyor","importBackendFailed":"Sunucudan içe aktarma başarısız.","cannotExportEmptyCanvas":"Boş tuval dışarıya aktarılamaz.","couldNotCopyToClipboard":"Panoya kopyalanamıyor.","decryptFailed":"Şifrelenmiş veri çözümlenemedi.","uploadedSecurly":"Yükleme uçtan uca şifreleme ile korunmaktadır. Excalidraw sunucusu ve üçüncül şahıslar içeriği okuyamayacaktır.","loadSceneOverridePrompt":"Harici çizimler yüklemek mevcut olan içeriği değiştirecektir. Devam etmek istiyor musunuz?","collabStopOverridePrompt":"Oturumu sonlandırmak daha önceki, yerel olarak kaydedilmiş çizimin üzerine kaydedilmesine sebep olacak. Emin misiniz?\\n\\n(Yerel çiziminizi kaybetmemek için tarayıcı sekmesini kapatabilirsiniz.)","errorAddingToLibrary":"Öğe kütüphaneye eklenemedi","errorRemovingFromLibrary":"Öğe kütüphaneden silinemedi","confirmAddLibrary":"Bu, kitaplığınıza {{numShapes}} tane şekil ekleyecek. Emin misiniz?","imageDoesNotContainScene":"Bu görüntü herhangi bir sahne verisi içermiyor gibi görünüyor. Dışa aktarma sırasında sahne yerleştirmeyi etkinleştirdiniz mi?","cannotRestoreFromImage":"Sahne bu resim dosyasından geri yüklenemedi","invalidSceneUrl":"Verilen bağlantıdan çalışma alanı yüklenemedi. Dosya bozuk olabilir veya geçerli bir Excalidraw JSON verisi bulundurmuyor olabilir.","resetLibrary":"Bu işlem kütüphanenizi sıfırlayacak. Emin misiniz?","removeItemsFromsLibrary":"{{count}} öğe(ler) kitaplıktan kaldırılsın mı?","invalidEncryptionKey":"Şifreleme anahtarı 22 karakter olmalı. Canlı işbirliği devre dışı bırakıldı.","collabOfflineWarning":"İnternet bağlantısı bulunamadı. Değişiklikleriniz kaydedilmeyecek!"},"errors":{"unsupportedFileType":"Desteklenmeyen dosya türü.","imageInsertError":"Görsel eklenemedi. Daha sonra tekrar deneyin...","fileTooBig":"Dosya çok büyük. İzin verilen maksimum boyut {{maxSize}}.","svgImageInsertError":"SVG resmi eklenemedi. SVG işaretlemesi geçersiz görünüyor.","failedToFetchImage":"","invalidSVGString":"Geçersiz SVG.","cannotResolveCollabServer":"İş birliği sunucusuna bağlanılamıyor. Lütfen sayfayı yenileyip tekrar deneyin.","importLibraryError":"Kütüphane yüklenemedi","collabSaveFailed":"Backend veritabanına kaydedilemedi. Eğer problem devam ederse, çalışmanızı korumak için dosyayı yerel olarak kaydetmelisiniz.","collabSaveFailed_sizeExceeded":"Backend veritabanına kaydedilemedi; tuval çok büyük. Çalışmanızı korumak için dosyayı yerel olarak kaydetmelisiniz.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":"Resimleri kütüphaneye ekleme desteği yakında geliyor!"}},"toolBar":{"selection":"Seçme","image":"Görsel ekle","rectangle":"Dikdörtgen","diamond":"Elmas","ellipse":"Elips","arrow":"Ok","line":"Çizgi","freedraw":"Çiz","text":"Yazı","library":"Kütüphane","lock":"Seçilen aracı çizimden sonra aktif tut","penMode":"Kalem modu - dokunmayı engelle","link":"Seçilen şekil için bağlantı Ekle/Güncelle","eraser":"Silgi","frame":"Çerçeve aracı","embeddable":"Web Yerleştirme","laser":"Lazer işaretçisi","hand":"","extraTools":"Daha fazla araç"},"headings":{"canvasActions":"Tuval eylemleri","selectedShapeActions":"Seçilen şekil aksiyonları","shapes":"Şekiller"},"hints":{"canvasPanning":"","linearElement":"Birden fazla nokta için tıklayın, tek çizgi için sürükleyin","freeDraw":"Tıkla ve sürükle, bitirdiğinde serbest bırak","text":"İpucu: seçme aracıyla herhangi bir yere çift tıklayarak da yazı ekleyebilirsin","embeddable":"Web sitesi yerleştirmek için sürükle bırak","text_selected":"Metni düzenlemek için çift tıklayın veya ENTER\'a basın","text_editing":"Düzenlemeyi bitirmek için ESC veya Ctrl/Cmd+ENTER tuşlarına basın","linearElementMulti":"Bitirmek için son noktaya tıklayın ya da Escape veya Enter tuşuna basın","lockAngle":"SHIFT tuşuna basılı tutarak açıyı koruyabilirsiniz","resize":"Yeniden boyutlandırırken SHIFT tuşunu basılı tutarak oranları sınırlayabilirsiniz,\\nmerkezden yeniden boyutlandırmak için ALT tuşunu basılı tutun","resizeImage":"SHIFT\'e basılı tutarak serbestçe yeniden boyutlandırabilirsiniz, merkezden yeniden boyutlandırmak için ALT tuşunu basılı tutun","rotate":"Döndürürken SHIFT tuşuna basılı tutarak açıları koruyabilirsiniz","lineEditor_info":"Puanları düzenlemek için ctrl veya cmd tuşuna basılı tutup çift tıklayın veya enter tuşuna basın","lineEditor_pointSelected":"Sil tuşuna basarak noktaları silin,\\nCtrl/Cmd + D ile çoğaltın, ya da sürükleyerek taşıyın","lineEditor_nothingSelected":"Düzenlemek için bir nokta seçin (birden fazla seçmek için SHIFT tuşunu basılı tutun),\\nveya Alt tuşunu basılı tutun ve yeni noktalar eklemek için tıklayın","placeImage":"Resmi yerleştirmek için tıklayın ya da boyutunu manuel olarak ayarlamak için tıklayıp sürükleyin","publishLibrary":"Kendi kitaplığınızı yayınlayın","bindTextToElement":"Enter tuşuna basarak metin ekleyin","deepBoxSelect":"Ctrl/Cmd tuşuna basılı tutarak derin seçim yapın ya da sürüklemeyi engelleyin","eraserRevert":"Alt tuşuna basılı tutarak silinme için işaretlenmiş ögeleri tersine çevirin","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"Önizleme gösterilemiyor","canvasTooBig":"Kanvas çok büyük olabilir.","canvasTooBigTip":"İpucu: En uzaktaki elemanları birbirine yakınlaştırmayı deneyin."},"errorSplash":{"headingMain":"Hata oluştu. Lütfen ","clearCanvasMessage":"Yenileme sonrası sorun devam ediyorsa, lütfen ","clearCanvasCaveat":" Bu, yaptığınız değişiklikleri sıfırlayacak ","trackedToSentry":"Tanımlayıcı ile ilgili hata {{eventId}} sistemimize yakalandı.","openIssueMessage":"Sahne bilginizi hata mesajına yansıtmamak için oldukça dikkatli davrandık. Eğer sahneniz gizli değilse hatayı lütfen şuradan takip edin Lütfen aşağıya GitHub sorununa kopyalayarak ve yapıştırarak bilgi ekleyin.","sceneContent":"Sahne içeriği:"},"roomDialog":{"desc_intro":"Çalışma alanınıza, sizinle birlikte çalışabilmeleri için başkalarını da ekleyebilirsiniz.","desc_privacy":"Çalışma ortamında yaptıklarınız ve çizimleriniz uçtan uca şifrelemeyle saklanmaktadır. Sunucularımız dahi bu verileri şifrelenmemiş haliyle göremez.","button_startSession":"Oturumu başlat","button_stopSession":"Oturumu sonlandır","desc_inProgressIntro":"Ortak çalışma ortamı oluşturuldu.","desc_shareLink":"Bu bağlantıyı birlikte çalışacağınız kişilerle paylaşabilirsiniz:","desc_exitSession":"Çalışma ortamını kapattığınızda ortak çalışmadan ayrılmış olursunuz ancak kendi versiyonunuzda çalışmaya devam edebilirsiniz. Bu durumda ortak çalıştığınız diğer kişiler etkilenmeyecek, çalışma ortamındaki versiyon üzerinden çalışmaya devam edebilecekler.","shareTitle":"Excalidraw\'da canlı ortak calışma oturumuna katıl"},"errorDialog":{"title":"Hata"},"exportDialog":{"disk_title":"Belleğe kaydet","disk_details":"Sahne verilerini daha sonra içe aktarabileceğiniz bir dosyaya aktarın.","disk_button":"Dosyaya kaydet","link_title":"Paylaşılabilir bağlantı","link_details":"Salt okunur bir bağlantı olarak dışa aktarın.","link_button":"Bağlantı olarak dışa aktar","excalidrawplus_description":"Sahneyi Excalidraw+ çalışma alanınıza kaydedin.","excalidrawplus_button":"Dışa aktar","excalidrawplus_exportError":"Şu anda Excalidraw+\'a aktarılamadı..."},"helpDialog":{"blog":"Blog\'umuzu okuyun","click":"tıkla","deepSelect":"Derin seçim","deepBoxSelect":"Kutu içerisinde derin seçim yapın, sürüklemeyi engelleyin","curvedArrow":"Eğri ok","curvedLine":"Eğri çizgi","documentation":"Dokümantasyon","doubleClick":"çift-tıklama","drag":"sürükle","editor":"Düzenleyici","editLineArrowPoints":"Çizgi/ok noktalarını düzenle","editText":"Etiket / metin düzenle","github":"Bir hata mı buldun? Bildir","howto":"Rehberlerimizi takip edin","or":"veya","preventBinding":"Ok bağlamayı önleyin","tools":"Araçlar","shortcuts":"Klavye kısayolları","textFinish":"Düzenlemeyi bitir (metin düzenleyici)","textNewLine":"Yeni satır ekle (metin düzenleyici)","title":"Yardım","view":"Görünüm","zoomToFit":"Tüm öğeleri sığdırmak için yakınlaştır","zoomToSelection":"Seçime yakınlaş","toggleElementLock":"Seçimi Kilitle/çöz","movePageUpDown":"Sayfayı yukarı/aşağı kaydır","movePageLeftRight":"Sayfayı sola/sağa kaydır"},"clearCanvasDialog":{"title":"Tuvali temizle"},"publishDialog":{"title":"Kitaplığı yayınla","itemName":"Öğe adı","authorName":"Yazar adı","githubUsername":"GıtHub kullanıcı adı","twitterUsername":"Twitter kullanıcı adı","libraryName":"Kitaplık adı","libraryDesc":"Kitaplık açıklaması","website":"Web sitesi","placeholder":{"authorName":"Adınız ya da kullanıcı adınız","libraryName":"Kitaplığınızın adı","libraryDesc":"İnsanların kullanımını anlamasına yardımcı olmak için kitaplığınızın açıklaması","githubHandle":"Github bağlantısı ( tercihe bağlı), kütüphane gözden geçirme için onaylandığında düzenleyebiliesiniz diye","twitterHandle":"Twitter kullanıcı adı ( tercihe bağlı), bu sayede Twitter üzerinde paylaşıren çalışmanızı size atfedebiliriz","website":"Kişisel web sayfanızı ya da başka bir yeri bağlayın (tercihe bağlı)"},"errors":{"required":"Gerekli","website":"Geçerli bir URL girin"},"noteDescription":"Submit your library to be included in the genel kütüphane reposudiğer insanlar çizimlerinde kullanabilsin diye.","noteGuidelines":"Önce kütüphane elle onaylanmalı. şunu okuyun yönergeler onaylamadan önce. gerekli olması halinde iletişim kurmak için ve değişiklik için Github hesabı gerekli, ama çok da illaki olmalı değil.","noteLicense":"Bunu onaylayarak, kütüğhanenin şu lisansla yayınlanmasını onaylıyorsunuz MIT Lisans, ki bu kısaca herkesin onu kısıtlama olmaksızın kullanabileceği anlamına gelmektedir.","noteItems":"Her kütüphane kendi ismine sahip olmalı ki tarama yapabilelim. Şu kütüphane ögeleri dahil edilecek:","atleastOneLibItem":"Lütfen başlamak için en az bir tane kütüphane ögesi seçin","republishWarning":"Not: seçilen ögelerden bir kısmı zaten yayınlanmış/gönderilmiş. Yalnızca mevcut kütüphane ve gönderileri güncellerken yeniden gönderme işlemi yapmalısınız."},"publishSuccessDialog":{"title":"Kütüphane gönderildi","content":"Teşekkürler {{authorName}}. Kütüphaneniz gözden geçirme için alındı. Durumu takip edebilirsinizburada"},"confirmDialog":{"resetLibrary":"Kütüphaneyi sıfırla","removeItemsFromLib":"Seçilen ögeleri kütüphaneden kaldır"},"imageExportDialog":{"header":"Resmi dışa aktar","label":{"withBackground":"Arka plan","onlySelected":"Sadece seçilen","darkMode":"Karanlık mod","embedScene":"Sahne yerleştir","scale":"Ölçeklendir","padding":"Dış boşluk"},"tooltip":{"embedScene":"Sahne verisi, sahnenin geri yüklenebilmesi için dışarı aktarılan PNG/SVG dosyasına kaydedilecektir. Bu, dışa aktarılan dosya boyutunu arttıracaktır."},"title":{"exportToPng":"PNG olarak dışa aktar","exportToSvg":"SVG olarak dışa aktar","copyPngToClipboard":""},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Panoya kopyala"}},"encrypted":{"tooltip":"Çizimleriniz uçtan-uca şifrelenmiştir, Excalidraw\'ın sunucuları bile onları göremez.","link":"Excalidraw\'da uçtan uca şifreleme hakkında blog yazısı"},"stats":{"angle":"Açı","element":"Bileşen","elements":"Bileşenler","height":"Yükseklik","scene":"Sahne","selected":"Seçili","storage":"Depolama","title":"İnekler için istatistikler","total":"Toplam","version":"Sürüm","versionCopy":"Kopyalamak için tıkla","versionNotAvailable":"Sürüm mevcut değil","width":"Genişlik"},"toast":{"addedToLibrary":"Kütüphaneye eklendi","copyStyles":"Stiller kopyalandı.","copyToClipboard":"Panoya kopyalandı.","copyToClipboardAsPng":"{{exportSelection}} panoya PNG olarak\\n({{exportColorScheme}}) kopyalandı","fileSaved":"Dosya kaydedildi.","fileSavedToFilename":"{filename} kaydedildi","canvas":"tuval","selection":"seçim","pasteAsSingleElement":"Tekil obje olarak yapıştırmak için veya var olan bir metin editörüne yapıştırmak için {{shortcut}} kullanın","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"Şeffaf","black":"Siyah","white":"Beyaz","red":"Kırmızı","pink":"Pembe","grape":"Koyu Mor","violet":"Menekşe rengi","gray":"Gri","blue":"Mavi","cyan":"Camgöbeği","teal":"Deniz mavisi","green":"Yeşil","yellow":"Sarı","orange":"Turuncu","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"Ecalidraw+\'a mı gitmek istediniz?","menuHint":"Dışa aktar, seçenekler, diller, ..."},"defaults":{"menuHint":"Dışa aktar, seçenekler, ve daha fazlası...","center_heading":"","toolbarHint":"Bir araç seçin ve çizime başlayın!","helpHint":"Kısayollar & yardım"}},"colorPicker":{"mostUsedCustomColors":"En çok kullanılan özel renkler","colors":"Renkler","shades":"","hexCode":"Hex kodu","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"Diske Kaydet","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/uk-UA-json-ca6ea1156db2649d3e27.js b/public/excalidraw/excalidraw-assets-dev/locales/uk-UA-json-ca6ea1156db2649d3e27.js
new file mode 100644
index 0000000..ad10deb
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/uk-UA-json-ca6ea1156db2649d3e27.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/uk-UA-json"],{
+
+/***/ "../../locales/uk-UA.json":
+/*!********************************!*\
+ !*** ../../locales/uk-UA.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Вставити","pasteAsPlaintext":"Вставити як простий текст","pasteCharts":"Вставити діаграми","selectAll":"Вибрати все","multiSelect":"Додати елемент до вибраного","moveCanvas":"Перемістити полотно","cut":"Вирізати","copy":"Копіювати","copyAsPng":"Копіювати як PNG","copyAsSvg":"Копіювати як SVG","copyText":"Копіювати в буфер обміну як текст","bringForward":"Перемістити вперед","sendToBack":"На задній план","bringToFront":"На передній план","sendBackward":"Перемістити назад","delete":"Видалити","copyStyles":"Копіювати стилі","pasteStyles":"Вставити стилі","stroke":"Контур","background":"Тло","fill":"Заповнити","strokeWidth":"Товщина контуру","strokeStyle":"Стиль контуру","strokeStyle_solid":"Суцільний","strokeStyle_dashed":"Пунктир","strokeStyle_dotted":"Крапки","sloppiness":"Охайність","opacity":"Прозорість","textAlign":"Вирівнювання тексту","edges":"Краї","sharp":"Гострі","round":"Круглі","arrowheads":"Закінчення стрілки","arrowhead_none":"Жоден","arrowhead_arrow":"Стрілка","arrowhead_bar":"Колона","arrowhead_dot":"Точка","arrowhead_triangle":"Трикутник","fontSize":"Розмір шрифту","fontFamily":"Шрифт","addWatermark":"Додати «Накреслене в Excalidraw»","handDrawn":"Ручний апарат","normal":"Звичайний","code":"Код","small":"Малий","medium":"Середній","large":"Великий","veryLarge":"Дуже великий","solid":"Суцільна","hachure":"Штриховка","zigzag":"Зиґзаґ","crossHatch":"Перехресна штриховка","thin":"Тонкий","bold":"Жирний","left":"Зліва","center":"По центру","right":"Справа","extraBold":"Товстий","architect":"Архітектор","artist":"Художник","cartoonist":"Карикатурист","fileTitle":"Назва файла","colorPicker":"Палітра кольорів","canvasColors":"Використовується на полотні","canvasBackground":"Тло полотна","drawingCanvas":"Полотно","layers":"Шари","actions":"Дії","language":"Мова","liveCollaboration":"Спільна робота наживо...","duplicateSelection":"Дублювати","untitled":"Без назви","name":"Ім’я","yourName":"Ваше ім’я","madeWithExcalidraw":"Накреслене в Excalidraw","group":"Групувати виділене","ungroup":"Розгрупувати виділене","collaborators":"Співавтори","showGrid":"Показати сітку","addToLibrary":"Додати до бібліотеки","removeFromLibrary":"Видалити з бібліотеки","libraryLoadingMessage":"Завантажити бібліотеку…","libraries":"Всі бібліотеки","loadingScene":"Завантаження сцени…","align":"Вирівнювання","alignTop":"Вирівняти по верхньому краю","alignBottom":"Вирівняти по нижньому краю","alignLeft":"Вирівняти по лівому краю","alignRight":"Вирівнювання по правому краю","centerVertically":"Центрувати по вертикалі","centerHorizontally":"Центрувати по горизонталі","distributeHorizontally":"Розподілити по горизонталі","distributeVertically":"Розподілити вертикально","flipHorizontal":"Віддзеркалити горизонтально","flipVertical":"Віддзеркалити вертикально","viewMode":"Режим перегляду","share":"Поділитися","showStroke":"Показати палітру для контура","showBackground":"Показати палітру для фону","toggleTheme":"Перемкнути тему","personalLib":"Персональна бібліотека","excalidrawLib":"Бібліотека Excalidraw","decreaseFontSize":"Зменшити розмір шрифту","increaseFontSize":"Збільшити розмір шрифту","unbindText":"Відв\'язати текст","bindText":"Прив’язати текст до контейнера","createContainerFromText":"Огорнути текст у контейнер","link":{"edit":"Редагування посилання","editEmbed":"Редагування посилання і вкладення","create":"Створити посилання","createEmbed":"Створити посилання і вкладення","label":"Посилання","labelEmbed":"Посилання і вкладення","empty":"Посилання відсутнє"},"lineEditor":{"edit":"Редагувати лінію","exit":"Закінчити редагування лінії"},"elementLock":{"lock":"Блокувати","unlock":"Розблокувати","lockAll":"Заблокувати все","unlockAll":"Розблокувати все"},"statusPublished":"Опубліковано","sidebarLock":"Не закривати бокове меню","selectAllElementsInFrame":"Обрати всі елементи у фреймі","removeAllElementsFromFrame":"Видалити всі елементи з фрейму","eyeDropper":"Вибрати колір з полотна"},"library":{"noItems":"Тут поки пусто...","hint_emptyLibrary":"Виберіть об\'єкт на полотні, щоб додати його сюди або встановіть бібліотеку з публічного репозиторію, що нижче.","hint_emptyPrivateLibrary":"Виберіть елемент на полотні, щоб додати його сюди."},"buttons":{"clearReset":"Очистити полотно","exportJSON":"Експорт у файл","exportImage":"Експорт зображення...","export":"Зберегти як...","copyToClipboard":"Скопіювати до буферу обміну","save":"Зберегти до поточного файлу","saveAs":"Зберегти як","load":"Відкрити","getShareableLink":"Отримати посилання","close":"Закрити","selectLanguage":"Обрати мову","scrollBackToContent":"Повернутися до вмісту","zoomIn":"Збільшити","zoomOut":"Зменшити","resetZoom":"Скинути масштаб","menu":"Меню","done":"Готово","edit":"Редагувати","undo":"Відмінити","redo":"Повторити","resetLibrary":"Очистити бібліотеку","createNewRoom":"Створити нову кімнату","fullScreen":"Повноекранний режим","darkMode":"Темна тема","lightMode":"Світла тема","zenMode":"Режим Дзен","objectsSnapMode":"","exitZenMode":"Вийти з дзен-режиму","cancel":"Скасувати","clear":"Очистити","remove":"Видалити","embed":"Перемкнути вкладення","publishLibrary":"Опублікувати","submit":"Надіслати","confirm":"Підтвердити","embeddableInteractionButton":"Натисніть для взаємодії"},"alerts":{"clearReset":"Це очистить все полотно. Впевнені?","couldNotCreateShareableLink":"Не вдалося створити посилання.","couldNotCreateShareableLinkTooBig":"Не вдалося створити посилання для обміну: сцена занадто велика","couldNotLoadInvalidFile":"Файл з помилками не відкрився","importBackendFailed":"Імпортування невдале.","cannotExportEmptyCanvas":"Не вийшло експортувати пусте полотно.","couldNotCopyToClipboard":"Не вдалося скопіювати до буфера обміну.","decryptFailed":"Не вдалося розшифрувати дані.","uploadedSecurly":"Це завантаження було захищене наскрізним шифруванням, а це означає що сервер Excalidraw та інші не зможуть прочитати вміст.","loadSceneOverridePrompt":"Завантаження зовнішнього креслення замінить ваш наявний контент. Продовжити?","collabStopOverridePrompt":"Зупинка сесії перезапише ваш попередній, локально збережений малюнок. Ви впевнені?\\n\\n(Якщо ви хочете зберегти локальний малюнок, просто закрийте замість нього вкладку браузера.)","errorAddingToLibrary":"Не вдалося додати елемент до бібліотеки","errorRemovingFromLibrary":"Не вдалося видалити елемент з бібліотеки","confirmAddLibrary":"Це призведе до додавання {{numShapes}} фігур до вашої бібліотеки. Ви впевнені?","imageDoesNotContainScene":"Виглядає ніби зображення не містить корисної інформації. Ви увімкнули вбудовування сцени при експорті?","cannotRestoreFromImage":"Сцена не може бути відновлена з цього файлу зображення","invalidSceneUrl":"Не вдалося імпортувати сцену з наданого URL. Він або недоформований, або не містить дійсних даних Excalidraw JSON.","resetLibrary":"Це призведе до очищення бібліотеки. Ви впевнені?","removeItemsFromsLibrary":"Видалити {{count}} елемент(ів) з бібліотеки?","invalidEncryptionKey":"Ключ шифрування повинен бути довжиною до 22 символів. Спільну роботу вимкнено.","collabOfflineWarning":"Немає підключення до Інтернету.\\nВаші зміни не будуть збережені!"},"errors":{"unsupportedFileType":"Непідтримуваний тип файлу.","imageInsertError":"Не вдалося вставити зображення. Повторіть спробу пізніше...","fileTooBig":"Занадто великий розмір файлу, максимальний розмір файлу {{maxSize}}.","svgImageInsertError":"Не вдалося вставити SVG-зображення. Помилка розмітки SVG.","failedToFetchImage":"","invalidSVGString":"Недійсний SVG.","cannotResolveCollabServer":"Не вдалося приєднатися до сервера. Перезавантажте сторінку та повторіть спробу.","importLibraryError":"Не вдалося завантажити бібліотеку","collabSaveFailed":"Не вдалося зберегти у базу даних сервера. Якщо проблеми не зникнуть, Вам слід зберегти файл локально, щоб не втратити роботу.","collabSaveFailed_sizeExceeded":"Полотно завелике! Не вдалося зберегти у базу даних сервера. Вам слід зберегти файл локально, щоб не втратити свою роботу.","brave_measure_text_error":{"line1":"Ви використовуєте браузер Brave з увімкненим налаштуванням Агресивного Блокування Розпізнавання Пристрою.","line2":"Це може нашкодити текстовим елементам у ваших малюнках.","line3":"Ми наполегливо рекомендуємо вимкнути це налаштування. Виконайте наступні кроки, щоб виправити це.","line4":"Якщо вимкнення цього параметра не вирішує показ текстових елементів, тоді створіть, будь ласка, запит на розв\'язання проблеми на нашому GitHub або напишіть нам у Discord"},"libraryElementTypeError":{"embeddable":"Вбудовані елементи не можна додати в бібліотеку.","image":"Підтримка додавання зображень в бібліотеку найближчим часом!"}},"toolBar":{"selection":"Виділення","image":"Вставити зображення","rectangle":"Прямокутник","diamond":"Ромб","ellipse":"Еліпс","arrow":"Стрілка","line":"Лінія","freedraw":"Малювати","text":"Текст","library":"Бібліотека","lock":"Залишити обраний інструмент після креслення","penMode":"Режим пера - запобігання дотику","link":"Додати/Оновити посилання для вибраної форми","eraser":"Очищувач","frame":"Інструмент фрейму","embeddable":"Веб вкладення","laser":"","hand":"Рука (інструмент для панорамування)","extraTools":"Інші інструменти"},"headings":{"canvasActions":"Дії з полотном","selectedShapeActions":"Вибрані дії з фігурою","shapes":"Фігури"},"hints":{"canvasPanning":"Щоб перемістити полотно, утримуйте коліщатко миші або пробіл під час перетягування, або скористайтеся інструментом Рука","linearElement":"Натисніть щоб додати кілька точок. Перетягніть щоб намалювати одну лінію","freeDraw":"Натисніть і потягніть, відпустіть коли завершите","text":"Порада: можна також додати текст, двічі клацнувши по будь-якому місці інструментом вибору","embeddable":"Клікніть та перетягніть для створення вбудованого вебсайту","text_selected":"Подвійний клік або натисніть клавішу ENTER, щоб редагувати текст","text_editing":"Натисніть клавішу Escape або Ctrl/Cmd+ENTER, щоб завершити редагування","linearElementMulti":"Натисніть на останню точку, клацніть Esc або Enter щоб завершити","lockAngle":"Ви можете обмежити кут, утримуюючи SHIFT","resize":"Ви можете зберегти пропорції, утримуючи SHIFT під час зміни розміру,\\nутримуйте ALT для змінення розміру від центру","resizeImage":"Ви можете змінювати розміри утримуючи клавішу SHIFT, втримуйте клавішу ALT щоб змінювати розмір відносно центру","rotate":"Ви можете обмежити кути, утримуючи SHIFT під час обертання","lineEditor_info":"Утримуйте CtrlOrCmd і двічі клацніть або натисніть CtrlOrCmd + Enter, щоб редагувати цятки","lineEditor_pointSelected":"Натисніть Delete для видалення точку (точок), або Ctrl/Cmd+D для дублювання, перетаскування працює як звично","lineEditor_nothingSelected":"Виберіть точку для редагування (втримуйте клавішу SHIFT для вибору кількох точок), або клавішу Alt для додавання нових точок","placeImage":"Клацніть, щоб розмістити зображення, або натисніть та потягніть щоб змінити його розмір","publishLibrary":"Опублікувати свою власну бібліотеку","bindTextToElement":"Натисніть Enter, щоб додати текст","deepBoxSelect":"Втримуйте Ctrl/Cmd для глибокого виділення та щоб попередити перетягування","eraserRevert":"Втримуйте клавішу Alt, щоб повернути елементи позначені для видалення","firefox_clipboard_write":"Цю функцію можна ввімкнути, встановивши значення \\"true\\" для налаштування \\"dom.events.asyncClipboard.clipboardItem\\". Перейдіть на сторінку «about:config», щоб змінити налаштування браузера у Firefox.","disableSnapping":""},"canvasError":{"cannotShowPreview":"Не вдається показати попередній перегляд","canvasTooBig":"Полотно може бути завеликим.","canvasTooBigTip":"Порада: спробуйте підсунути найвіддаленіші елементи ближче один до одного."},"errorSplash":{"headingMain":"Сталася помилка. Спробуйте ","clearCanvasMessage":"Якщо перезавантаження не допоможе, спробуйте ","clearCanvasCaveat":" Це призведе до втрати роботи ","trackedToSentry":"Помилка з ідентифікатором {{eventId}} було відслідковано в нашій системі.","openIssueMessage":"Ми були дуже обережні, щоб не включати інформацію про ваші сцени в текст помилки. Якщо ваша сцена не була приватна, будь ласка, розгляньте можливість продовження на нашому Будь ласка, додайте інформацію нижче, скопіюючи і вставляючи у GitHub issue.","sceneContent":"Вміст сцени:"},"roomDialog":{"desc_intro":"Ви можете запросити людей для спільної роботи.","desc_privacy":"Не хвилюйтеся, сесія захищена наскрізним шифруванням, тому ваше креслення залишиться приватним. Навіть наш сервер не побачить вашу роботу.","button_startSession":"Почати сесію","button_stopSession":"Закрити сесію","desc_inProgressIntro":"Сесія спільної роботи над кресленням триває.","desc_shareLink":"Поділіться цим посиланням з будь-ким для спільної роботи:","desc_exitSession":"Зупинка сесії відключить вас від кімнати, але ви зможете продовжити роботу з полотном локально. Зверніть увагу, що це не вплине на інших людей, і вони все одно зможуть працювати над їх версією.","shareTitle":"Приєднатися до сеансу спільної роботи на Excalidraw"},"errorDialog":{"title":"Помилка"},"exportDialog":{"disk_title":"Зберегти на диск","disk_details":"Експорт даних сцени в файл, з якого можна імпортувати пізніше.","disk_button":"Зберегти до файлу","link_title":"Доступ за посиланням","link_details":"Експортувати як посилання тільки для читання.","link_button":"Експортувати у посилання","excalidrawplus_description":"Збережіть сцену у вашому обліковому записі Excalidraw+.","excalidrawplus_button":"Експортувати","excalidrawplus_exportError":"Не вдалося експортувати у Excalidraw+..."},"helpDialog":{"blog":"Наш блог","click":"натиснути","deepSelect":"Глибокий вибір","deepBoxSelect":"Глибоке виділення в межах рамки, та обмеження перетягування","curvedArrow":"Крива стрілка","curvedLine":"Крива лінія","documentation":"Документація","doubleClick":"подвійний клік","drag":"перетягнути","editor":"Редактор","editLineArrowPoints":"Редагувати лінію/стрілки","editText":"Редагувати текст / додати позначку","github":"Знайшли помилку? Повідомте","howto":"Дотримуйтесь наших інструкцій","or":"або","preventBinding":"Запобігти зв\'язування зі стрілками","tools":"Інструменти","shortcuts":"Гарячі клавіші","textFinish":"Завершити редагування (текстовий редактор)","textNewLine":"Додати новий рядок (текстовий редактор)","title":"Допомога","view":"Вигляд","zoomToFit":"Збільшити щоб умістити всі елементи","zoomToSelection":"Наблизити вибране","toggleElementLock":"Заблокувати/розблокувати вибране","movePageUpDown":"Пересунути сторінку вгору/вниз","movePageLeftRight":"Пересунути сторінку вліво/вправо"},"clearCanvasDialog":{"title":"Очистити полотно"},"publishDialog":{"title":"Опублікувати бібліотеку","itemName":"Назва елементу","authorName":"Ім\'я автора","githubUsername":"Ім\'я користувача Github","twitterUsername":"Ім\'я користувача Твитер","libraryName":"Назва бібліотеки","libraryDesc":"Опис бібліотеки","website":"Вебсайт","placeholder":{"authorName":"Ваше ім\'я або ім\'я користувача","libraryName":"Назва вашої бібліотеки","libraryDesc":"Опис вашої бібліотеки, щоб допомогти людям зрозуміти її використання","githubHandle":"Ім\'я користувача в GitHub (необов\'язково), щоб ви могли редагувати бібліотеку під час перевірки","twitterHandle":"Ім\'я користувача у Twitter (необов\'язково), щоб ми могли згадати вас під час промоції у Twitter","website":"Посилання на ваш особистий сайт або інший сайт (опціонально)"},"errors":{"required":"Обов’язково","website":"Введіть дійсну URL-адресу"},"noteDescription":"Подати бібліотеку, щоб вона була включена до публічного репозиторія бібліотекдля інших людей, для використання у їхніх полотнах.","noteGuidelines":"Спочатку бібліотека повинна бути підтверджена. Будь ласка, прочитайте настанови перед відправкою. Вам знадобиться обліковий запис на GitHub, щоб колаборувати та вносити зміни, але це не обов\'язково.","noteLicense":"Публікуючи, ви погоджуєтеся, що бібліотека буде опублікована під Ліцензія MIT, , простими словами, це означає що нею зможе користуватися будь-хто без обмежень.","noteItems":"Кожен об\'єкт в бібліотеці повинен мати назву, це потрібно для пошуку та фільтрування. Наступні об\'єкти бібліотеки будуть включені:","atleastOneLibItem":"Будь ласка, виберіть принаймні один елемент бібліотеки, щоб почати","republishWarning":"Зауважте, деякі з вибраних елементів позначені як вже опубліковані/надіслані. Ви повинні повторно надсилати елементи тільки при оновленні вже опублікованої бібліотеки чи при публікації бібліотеки."},"publishSuccessDialog":{"title":"Бібліотека відправлена","content":"Дякуємо, {{authorName}}. Ваша бібліотека була відправлена для розгляду. Ви можете відстежувати статустут"},"confirmDialog":{"resetLibrary":"Очистити бібліотеку","removeItemsFromLib":"Видалити вибрані елементи з бібліотеки"},"imageExportDialog":{"header":"Експортувати зображення","label":{"withBackground":"Тло","onlySelected":"Тільки вибране","darkMode":"Темний режим","embedScene":"Вбудована сцена","scale":"Масштабування","padding":"Відступ"},"tooltip":{"embedScene":"Дані сцени будуть збережені в експортований файл PNG/SVG. Ця сцена може бути відновлена з нього, однак це збільшить розмір експортованого файлу."},"title":{"exportToPng":"Експортувати в PNG","exportToSvg":"Експортувати у SVG","copyPngToClipboard":"Скопіювати PNG в буфер обміну"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"Копіювати в буфер обміну"}},"encrypted":{"tooltip":"Ваші креслення захищені наскрізним шифруванням — сервери Excalidraw ніколи їх не побачать.","link":"Допис у блозі на наскрізному шифруванні в Excalidraw"},"stats":{"angle":"Кут","element":"Елемент","elements":"Елементи","height":"Висота","scene":"Сцена","selected":"Обрано","storage":"Сховище","title":"Статистика","total":"Всього","version":"Версія","versionCopy":"Натисніть, щоб скопіювати","versionNotAvailable":"Версія недоступна","width":"Ширина"},"toast":{"addedToLibrary":"Додано до бібліотеки","copyStyles":"Скопійовані стилі.","copyToClipboard":"Скопіювати до буферу обміну.","copyToClipboardAsPng":"Скопійовано {{exportSelection}} до буфера обміну як PNG\\n({{exportColorScheme}})","fileSaved":"Файл збережено.","fileSavedToFilename":"Збережено в {filename}","canvas":"полотно","selection":"виділення","pasteAsSingleElement":"Використайте {{shortcut}} для вставки самостійного зразка або використайте в текстовому редакторі","unableToEmbed":"Вбудування цієї url на даний час не допускається. Підніміть питання на GitHub, щоб попросити внести URL-адресу до білого списку","unrecognizedLinkFormat":"Посилання, яке ви вставили, не відповідає очікуваному формату. Будь ласка, спробуйте вставити рядок \\"embed\\", наданий сайтом-джерелом"},"colors":{"transparent":"Прозорий","black":"Чорний","white":"Білий","red":"Червоний","pink":"Рожевий","grape":"Виноградний","violet":"Фіолетовий","gray":"Сірий","blue":"Синій","cyan":"Ціан","teal":"Бірюзовий","green":"Зелений","yellow":"Жовтий","orange":"Помаранчевий","bronze":"Бронзовий"},"welcomeScreen":{"app":{"center_heading":"Всі ваші дані збережено локально у Вашому браузері.","center_heading_plus":"Чи бажаєте перейти до Excalidraw+?","menuHint":"Експорт, налаштування, мови, ..."},"defaults":{"menuHint":"Експорт, налаштування та багато іншого...","center_heading":"Діаграми. Робити. Просто.","toolbarHint":"Оберіть інструмент і почніть малювати!","helpHint":"Гарячі клавіші і допомога"}},"colorPicker":{"mostUsedCustomColors":"Найбільш використовувані користувацькі кольори","colors":"Кольори","shades":"Тіні","hexCode":"Hex-код","noShades":"Немає доступних відтінків цього кольору"},"overwriteConfirm":{"action":{"exportToImage":{"title":"Експортувати як зображення","button":"Експортувати як зображення","description":"Експорт даних сцени у вигляді зображення, з якого можна імпортувати пізніше."},"saveToDisk":{"title":"Зберегти на диск","button":"Зберегти на диск","description":"Експорт даних сцени в файл, з якого можна імпортувати пізніше."},"excalidrawPlus":{"title":"Excalidraw+","button":"Експортувати до Excalidraw+","description":"Зберегти сцену до робочого простору Excalidraw+."}},"modal":{"loadFromFile":{"title":"Завантажити з файлу","button":"Завантажити з файлу","description":"Завантаження з файлу замінить наявний вміст. Ви можете спочатку створити резервну копію малюнка, скориставшись одним із наведених нижче способів."},"shareableLink":{"title":"Завантажити з посилання","button":"Замінити мій контент","description":"Завантаження зовнішнього малюнка замінить ваш наявний вміст. Ви можете спочатку створити резервну копію малюнка, скориставшись одним із наведених нижче способів."}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/vi-VN-json-9a5e5fab41a1a120a916.js b/public/excalidraw/excalidraw-assets-dev/locales/vi-VN-json-9a5e5fab41a1a120a916.js
new file mode 100644
index 0000000..efe2a59
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/vi-VN-json-9a5e5fab41a1a120a916.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/vi-VN-json"],{
+
+/***/ "../../locales/vi-VN.json":
+/*!********************************!*\
+ !*** ../../locales/vi-VN.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"Dán","pasteAsPlaintext":"Dán kiểu văn bản thuần","pasteCharts":"Dán biểu đồ","selectAll":"Chọn tất cả","multiSelect":"Thêm mới vào Select","moveCanvas":"Di chuyển canvas","cut":"Cắt","copy":"Sao chép","copyAsPng":"Sao chép vào bộ nhớ tạm dưới dạng PNG","copyAsSvg":"Sao chép vào bộ nhớ tạm dưới dạng SVG","copyText":"Sao chép vào bộ nhớ tạm dưới dạng chữ","bringForward":"Đưa ra trước","sendToBack":"Hạ xuống dưới","bringToFront":"Đưa ra đầu tiên","sendBackward":"Hạ xuống cuối","delete":"Xóa","copyStyles":"Sao chép định dạng","pasteStyles":"Dán định dạng","stroke":"Nét","background":"Nền","fill":"Fill","strokeWidth":"Độ dày nét","strokeStyle":"Kiểu nét","strokeStyle_solid":"Khối","strokeStyle_dashed":"Gạch ngang","strokeStyle_dotted":"Nhiều chấm","sloppiness":"Hoa văn nét","opacity":"Độ trong suốt","textAlign":"Căn chỉnh văn bản","edges":"Cạnh","sharp":"Nhọn","round":"Tròn","arrowheads":"Đầu mũi tên","arrowhead_none":"Không","arrowhead_arrow":"Mũi tên","arrowhead_bar":"Thanh","arrowhead_dot":"Chấm","arrowhead_triangle":"Tam giác","fontSize":"Cỡ chữ","fontFamily":"Phông chữ","addWatermark":"Làm với Excalidraw\\"","handDrawn":"Vẽ tay","normal":"Bình thường","code":"Mã","small":"Nhỏ","medium":"Vừa","large":"Lớn","veryLarge":"Rất lớn","solid":"Đặc","hachure":"Nét gạch gạch","zigzag":"Zigzag","crossHatch":"Nét gạch chéo","thin":"Mỏng","bold":"In đậm","left":"Trái","center":"Giữa","right":"Phải","extraBold":"Nét siêu đậm","architect":"Kiến trúc sư","artist":"Nghệ sỹ","cartoonist":"Hoạt hình","fileTitle":"Tên tập tin","colorPicker":"Chọn màu","canvasColors":"Đã dùng trên canvas","canvasBackground":"Nền canvas","drawingCanvas":"Canvas vẽ","layers":"Lớp","actions":"Chức năng","language":"Ngôn ngữ","liveCollaboration":"Hợp tác trực tiếp...","duplicateSelection":"Tạo bản sao","untitled":"Không có tiêu đề","name":"Tên","yourName":"Tên của bạn","madeWithExcalidraw":"Làm với Excalidraw","group":"Gộp nhóm lại lựa chọn","ungroup":"Tách nhóm lựa chọn","collaborators":"Cộng tác viên","showGrid":"Hiển thị lưới","addToLibrary":"Thêm vào thư viện","removeFromLibrary":"Xóa khỏi thư viện","libraryLoadingMessage":"Đang tải thư viện…","libraries":"Xem thư viện","loadingScene":"Đang tải về…","align":"Căn chỉnh","alignTop":"Căn trên","alignBottom":"Căn dưới","alignLeft":"Canh trái","alignRight":"Canh phải","centerVertically":"Giữa theo chiều dọc","centerHorizontally":"Giữa theo chiều ngang","distributeHorizontally":"Phân bố theo chiều ngang","distributeVertically":"Phân bố theo chiều dọc","flipHorizontal":"Lật ngang","flipVertical":"Lật dọc","viewMode":"Chế độ xem","share":"Chia sẻ","showStroke":"Hiển thị chọn màu","showBackground":"Hiện thị chọn màu nền","toggleTheme":"","personalLib":"Thư viện cá nhân","excalidrawLib":"Thư viện Excalidraw","decreaseFontSize":"Giảm cỡ chữ","increaseFontSize":"Tăng cỡ chữ","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"Sửa liên kết","editEmbed":"","create":"Tạo liên kết","createEmbed":"","label":"Liên kết","labelEmbed":"","empty":""},"lineEditor":{"edit":"Điều chỉnh nét","exit":"Thoát chỉnh nét"},"elementLock":{"lock":"Khoá","unlock":"Mở khoá","lockAll":"Khóa tất cả","unlockAll":"Mở khóa tất cả"},"statusPublished":"Đã đăng tải","sidebarLock":"Giữ thanh bên luôn mở","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"Chưa có món nào...","hint_emptyLibrary":"Chọn một món trên canvas để thêm nó vào đây, hoặc cài đặt thư viện từ kho lưu trữ công cộng, ở bên dưới.","hint_emptyPrivateLibrary":"Chọn một món trên canvas để thêm nó vào đây."},"buttons":{"clearReset":"Reset canvas","exportJSON":"Xuất ra tập tin","exportImage":"Xuất file ảnh...","export":"Lưu vào...","copyToClipboard":"Sao chép vào bộ nhớ tạm","save":"Lưu vào tập tin hiện tại","saveAs":"Lưu thành","load":"Mở","getShareableLink":"Tạo liên kết để chia sẻ","close":"Đóng","selectLanguage":"Chọn ngôn ngữ","scrollBackToContent":"Cuộn về nội dung chính","zoomIn":"Phóng to","zoomOut":"Thu nhỏ","resetZoom":"Đặt lại thu phóng","menu":"Bảng chọn","done":"Xong","edit":"Chỉnh sửa","undo":"Hoàn tác","redo":"Làm lại","resetLibrary":"","createNewRoom":"Tạo phòng mới","fullScreen":"Toàn màn hình","darkMode":"Chế độ tối","lightMode":"Chế độ sáng","zenMode":"Chế độ zen","objectsSnapMode":"","exitZenMode":"Thoát chể độ zen","cancel":"Hủy","clear":"Làm sạch","remove":"Xóa","embed":"","publishLibrary":"Đăng tải","submit":"Gửi","confirm":"Xác nhận","embeddableInteractionButton":""},"alerts":{"clearReset":"Điều này sẽ dọn hết canvas. Bạn có chắc không?","couldNotCreateShareableLink":"Không thể tạo đường dẫn chia sẻ.","couldNotCreateShareableLinkTooBig":"Không thể tạo đường dẫn chia sẻ: bản vẽ quá lớn","couldNotLoadInvalidFile":"Không thể load tập tin không hợp lệ","importBackendFailed":"","cannotExportEmptyCanvas":"Không thể xuất canvas trống.","couldNotCopyToClipboard":"","decryptFailed":"Không thể giải mã dữ liệu.","uploadedSecurly":"","loadSceneOverridePrompt":"","collabStopOverridePrompt":"Dừng phiên sẽ ghi đè lên bản vẽ được lưu trữ cục bộ trước đó của bạn. Bạn có chắc không?\\n\\n(Nếu bạn muốn giữ bản vẽ cục bộ của mình, chỉ cần đóng tab trình duyệt.)","errorAddingToLibrary":"Không thể thêm món vào thư viện","errorRemovingFromLibrary":"Không thể xoá món khỏi thư viện","confirmAddLibrary":"Hình {{numShapes}} sẽ được thêm vào thư viện. Bạn chắc chứ?","imageDoesNotContainScene":"Hình ảnh này dường như không chứa bất kỳ dữ liệu cảnh nào. Bạn đã bật tính năng nhúng cảnh khi xuất chưa?","cannotRestoreFromImage":"","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"Xoá {{count}} món từ thư viện?","invalidEncryptionKey":"Khóa mã hóa phải có 22 ký tự. Hợp tác trực tiếp bị vô hiệu hóa.","collabOfflineWarning":"Không có kết nối internet.\\nThay đổi của bạn sẽ không được lưu!"},"errors":{"unsupportedFileType":"Loại tập tin không được hỗ trợ.","imageInsertError":"Không thể thêm ảnh. Hãy thử lại sau...","fileTooBig":"Tệp tin quá lớn. Dung lượng tối đa cho phép là {{maxSize}}.","svgImageInsertError":"Không thể thêm ảnh SVG. Mã SVG có vẻ sai.","failedToFetchImage":"","invalidSVGString":"SVG không hợp lệ.","cannotResolveCollabServer":"Không thể kết nối với máy chủ hợp tác. Hãy tải lại trang và thử lại.","importLibraryError":"Không thể tải thư viện","collabSaveFailed":"Không thể lưu vào cơ sở dữ liệu. Nếu vấn đề tiếp tục xảy ra, bạn nên lưu tệp vào máy để đảm bảo bạn không bị mất công việc.","collabSaveFailed_sizeExceeded":"Không thể lưu vào cơ sở dữ liệu, canvas có vẻ quá lớn. Bạn nên lưu tệp cục bộ để đảm bảo bạn không bị mất công việc.","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"Lựa chọn","image":"Chèn ảnh","rectangle":"Hình chữ nhật","diamond":"Kim cương","ellipse":"Hình elíp","arrow":"Mũi tên","line":"Đường kẻ","freedraw":"Vẽ","text":"Văn bản","library":"Thư viện","lock":"Giữ dụng cũ hiện tại sau khi vẽ","penMode":"Chế độ bút vẽ - ngăn ngừa chạm nhầm","link":"Thêm/ Chỉnh sửa liên kết cho hình được chọn","eraser":"Xóa","frame":"","embeddable":"","laser":"","hand":"Tay kéo","extraTools":""},"headings":{"canvasActions":"Hành động canvas","selectedShapeActions":"Các hành động cho hình dạng đã chọn","shapes":"Các hình khối"},"hints":{"canvasPanning":"Để di chuyển canvas, giữ con lăn chuột hoặc phím cách trong khi kéo, hoặc sử dụng công cụ cầm tay","linearElement":"Ấn để bắt đầu nhiểm điểm vẽ, kéo để vẽ một đường thẳng","freeDraw":"Ấn bà kéo, thả khi bạn xong","text":"Mẹo: bạn có thể thêm văn bản tại bất cứ đâu bằng cách ấn hai lần bằng tool lựa chọn","embeddable":"","text_selected":"Ấn 2 lần hoặc nhấn ENTER để chỉnh văn bản","text_editing":"Nhấn Escape hoặc Ctrl/Cmd+ENTER để hoàn thành chỉnh sửa","linearElementMulti":"Nhấn vào điểm cuối hoặc nhấn Escape hoặc Enter để kết thúc","lockAngle":"Bạn có thể chỉnh lại góc bằng cách giữ phím SHIFT","resize":"Bạn có thể chỉnh tỷ lệ bằng cách giữ SHIFT khi chỉnh kích cỡ,\\ngiữ ALT để chỉnh kích cỡ từ trung tâm","resizeImage":"","rotate":"","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"Tính năng này có thể được bật bằng cách đặt cờ \\"dom.events.asyncClipboard.clipboardItem\\" thành \\"true\\". Để thay đổi cờ trình duyệt trong Firefox, hãy truy cập trang \\"about:config\\".","disableSnapping":""},"canvasError":{"cannotShowPreview":"Không thể xem trước","canvasTooBig":"Canvas này có thể hơi lớn.","canvasTooBigTip":"Mẹo: hãy thử di chuyển các elements nhất lại gần nhau hơn một chút."},"errorSplash":{"headingMain":"","clearCanvasMessage":"Nếu không tải lại được, hãy thử ","clearCanvasCaveat":" Điều này sẽ dẫn đến mất dữ liệu bạn đã làm ","trackedToSentry":"","openIssueMessage":"","sceneContent":""},"roomDialog":{"desc_intro":"","desc_privacy":"","button_startSession":"","button_stopSession":"","desc_inProgressIntro":"","desc_shareLink":"","desc_exitSession":"","shareTitle":""},"errorDialog":{"title":""},"exportDialog":{"disk_title":"","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"","excalidrawplus_exportError":""},"helpDialog":{"blog":"","click":"","deepSelect":"","deepBoxSelect":"","curvedArrow":"","curvedLine":"","documentation":"","doubleClick":"","drag":"","editor":"","editLineArrowPoints":"","editText":"","github":"","howto":"","or":"","preventBinding":"","tools":"","shortcuts":"","textFinish":"","textNewLine":"","title":"","view":"","zoomToFit":"","zoomToSelection":"","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":"Dọn canvas"},"publishDialog":{"title":"","itemName":"Tên món","authorName":"","githubUsername":"","twitterUsername":"","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"Từng món trong thư viện phải có tên riêng để có thể lọc. Các món thư viện sau đây sẽ thêm:","atleastOneLibItem":"Vui lòng chọn ít nhất một món thư viện để bắt đầu","republishWarning":"Lưu ý: một số món đã chọn được đánh dấu là đã xuất bản/đã gửi. Bạn chỉ nên gửi lại các món khi cập nhật thư viện hiện có hoặc gửi."},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":"Xóa món đã chọn khỏi thư viện"},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"","link":""},"stats":{"angle":"","element":"","elements":"","height":"","scene":"","selected":"","storage":"","title":"","total":"","version":"","versionCopy":"","versionNotAvailable":"","width":""},"toast":{"addedToLibrary":"","copyStyles":"","copyToClipboard":"","copyToClipboardAsPng":"","fileSaved":"","fileSavedToFilename":"","canvas":"canvas","selection":"","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/zh-CN-json-670c28a6ae1e3ddecaa4.js b/public/excalidraw/excalidraw-assets-dev/locales/zh-CN-json-670c28a6ae1e3ddecaa4.js
new file mode 100644
index 0000000..983715c
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/zh-CN-json-670c28a6ae1e3ddecaa4.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/zh-CN-json"],{
+
+/***/ "../../locales/zh-CN.json":
+/*!********************************!*\
+ !*** ../../locales/zh-CN.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"粘贴","pasteAsPlaintext":"粘贴为纯文本","pasteCharts":"粘贴图表","selectAll":"全部选中","multiSelect":"添加元素到选区","moveCanvas":"移动画布","cut":"剪切","copy":"拷贝","copyAsPng":"复制为 PNG 到剪贴板","copyAsSvg":"复制为 SVG 到剪贴板","copyText":"复制文本到剪贴板","bringForward":"上移一层","sendToBack":"置于底层","bringToFront":"置于顶层","sendBackward":"下移一层","delete":"删除","copyStyles":"拷贝样式","pasteStyles":"粘贴样式","stroke":"描边","background":"背景","fill":"填充","strokeWidth":"描边宽度","strokeStyle":"边框样式","strokeStyle_solid":"实线","strokeStyle_dashed":"虚线","strokeStyle_dotted":"点虚线","sloppiness":"线条风格","opacity":"透明度","textAlign":"文本对齐","edges":"边角","sharp":"尖锐","round":"圆润","arrowheads":"端点","arrowhead_none":"无","arrowhead_arrow":"箭头","arrowhead_bar":"条状","arrowhead_dot":"圆点","arrowhead_triangle":"三角箭头","fontSize":"字体大小","fontFamily":"字体","addWatermark":"添加 “使用 Excalidraw 创建” 水印","handDrawn":"手写","normal":"普通","code":"代码","small":"小","medium":"中","large":"大","veryLarge":"加大","solid":"实心","hachure":"线条","zigzag":"之字形折线","crossHatch":"交叉线条","thin":"细","bold":"粗","left":"左对齐","center":"居中","right":"右对齐","extraBold":"特粗","architect":"朴素","artist":"艺术","cartoonist":"漫画家","fileTitle":"文件名","colorPicker":"取色器","canvasColors":"画布上的","canvasBackground":"画布背景","drawingCanvas":"绘制 Canvas","layers":"图层","actions":"操作","language":"语言","liveCollaboration":"实时协作...","duplicateSelection":"复制","untitled":"无标题","name":"名字","yourName":"您的姓名","madeWithExcalidraw":"使用 Excalidraw 创建","group":"编组","ungroup":"解除编组","collaborators":"协作者","showGrid":"显示网格","addToLibrary":"添加到素材库中","removeFromLibrary":"从素材库中移除","libraryLoadingMessage":"正在加载素材库…","libraries":"浏览素材库","loadingScene":"正在加载绘图…","align":"对齐","alignTop":"顶部对齐","alignBottom":"底端对齐","alignLeft":"左对齐","alignRight":"右对齐","centerVertically":"垂直居中","centerHorizontally":"水平居中","distributeHorizontally":"水平等距分布","distributeVertically":"垂直等距分布","flipHorizontal":"水平翻转","flipVertical":"垂直翻转","viewMode":"查看模式","share":"分享","showStroke":"显示描边颜色选择器","showBackground":"显示背景颜色选择器","toggleTheme":"切换主题","personalLib":"个人素材库","excalidrawLib":"Excalidraw 素材库","decreaseFontSize":"缩小字体大小","increaseFontSize":"放大字体大小","unbindText":"取消文本绑定","bindText":"将文本绑定到容器","createContainerFromText":"将文本包围在容器中","link":{"edit":"编辑链接","editEmbed":"编辑链接与嵌入","create":"新建链接","createEmbed":"创建链接与嵌入","label":"链接","labelEmbed":"链接与嵌入","empty":"未设定链接"},"lineEditor":{"edit":"编辑线条","exit":"退出线条编辑"},"elementLock":{"lock":"锁定","unlock":"解除锁定","lockAll":"全部锁定","unlockAll":"全部解锁"},"statusPublished":"已发布","sidebarLock":"侧边栏常驻","selectAllElementsInFrame":"选择画框中的所有元素","removeAllElementsFromFrame":"分离出画框中的所有元素","eyeDropper":"从画布上取色"},"library":{"noItems":"尚未添加任何项目……","hint_emptyLibrary":"选中画布上的项目添加到此处,或从下方的公共素材库中导入。","hint_emptyPrivateLibrary":"选中画布上的项目添加到此处。"},"buttons":{"clearReset":"重置画布","exportJSON":"导出为文件","exportImage":"导出图片...","export":"保存到...","copyToClipboard":"复制到剪贴板","save":"保存至当前文件","saveAs":"保存为","load":"打开","getShareableLink":"获取共享链接","close":"关闭","selectLanguage":"选择语言","scrollBackToContent":"滚动回到内容","zoomIn":"放大","zoomOut":"缩小","resetZoom":"重置缩放","menu":"菜单","done":"完成","edit":"编辑","undo":"撤销","redo":"重做","resetLibrary":"重置素材库","createNewRoom":"新建会议室","fullScreen":"全屏","darkMode":"深色模式","lightMode":"浅色模式","zenMode":"禅模式","objectsSnapMode":"吸附至对象","exitZenMode":"退出禅模式","cancel":"取消","clear":"清除","remove":"删除","embed":"切换嵌入","publishLibrary":"发布","submit":"提交","confirm":"确定","embeddableInteractionButton":"点击以开始交互"},"alerts":{"clearReset":"这将会清除整个画布。您是否要继续?","couldNotCreateShareableLink":"无法创建共享链接","couldNotCreateShareableLinkTooBig":"无法创建可共享链接:画布过大","couldNotLoadInvalidFile":"无法加载无效的文件","importBackendFailed":"从后端导入失败。","cannotExportEmptyCanvas":"无法导出空白画布。","couldNotCopyToClipboard":"无法复制到剪贴板。","decryptFailed":"无法解密数据。","uploadedSecurly":"上传已被端到端加密保护,这意味着 Excalidraw 的服务器和第三方都无法读取内容。","loadSceneOverridePrompt":"加载外部绘图将取代您现有的内容。您想要继续吗?","collabStopOverridePrompt":"停止会话将覆盖您先前本地存储的绘图。 您确定吗?\\n\\n(如果您想保持本地绘图,只需关闭浏览器选项卡。)","errorAddingToLibrary":"无法将项目添加到素材库中","errorRemovingFromLibrary":"无法从素材库中移除项目","confirmAddLibrary":"这将添加 {{numShapes}} 个形状到您的素材库中。您确定吗?","imageDoesNotContainScene":"此图像似乎不包含任何画布数据。您是否在导出时启用了画布嵌入功能?","cannotRestoreFromImage":"无法从此图像文件恢复画布","invalidSceneUrl":"无法从提供的 URL 导入场景。它或者格式不正确,或者不包含有效的 Excalidraw JSON 数据。","resetLibrary":"这将会清除你的素材库。你确定要这么做吗?","removeItemsFromsLibrary":"确定要从素材库中删除 {{count}} 个项目吗?","invalidEncryptionKey":"密钥必须包含22个字符。实时协作已被禁用。","collabOfflineWarning":"无网络连接。\\n您的改动将不会被保存!"},"errors":{"unsupportedFileType":"不支持的文件格式。","imageInsertError":"无法插入图像。请稍后再试……","fileTooBig":"文件过大。最大允许的大小为 {{maxSize}}。","svgImageInsertError":"无法插入 SVG 图像。该 SVG 标记似乎是无效的。","failedToFetchImage":"","invalidSVGString":"无效的 SVG。","cannotResolveCollabServer":"无法连接到实时协作服务器。请重新加载页面并重试。","importLibraryError":"无法加载素材库","collabSaveFailed":"无法保存到后端数据库。如果问题持续存在,您应该保存文件到本地,以确保您的工作不会丢失。","collabSaveFailed_sizeExceeded":"无法保存到后端数据库,画布似乎过大。您应该保存文件到本地,以确保您的工作不会丢失。","brave_measure_text_error":{"line1":"您似乎正在使用 Brave 浏览器并启用了积极阻止指纹识别的设置。","line2":"这可能会破坏绘图中的 文本元素。","line3":"我们强烈建议禁用此设置。您可以按照这些步骤来设置。","line4":"如果禁用此设置无法修复文本元素的显示,请在 GitHub 上提交一个 issue ,或者在 Discord 上反馈"},"libraryElementTypeError":{"embeddable":"嵌入元素不能添加到素材库。","image":"我们不久将支持添加图片到素材库"}},"toolBar":{"selection":"选择","image":"插入图像","rectangle":"矩形","diamond":"菱形","ellipse":"椭圆","arrow":"箭头","line":"线条","freedraw":"自由书写","text":"文字","library":"素材库","lock":"绘制后保持所选的工具栏状态","penMode":"笔模式 – 避免误触","link":"为选中的形状添加/更新链接","eraser":"橡皮","frame":"画框工具","embeddable":"嵌入网页","laser":"激光笔","hand":"抓手(平移工具)","extraTools":"更多工具"},"headings":{"canvasActions":"画布动作","selectedShapeActions":"选定形状操作","shapes":"形状"},"hints":{"canvasPanning":"要移动画布,请按住鼠标滚轮或空格键同时拖拽鼠标,或使用抓手工具。","linearElement":"点击创建多个点 拖动创建直线","freeDraw":"点击并拖动,完成时松开","text":"提示:您也可以使用选择工具双击任意位置来添加文字","embeddable":"点击并拖动以创建嵌入网页","text_selected":"双击或按回车键以编辑文本","text_editing":"按下 Escape 或 CtrlOrCmd+ENTER 完成编辑","linearElementMulti":"点击最后一个点或按下 Esc/Enter 来完成","lockAngle":"可以按住 Shift 来约束角度","resize":"您可以按住SHIFT来限制比例大小,\\n按住ALT来调整中心大小","resizeImage":"按住SHIFT可以自由缩放,\\n按住ALT可以从中间缩放","rotate":"旋转时可以按住 Shift 来约束角度","lineEditor_info":"按住 CtrlOrCmd 并双击或按 CtrlOrCmd + Enter 来编辑点","lineEditor_pointSelected":"按下 Delete 移除点,CtrlOrCmd+D 以复制,拖动以移动","lineEditor_nothingSelected":"选择要编辑的点 (按住 SHIFT 选择多个),\\n或按住 Alt 并点击以添加新点","placeImage":"点击放置图像,或者点击并拖动以手动设置图像大小","publishLibrary":"发布您自己的素材库","bindTextToElement":"按下 Enter 以添加文本","deepBoxSelect":"按住 CtrlOrCmd 以深度选择,并避免拖拽","eraserRevert":"按住 Alt 以反选被标记删除的元素","firefox_clipboard_write":"将高级配置首选项“dom.events.asyncClipboard.clipboardItem”设置为“true”可以启用此功能。要更改 Firefox 的高级配置首选项,请前往“about:config”页面。","disableSnapping":"按住 CtrlOrCmd 以禁用吸附"},"canvasError":{"cannotShowPreview":"无法显示预览","canvasTooBig":"画布可能过大。","canvasTooBigTip":"提示:尝试将最远的元素移动到和其它元素更近一些。"},"errorSplash":{"headingMain":"遇到异常。请尝试。","clearCanvasMessage":"如果重新加载页面无效,请尝试。","clearCanvasCaveat":"这会造成当前工作丢失","trackedToSentry":"标识符为{{eventId}}的错误已在我们的系统中被记录","openIssueMessage":"我们非常谨慎地处理错误信息,您的画布内容不会被包含在错误报告中。如果您的画布内容不需要保持私密,请考虑在我们的 上提供更多信息。请复制粘贴以下信息到 GitHub Issue 中。","sceneContent":"画布内容:"},"roomDialog":{"desc_intro":"你可以邀请其他人到目前的画面中与你协作。","desc_privacy":"别担心,该会话使用端到端加密,无论绘制什么都将保持私密,甚至连我们的服务器也无法查看。","button_startSession":"开始会话","button_stopSession":"结束会话","desc_inProgressIntro":"实时协作会话进行中。","desc_shareLink":"分享此链接给你要协作的用户","desc_exitSession":"停止会话将中断您与房间的连接,但您依然可以在本地继续使用画布。请注意,这不会影响到其他用户,他们仍可以在他们的版本上继续协作。","shareTitle":"加入 Excalidraw 实时协作会话"},"errorDialog":{"title":"错误"},"exportDialog":{"disk_title":"保存到本地","disk_details":"将画布数据导出为文件,以便以后导入","disk_button":"保存为文件","link_title":"分享链接","link_details":"导出为只读链接。","link_button":"导出链接","excalidrawplus_description":"将画布保存到您的 Excalidraw+ 工作区。","excalidrawplus_button":"导出","excalidrawplus_exportError":"暂时无法导出到 Excalidraw+ ..."},"helpDialog":{"blog":"浏览我们的博客","click":"单击","deepSelect":"深度选择","deepBoxSelect":"在方框内深度选择并避免拖拽","curvedArrow":"曲线箭头","curvedLine":"曲线","documentation":"文档","doubleClick":"双击","drag":"拖动","editor":"编辑器","editLineArrowPoints":"编辑线条或箭头的点","editText":"添加或编辑文本","github":"提交问题","howto":"帮助文档","or":"或","preventBinding":"禁用箭头吸附","tools":"工具","shortcuts":"快捷键列表","textFinish":"完成编辑 (文本编辑器)","textNewLine":"添加新行(文本编辑器)","title":"帮助","view":"视图","zoomToFit":"缩放以适应所有元素","zoomToSelection":"缩放到选区","toggleElementLock":"锁定/解锁","movePageUpDown":"上下移动页面","movePageLeftRight":"左右移动页面"},"clearCanvasDialog":{"title":"清除画布"},"publishDialog":{"title":"发布素材库","itemName":"项目名称","authorName":"作者名","githubUsername":"GitHub 用户名","twitterUsername":"Twitter 用户名","libraryName":"名称","libraryDesc":"简介","website":"网址","placeholder":{"authorName":"您的名字或用户名","libraryName":"素材库名称","libraryDesc":"介绍您的素材库,让人们了解其用途","githubHandle":"GitHub 用户名(可选),填写后,您可以编辑已提交待审的素材库","twitterHandle":"Twitter 用户名(可选),填写后,当我们在Twitter发布推广信息时便可提及您","website":"您个人网站的或任意的链接(可选)"},"errors":{"required":"必填","website":"输入一个有效的URL"},"noteDescription":"提交后,您的素材库将被包含在公共素材库广场以供其他人在绘图中使用。","noteGuidelines":"提交的素材库需先经人工审核。在提交之前,请先阅读指南 。后续沟通和对库的修改需要 GitHub 账号,但这不是必须的。","noteLicense":"提交即表明您已同意素材库将遵循 MIT 许可证,简而言之,任何人都可以不受限制地使用它们。","noteItems":"素材库中每个项目都有各自的名称以供筛选。以下项目将被包含:","atleastOneLibItem":"请选择至少一个素材库以开始","republishWarning":"注意:部分选中的项目已经发布或提交。请仅在更新已有或已提交的素材库时重复提交项目。"},"publishSuccessDialog":{"title":"素材库已提交","content":"谢谢你 {{authorName}}。您的素材库已被提交审核。请点击此处跟进此次提交的状态"},"confirmDialog":{"resetLibrary":"重置素材库","removeItemsFromLib":"从素材库中删除选中的项目"},"imageExportDialog":{"header":"导出图片","label":{"withBackground":"背景","onlySelected":"仅选中","darkMode":"深色模式","embedScene":"包含画布数据","scale":"缩放比例","padding":"内边距"},"tooltip":{"embedScene":"画布数据将被保存到导出的 PNG/SVG 文件,以便恢复。\\n将会增加导出文件的大小。"},"title":{"exportToPng":"导出为 PNG","exportToSvg":"导出为 SVG","copyPngToClipboard":"复制 PNG 到剪切板"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"复制到剪贴板"}},"encrypted":{"tooltip":"您的绘图采用端到端加密,其内容对于 Excalidraw 服务器是不可见的。","link":"Excalidraw 中关于端到端加密的博客"},"stats":{"angle":"角度","element":"元素","elements":"元素","height":"高度","scene":"画布","selected":"选中","storage":"存储","title":"详细统计信息","total":"总计","version":"版本","versionCopy":"点击复制","versionNotAvailable":"版本不可用","width":"宽度"},"toast":{"addedToLibrary":"添加到素材库中","copyStyles":"样式已拷贝。","copyToClipboard":"已复制到剪切板。","copyToClipboardAsPng":"已将 {{exportSelection}} 作为 PNG 复制到剪贴板\\n({{exportColorScheme}})","fileSaved":"文件已保存。","fileSavedToFilename":"保存到 {filename}","canvas":"画布","selection":"所选项","pasteAsSingleElement":"使用 {{shortcut}} 粘贴为单个元素,\\n或粘贴到现有的文本编辑器里","unableToEmbed":"目前不允许嵌入此网址。请在 GitHub 上提 issue 请求将此网址加入白名单","unrecognizedLinkFormat":"您嵌入的链接不符合格式要求。请尝试粘贴源网站提供的“嵌入 (embed)”字符串"},"colors":{"transparent":"透明","black":"黑","white":"白","red":"红","pink":"粉红","grape":"紫红","violet":"蓝紫","gray":"灰","blue":"蓝","cyan":"青","teal":"蓝绿","green":"绿","yellow":"黄","orange":"橙","bronze":"古铜"},"welcomeScreen":{"app":{"center_heading":"您的所有数据都储存在浏览器本地。","center_heading_plus":"是否前往 Excalidraw+ ?","menuHint":"导出、首选项、语言……"},"defaults":{"menuHint":"导出、首选项……","center_heading":"图,化繁为简。","toolbarHint":"选择工具并开始绘图!","helpHint":"快捷键和帮助"}},"colorPicker":{"mostUsedCustomColors":"常用自定义颜色","colors":"颜色","shades":"色调明暗","hexCode":"十六进制值","noShades":"此颜色没有可用的明暗变化"},"overwriteConfirm":{"action":{"exportToImage":{"title":"导出为图片","button":"导出为图片","description":"将画布数据导出为图片,以便以后导入。"},"saveToDisk":{"title":"保存到本地","button":"保存到本地","description":"将画布数据导出为文件,以便以后导入。"},"excalidrawPlus":{"title":"Excalidraw+","button":"导出到 Excalidraw+","description":"将画布保存到您的 Excalidraw+ 工作区。"}},"modal":{"loadFromFile":{"title":"从文件加载","button":"从文件加载","description":"从文件加载将替换您现有的内容。 您可以先使用下列方式备份您的绘图。"},"shareableLink":{"title":"从链接加载","button":"替换我的内容","description":"加载外部绘图将替换您现有的内容。 您可以先使用下列方式备份您的绘图。"}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/zh-HK-json-93b9b676d4f4b5702797.js b/public/excalidraw/excalidraw-assets-dev/locales/zh-HK-json-93b9b676d4f4b5702797.js
new file mode 100644
index 0000000..35481c0
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/zh-HK-json-93b9b676d4f4b5702797.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/zh-HK-json"],{
+
+/***/ "../../locales/zh-HK.json":
+/*!********************************!*\
+ !*** ../../locales/zh-HK.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"貼上","pasteAsPlaintext":"","pasteCharts":"貼上圖表","selectAll":"全選","multiSelect":"多重選取","moveCanvas":"移動畫布","cut":"剪下","copy":"複製","copyAsPng":"以 PNG 格式複製","copyAsSvg":"以 SVG 格式複製","copyText":"","bringForward":"往上一層移動","sendToBack":"移到最底層","bringToFront":"移到最上層","sendBackward":"往下一層移動","delete":"刪除","copyStyles":"複製樣式","pasteStyles":"套用樣式","stroke":"筆跡顏色","background":"填充顏色","fill":"背景樣式","strokeWidth":"筆跡寬度","strokeStyle":"筆跡線條","strokeStyle_solid":"實線","strokeStyle_dashed":"虛線(較密)","strokeStyle_dotted":"虛線(較疏)","sloppiness":"筆跡風格","opacity":"透明度","textAlign":"文字對齊","edges":"邊角樣式","sharp":"銳角","round":"圓角","arrowheads":"箭嘴","arrowhead_none":"無箭嘴","arrowhead_arrow":"普通箭嘴","arrowhead_bar":"平頭條狀","arrowhead_dot":"圓點","arrowhead_triangle":"三角箭嘴","fontSize":"字型大小","fontFamily":"字體","addWatermark":"加入「使用 Excalidraw 製圖」水印","handDrawn":"手繪體","normal":"電腦字體","code":"等寬體","small":"細","medium":"中","large":"大","veryLarge":"勁大","solid":"實心","hachure":"斜線","zigzag":"","crossHatch":"交叉格仔","thin":"幼","bold":"粗","left":"靠左對齊","center":"置中對齊","right":"靠右對齊","extraBold":"勁粗","architect":"手繪風格","artist":"藝術家風格","cartoonist":"卡通風格","fileTitle":"檔案名稱","colorPicker":"","canvasColors":"","canvasBackground":"畫布背景顏色","drawingCanvas":"畫布","layers":"圖層","actions":"動作","language":"🌏 語言","liveCollaboration":"","duplicateSelection":"製作副本","untitled":"未命名的作品","name":"","yourName":"你的名稱","madeWithExcalidraw":"使用 Excalidraw 製圖","group":"建立物件群組","ungroup":"取消物件群組","collaborators":"已連線的協作者","showGrid":"顯示網格","addToLibrary":"加入作品庫","removeFromLibrary":"從作品庫中移除","libraryLoadingMessage":"正在載入作品庫…","libraries":"瀏覽作品庫","loadingScene":"載入畫布中…","align":"物件對齊","alignTop":"水平置頂","alignBottom":"水平置底","alignLeft":"垂直靠左對齊","alignRight":"垂直靠右對齊","centerVertically":"垂直置中","centerHorizontally":"水平置中","distributeHorizontally":"左右等距","distributeVertically":"上下等距","flipHorizontal":"左右反轉","flipVertical":"上下反轉","viewMode":"唯讀模式","share":"","showStroke":"","showBackground":"","toggleTheme":"","personalLib":"","excalidrawLib":"","decreaseFontSize":"","increaseFontSize":"","unbindText":"","bindText":"","createContainerFromText":"","link":{"edit":"","editEmbed":"","create":"","createEmbed":"","label":"","labelEmbed":"","empty":""},"lineEditor":{"edit":"","exit":""},"elementLock":{"lock":"","unlock":"","lockAll":"","unlockAll":""},"statusPublished":"","sidebarLock":"","selectAllElementsInFrame":"","removeAllElementsFromFrame":"","eyeDropper":""},"library":{"noItems":"","hint_emptyLibrary":"","hint_emptyPrivateLibrary":""},"buttons":{"clearReset":"清空畫布","exportJSON":"","exportImage":"","export":"","copyToClipboard":"","save":"","saveAs":"","load":"","getShareableLink":"","close":"","selectLanguage":"","scrollBackToContent":"","zoomIn":"","zoomOut":"","resetZoom":"","menu":"","done":"","edit":"","undo":"","redo":"","resetLibrary":"","createNewRoom":"","fullScreen":"","darkMode":"","lightMode":"","zenMode":"","objectsSnapMode":"","exitZenMode":"","cancel":"","clear":"","remove":"","embed":"","publishLibrary":"","submit":"","confirm":"","embeddableInteractionButton":""},"alerts":{"clearReset":"【‼️ 警告 ‼️ 無法復原的動作】你確定要清空呢塊畫布嗎?","couldNotCreateShareableLink":"","couldNotCreateShareableLinkTooBig":"","couldNotLoadInvalidFile":"","importBackendFailed":"","cannotExportEmptyCanvas":"無嘢可以匯出喎~畫吓嘢先?","couldNotCopyToClipboard":"","decryptFailed":"","uploadedSecurly":"","loadSceneOverridePrompt":"","collabStopOverridePrompt":"","errorAddingToLibrary":"","errorRemovingFromLibrary":"","confirmAddLibrary":"","imageDoesNotContainScene":"","cannotRestoreFromImage":"","invalidSceneUrl":"","resetLibrary":"","removeItemsFromsLibrary":"","invalidEncryptionKey":"","collabOfflineWarning":""},"errors":{"unsupportedFileType":"","imageInsertError":"","fileTooBig":"","svgImageInsertError":"","failedToFetchImage":"","invalidSVGString":"","cannotResolveCollabServer":"","importLibraryError":"","collabSaveFailed":"","collabSaveFailed_sizeExceeded":"","brave_measure_text_error":{"line1":"","line2":"","line3":"","line4":""},"libraryElementTypeError":{"embeddable":"","image":""}},"toolBar":{"selection":"","image":"","rectangle":"","diamond":"","ellipse":"","arrow":"","line":"","freedraw":"","text":"","library":"","lock":"","penMode":"","link":"","eraser":"","frame":"","embeddable":"","laser":"","hand":"","extraTools":""},"headings":{"canvasActions":"畫布動作","selectedShapeActions":"","shapes":""},"hints":{"canvasPanning":"","linearElement":"","freeDraw":"","text":"","embeddable":"","text_selected":"","text_editing":"","linearElementMulti":"","lockAngle":"","resize":"","resizeImage":"","rotate":"","lineEditor_info":"","lineEditor_pointSelected":"","lineEditor_nothingSelected":"","placeImage":"","publishLibrary":"","bindTextToElement":"","deepBoxSelect":"","eraserRevert":"","firefox_clipboard_write":"","disableSnapping":""},"canvasError":{"cannotShowPreview":"無法顯示預覽","canvasTooBig":"塊畫布太大啦,縮細啲先啦?","canvasTooBigTip":""},"errorSplash":{"headingMain":"","clearCanvasMessage":"如果重新整理頁面都係睇唔到,你可以","clearCanvasCaveat":"(注意:呢個動作會直接丟棄你嘅作品,並且無法復原)","trackedToSentry":"","openIssueMessage":"","sceneContent":""},"roomDialog":{"desc_intro":"","desc_privacy":"","button_startSession":"","button_stopSession":"","desc_inProgressIntro":"","desc_shareLink":"","desc_exitSession":"","shareTitle":""},"errorDialog":{"title":""},"exportDialog":{"disk_title":"","disk_details":"","disk_button":"","link_title":"","link_details":"","link_button":"","excalidrawplus_description":"","excalidrawplus_button":"","excalidrawplus_exportError":""},"helpDialog":{"blog":"","click":"","deepSelect":"","deepBoxSelect":"","curvedArrow":"","curvedLine":"","documentation":"","doubleClick":"","drag":"","editor":"","editLineArrowPoints":"","editText":"","github":"","howto":"","or":"","preventBinding":"","tools":"","shortcuts":"","textFinish":"","textNewLine":"","title":"","view":"","zoomToFit":"","zoomToSelection":"","toggleElementLock":"","movePageUpDown":"","movePageLeftRight":""},"clearCanvasDialog":{"title":""},"publishDialog":{"title":"","itemName":"","authorName":"","githubUsername":"","twitterUsername":"","libraryName":"","libraryDesc":"","website":"","placeholder":{"authorName":"","libraryName":"","libraryDesc":"","githubHandle":"","twitterHandle":"","website":""},"errors":{"required":"","website":""},"noteDescription":"","noteGuidelines":"","noteLicense":"","noteItems":"","atleastOneLibItem":"","republishWarning":""},"publishSuccessDialog":{"title":"","content":""},"confirmDialog":{"resetLibrary":"","removeItemsFromLib":""},"imageExportDialog":{"header":"","label":{"withBackground":"","onlySelected":"","darkMode":"","embedScene":"","scale":"","padding":""},"tooltip":{"embedScene":""},"title":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""},"button":{"exportToPng":"","exportToSvg":"","copyPngToClipboard":""}},"encrypted":{"tooltip":"","link":""},"stats":{"angle":"","element":"","elements":"","height":"","scene":"","selected":"","storage":"","title":"","total":"","version":"","versionCopy":"","versionNotAvailable":"","width":""},"toast":{"addedToLibrary":"","copyStyles":"","copyToClipboard":"","copyToClipboardAsPng":"","fileSaved":"","fileSavedToFilename":"","canvas":"畫布","selection":"","pasteAsSingleElement":"","unableToEmbed":"","unrecognizedLinkFormat":""},"colors":{"transparent":"","black":"","white":"","red":"","pink":"","grape":"","violet":"","gray":"","blue":"","cyan":"","teal":"","green":"","yellow":"","orange":"","bronze":""},"welcomeScreen":{"app":{"center_heading":"","center_heading_plus":"","menuHint":""},"defaults":{"menuHint":"","center_heading":"","toolbarHint":"","helpHint":""}},"colorPicker":{"mostUsedCustomColors":"","colors":"","shades":"","hexCode":"","noShades":""},"overwriteConfirm":{"action":{"exportToImage":{"title":"","button":"","description":""},"saveToDisk":{"title":"","button":"","description":""},"excalidrawPlus":{"title":"","button":"","description":""}},"modal":{"loadFromFile":{"title":"","button":"","description":""},"shareableLink":{"title":"","button":"","description":""}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/locales/zh-TW-json-805d10b0eed9ca51b318.js b/public/excalidraw/excalidraw-assets-dev/locales/zh-TW-json-805d10b0eed9ca51b318.js
new file mode 100644
index 0000000..18e502c
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/locales/zh-TW-json-805d10b0eed9ca51b318.js
@@ -0,0 +1,22 @@
+"use strict";
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["locales/zh-TW-json"],{
+
+/***/ "../../locales/zh-TW.json":
+/*!********************************!*\
+ !*** ../../locales/zh-TW.json ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"labels":{"paste":"貼上","pasteAsPlaintext":"以純文字貼上","pasteCharts":"貼上圖表","selectAll":"全選","multiSelect":"將物件加入選取範圍","moveCanvas":"移動畫布","cut":"剪下","copy":"複製","copyAsPng":"以PNG格式儲存到剪貼板","copyAsSvg":"以SVG格式複製到剪貼板","copyText":"以文字格式複製至剪貼簿","bringForward":"上移一層","sendToBack":"移到最底層","bringToFront":"置於最頂層","sendBackward":"往後移一層","delete":"刪除","copyStyles":"複製樣式","pasteStyles":"貼上樣式","stroke":"筆畫","background":"背景","fill":"填滿","strokeWidth":"筆跡寬度","strokeStyle":"筆畫樣式","strokeStyle_solid":"實線","strokeStyle_dashed":"虛線","strokeStyle_dotted":"點線","sloppiness":"線條風格","opacity":"透明度","textAlign":"文字對齊","edges":"邊緣","sharp":"尖銳","round":"平滑","arrowheads":"箭頭","arrowhead_none":"無","arrowhead_arrow":"箭頭","arrowhead_bar":"條狀箭頭","arrowhead_dot":"點箭頭","arrowhead_triangle":"三角形","fontSize":"字型大小","fontFamily":"字體集","addWatermark":"加上 \\"Made with Excalidraw\\" 浮水印","handDrawn":"手寫","normal":"一般","code":"代碼","small":"小","medium":"中","large":"大","veryLarge":"特大","solid":"實心","hachure":"斜線筆觸","zigzag":"Z字形","crossHatch":"交叉筆觸","thin":"細","bold":"粗","left":"左側","center":"置中","right":"右側","extraBold":"極粗","architect":"精確","artist":"藝術","cartoonist":"卡通","fileTitle":"檔案名稱","colorPicker":"色彩選擇工具","canvasColors":"使用於畫布","canvasBackground":"Canvas 背景","drawingCanvas":"繪圖 canvas","layers":"圖層","actions":"動作","language":"語言","liveCollaboration":"即時協作...","duplicateSelection":"複製","untitled":"無標題","name":"名稱","yourName":"你的名稱","madeWithExcalidraw":"以 Excalidraw 製作","group":"建立群組","ungroup":"取消群組","collaborators":"協作者","showGrid":"顯示格線","addToLibrary":"加入資料庫","removeFromLibrary":"從資料庫中移除","libraryLoadingMessage":"資料庫讀取中…","libraries":"瀏覽資料庫","loadingScene":"場景讀取中…","align":"對齊","alignTop":"對齊頂部","alignBottom":"對齊底部","alignLeft":"對齊左側","alignRight":"對齊右側","centerVertically":"垂直置中","centerHorizontally":"水平置中","distributeHorizontally":"水平分布","distributeVertically":"垂直分布","flipHorizontal":"水平翻轉","flipVertical":"垂直翻轉","viewMode":"檢視模式","share":"共享","showStroke":"顯示線條檢色器","showBackground":"顯示背景檢色器","toggleTheme":"切換主題","personalLib":"個人資料庫","excalidrawLib":"Excalidraw 資料庫","decreaseFontSize":"縮小文字","increaseFontSize":"放大文字","unbindText":"取消綁定文字","bindText":"結合文字至容器","createContainerFromText":"將文字包於容器中","link":{"edit":"編輯連結","editEmbed":"編輯連結&嵌入","create":"建立連結","createEmbed":"建立連結&嵌入","label":"連結","labelEmbed":"連結&嵌入","empty":"未設定連結"},"lineEditor":{"edit":"編輯線條","exit":"結束線條編輯"},"elementLock":{"lock":"鎖定","unlock":"解鎖","lockAll":"全部鎖定","unlockAll":"全部解鎖"},"statusPublished":"已發布","sidebarLock":"側欄維持開啟","selectAllElementsInFrame":"選取框架內的所有元素","removeAllElementsFromFrame":"從框架內移除所有元素","eyeDropper":"從畫布中選取顏色"},"library":{"noItems":"尚未加入任何物件...","hint_emptyLibrary":"選取畫布上的物件以加入,或從下方的公開 repository 中安裝資料庫","hint_emptyPrivateLibrary":"選擇畫布上的物件以在此加入"},"buttons":{"clearReset":"重置 canvas","exportJSON":"匯出至檔案","exportImage":"匯出圖片","export":"儲存至...","copyToClipboard":"複製至剪貼簿","save":"儲存目前檔案","saveAs":"儲存為","load":"開啟","getShareableLink":"取得共享連結","close":"關閉","selectLanguage":"選擇語言","scrollBackToContent":"捲動回到內容","zoomIn":"放大","zoomOut":"縮小","resetZoom":"重設縮放","menu":"選單","done":"完成","edit":"編輯","undo":"復原","redo":"重做","resetLibrary":"重設資料庫","createNewRoom":"建立新協作會議室","fullScreen":"全螢幕","darkMode":"深色模式","lightMode":"淺色模式","zenMode":"專注模式","objectsSnapMode":"吸附至物件","exitZenMode":"離開專注模式","cancel":"取消","clear":"清除","remove":"刪除","embed":"切換嵌入","publishLibrary":"發布","submit":"送出","confirm":"確認","embeddableInteractionButton":"點擊以互動"},"alerts":{"clearReset":"這將會清除整個 canvas。你確定嗎?","couldNotCreateShareableLink":"無法建立共享連結。","couldNotCreateShareableLinkTooBig":"無法建立共享連結:場景太大","couldNotLoadInvalidFile":"無法讀取失效的檔案。","importBackendFailed":"後端讀取失敗。","cannotExportEmptyCanvas":"無法輸出空白的 canvas。","couldNotCopyToClipboard":"無法複製到剪貼簿","decryptFailed":"無法解密資料。","uploadedSecurly":"上傳已通過 end-to-end 加密,Excalidraw 伺服器和第三方無法皆讀取其內容。","loadSceneOverridePrompt":"讀取外部圖樣將取代目前的內容。是否要繼續?","collabStopOverridePrompt":"停止連線將覆蓋您先前於本機儲存的繪圖進度,是否確認?\\n\\n(如要保留原有的本機繪圖進度,直接關閉瀏覽器分頁即可。)","errorAddingToLibrary":"無法於此資料庫加入項目","errorRemovingFromLibrary":"無法由此資料庫移除項目","confirmAddLibrary":"這將會將 {{numShapes}} 個圖形加入你的資料庫,你確定嗎?","imageDoesNotContainScene":"此圖檔中未包含場景資料。輸出檔案時是否有包含場景資料?","cannotRestoreFromImage":"無法由此檔案回復場景。","invalidSceneUrl":"無法由提供的 URL 匯入場景。可能是發生異常,或未包含有效的 Excalidraw JSON 資料。","resetLibrary":"這會清除您的資料庫,是否確定?","removeItemsFromsLibrary":"從資料庫刪除 {{count}} 項?","invalidEncryptionKey":"加密鍵必須為22字元。即時協作已停用。","collabOfflineWarning":"沒有可用的網路連線。\\n變更無法儲存!"},"errors":{"unsupportedFileType":"不支援的檔案類型。","imageInsertError":"無法插入圖片。請稍後再試…","fileTooBig":"檔案過大。可接受的最大尺寸為 {{maxSize}} 。","svgImageInsertError":"無法插入 SVG 圖片。此 SVG 檔案有問題。","failedToFetchImage":"無法獲取圖片。","invalidSVGString":"無效的 SVG。","cannotResolveCollabServer":"無法連結至 collab 伺服器。請重新整理後再試一次。","importLibraryError":"無法載入資料庫","collabSaveFailed":"無法儲存至後端資料庫。若此問題持續發生,請將檔案儲存於本機以確保資料不會遺失。","collabSaveFailed_sizeExceeded":"無法儲存至後端資料庫,可能的原因為畫布尺寸過大。請將檔案儲存於本機以確保資料不會遺失。","brave_measure_text_error":{"line1":"看起來您開啟了 Brave 瀏覽器的 Aggressively Block Fingerprinting 設定。","line2":"這可能造成您畫布中 文字元素 的異常。","line3":"我們強烈建議您關閉此設定。您可以依照 這些步驟 來進行。","line4":"若關閉此設定並未修復文字元素的顯示問題,請回報於我們 GitHub 上的 issue,或在 Discord 上告訴我們。"},"libraryElementTypeError":{"embeddable":"可嵌入元素無法加入資料庫","image":"即將支援加入圖片至資料庫!"}},"toolBar":{"selection":"選取","image":"插入圖片","rectangle":"長方形","diamond":"菱形","ellipse":"橢圓","arrow":"箭頭","line":"線條","freedraw":"繪圖","text":"文字","library":"資料庫","lock":"可連續使用選取的工具","penMode":"筆模式 - 避免觸摸","link":"為所選的形狀增加\\b/更新連結","eraser":"橡皮擦","frame":"框架工具","embeddable":"嵌入網站","laser":"雷射筆","hand":"手形(平移工具)","extraTools":"更多工具"},"headings":{"canvasActions":"canvas 動作","selectedShapeActions":"選取圖形動作","shapes":"形狀"},"hints":{"canvasPanning":"若要移動畫布,請在拖曳時按住滑鼠滾輪或空白鍵,或使用手形工具","linearElement":"點擊以繪製多點曲線;或拖曳以繪製直線","freeDraw":"點擊並拖曳來繪圖,放開即結束","text":"提示:亦可使用選取工具在任何地方雙擊來加入文字","embeddable":"點擊並拖移以建立嵌入網站","text_selected":"雙擊滑鼠或按 Enter 以編輯文字","text_editing":"按跳脫鍵或 Ctrl 或 Cmd + Enter 以結束編輯","linearElementMulti":"按下 Escape 或 Enter 以結束繪製","lockAngle":"按住 SHIFT 可限制旋轉角度","resize":"縮放時按住 Shift 可保持原比例縮放;\\\\n按住 Alt 可由中心點進行縮放","resizeImage":"按住 SHIFT 可任意縮放,按住 ALT 可由中央縮放。","rotate":"旋轉時按住 Shift 可限制旋轉角度","lineEditor_info":"按住 Ctrl 或 Cmd 並雙擊或按住 Ctrl 或 Cmd + Enter 來編輯控制點","lineEditor_pointSelected":"按下 Delete 可移除錨點;Ctrl 或 Cmd + D 可複製;或可拖曳來移動","lineEditor_nothingSelected":"選擇要編輯的錨點(按住 SHIFT 可多選),\\n或按住 Alt 並點擊以增加新錨點。","placeImage":"點擊以放置圖片,或點擊並拖曳以手動調整其尺寸。","publishLibrary":"發布個人資料庫","bindTextToElement":"按下 Enter 以加入文字。","deepBoxSelect":"按住 Ctrl 或 Cmd 以深度選取並避免拖曳","eraserRevert":"按住 Alt 以反選取已標記待刪除的元素","firefox_clipboard_write":"此功能有機會透過將 \\"dom.events.asyncClipboard.clipboardItem\\" 設定為 \\"true\\" 來開啟。\\n若要變更 Firefox 瀏覽器的此設定值,請至 \\"about:config\\" 頁面。","disableSnapping":"按住 Ctrl 或 Cmd 以禁用吸附"},"canvasError":{"cannotShowPreview":"無法顯示預覽","canvasTooBig":"畫布可能過大","canvasTooBigTip":"提示:可嘗試將最遠的元素移動至較集中的位置"},"errorSplash":{"headingMain":"發生錯誤,嘗試","clearCanvasMessage":"若重新載入仍無法解決問題,嘗試","clearCanvasCaveat":"此動作將造成目前的作品被移除。","trackedToSentry":"此錯誤與其識別碼{{eventId}}將由系統記錄。","openIssueMessage":"我們將謹慎處理,你的作品內容不會被包含在錯誤報告中。若你的作品不需保持私密,請考慮使用我們的請將下列資訊複製貼上至 GitHub issue 中。","sceneContent":"作品內容:"},"roomDialog":{"desc_intro":"你可以邀請其他人一起協作目前的作品。","desc_privacy":"連線使用 end-to-end 加密故無須擔心作品的安全性。即使是我們的伺服器也無法取得其內容。","button_startSession":"開始連線","button_stopSession":"停止連線","desc_inProgressIntro":"即時協作連線正在進行中。","desc_shareLink":"將此連結分享給欲協作的對象:","desc_exitSession":"停止連線將中斷你與協作會議室的連結,但你仍可於本機編輯此作品。意指停止連線後你的編輯不會被先前共同協作的人看見,且他們可繼續共同協作另一個版本。","shareTitle":"加入 Excalidraw 上的即時協作會議室"},"errorDialog":{"title":"錯誤"},"exportDialog":{"disk_title":"儲存至硬碟","disk_details":"將場景匯出為可供匯入之檔案","disk_button":"儲存至檔案","link_title":"可共享連結","link_details":"匯出為唯讀連結","link_button":"匯出為連結","excalidrawplus_description":"將此場景儲存至你的 Excalidraw+ 工作區","excalidrawplus_button":"輸出","excalidrawplus_exportError":"目前無法輸出至 Excalidraw+"},"helpDialog":{"blog":"閱讀部落格","click":"點擊","deepSelect":"深度選取","deepBoxSelect":"在容器內深度選取並避免拖曳","curvedArrow":"曲箭頭","curvedLine":"曲線","documentation":"文件","doubleClick":"雙擊","drag":"拖曳","editor":"編輯器","editLineArrowPoints":"編輯線/箭頭控制點","editText":"編輯文字/增加標籤","github":"發現異常?回報問題","howto":"參照我們的說明","or":"或","preventBinding":"避免箭號連結","tools":"工具","shortcuts":"鍵盤快速鍵","textFinish":"完成編輯(文字編輯器)","textNewLine":"換行(文字編輯器)","title":"說明","view":"檢視","zoomToFit":"放大至填滿畫面","zoomToSelection":"縮放至選取區","toggleElementLock":"鎖定/解鎖已選的項目","movePageUpDown":"向上/下移動頁面","movePageLeftRight":"向左/右移動頁面"},"clearCanvasDialog":{"title":"清除畫布"},"publishDialog":{"title":"發布資料庫","itemName":"項目名稱","authorName":"作者名稱","githubUsername":"GitHub 帳號","twitterUsername":"Twitter 帳號","libraryName":"資料庫名稱","libraryDesc":"資料庫說明","website":"網站","placeholder":{"authorName":"您的名稱或帳號","libraryName":"您的資料庫名稱","libraryDesc":"提供您的資料庫說明以利他人理解其用途","githubHandle":"Github handle(選填),填寫後您可編輯已送出待審查的資料庫","twitterHandle":"Twitter 帳號(選填),填寫後若我們在 Twitter 推廣時可提及您","website":"您個人網站或其他網站的連結(選填)"},"errors":{"required":"必填","website":"請輸入有效的 URL"},"noteDescription":"送出您的資料庫後將被包含於公開資料庫 repository以利他人在其繪圖中使用。","noteGuidelines":"資料庫需先經人工審查。請閱讀說明文件再送出。若需溝通與修改時要透過 GitHub 帳號來進行,但並非強制需求。","noteLicense":"送出即代表您同意此資料庫將發布時使用 MIT 授權,簡單來說是指任何人都能不受限制的使用。","noteItems":"每個資料庫項目都有獨立的名稱故可篩選。會包含下列資料庫項目:","atleastOneLibItem":"請選擇至少一項資料庫項目","republishWarning":"注意:部分選取中的物件先前已發布/送出過。建議僅在要更新現存資料庫或已送出的物件時才重新送出這些物件。"},"publishSuccessDialog":{"title":"資料庫已送出","content":"感謝 {{authorName}} 。您的資料庫已送出待審查。您可查看目前狀態在此"},"confirmDialog":{"resetLibrary":"重設資料庫","removeItemsFromLib":"從資料庫移除所選的項目"},"imageExportDialog":{"header":"匯出圖片","label":{"withBackground":"背景","onlySelected":"僅選取物件","darkMode":"深色模式","embedScene":"嵌入場景","scale":"縮放比例","padding":"內間距"},"tooltip":{"embedScene":"用於回復場景的場景資料會被包含在輸出的 PNG/SVG 檔案中。\\n會增加輸出的檔案大小。"},"title":{"exportToPng":"輸出成 PNG","exportToSvg":"輸出成 SVG","copyPngToClipboard":"複製 PNG 至剪貼簿"},"button":{"exportToPng":"PNG","exportToSvg":"SVG","copyPngToClipboard":"複製至剪貼簿"}},"encrypted":{"tooltip":"你的作品已使用 end-to-end 方式加密,Excalidraw 的伺服器也無法取得其內容。","link":"Excalidraw 端到端加密的相關部落格文章"},"stats":{"angle":"角度","element":"元素","elements":"元素","height":"高度","scene":"場景","selected":"已選","storage":"儲存","title":"詳細統計","total":"合計","version":"版本","versionCopy":"點擊複製","versionNotAvailable":"無法取得版本","width":"寬度"},"toast":{"addedToLibrary":"加入資料庫","copyStyles":"已複製樣式","copyToClipboard":"複製至剪貼簿。","copyToClipboardAsPng":"以 PNG 格式將 {{exportSelection}} 複製至剪貼簿\\n({{exportColorScheme}})","fileSaved":"已儲存檔案。","fileSavedToFilename":"儲存為 {filename}","canvas":"畫布","selection":"已選項目","pasteAsSingleElement":"使用 {{shortcut}} 以做為單一物件貼上,\\n或貼上至現有的文字編輯器","unableToEmbed":"目前不允許嵌入此網址。您可至 GitHub 提出 issue 以要求將此網址加入合格名單。","unrecognizedLinkFormat":"您嵌入的連結格式不符。請嘗試貼入原網站所提供的「嵌入」字串。"},"colors":{"transparent":"透明","black":"黑","white":"白","red":"紅","pink":"粉紅","grape":"深紫","violet":"藍紫","gray":"灰","blue":"藍","cyan":"青","teal":"藍綠","green":"綠","yellow":"黃","orange":"橘","bronze":"銅"},"welcomeScreen":{"app":{"center_heading":"所有資料皆已在瀏覽器中儲存於本機","center_heading_plus":"您是否是要前往 Excalidraw+ ?","menuHint":"輸出、偏好設定、語言..."},"defaults":{"menuHint":"輸出、偏好設定及其他...","center_heading":"圖表。製作。超簡單。","toolbarHint":"選個工具開始畫圖吧!","helpHint":"快速鍵與說明"}},"colorPicker":{"mostUsedCustomColors":"最常使用的自訂顏色","colors":"顏色","shades":"漸變色","hexCode":"Hex 碼","noShades":"沒有此顏色的漸變色"},"overwriteConfirm":{"action":{"exportToImage":{"title":"匯出為圖片","button":"匯出為圖片","description":"將場景匯出為可供匯入的圖片檔案"},"saveToDisk":{"title":"儲存至硬碟","button":"儲存至硬碟","description":"將場景匯出為可供匯入的檔案"},"excalidrawPlus":{"title":"Excalidraw+","button":"匯出至 Excalidraw+","description":"將此場景儲存至您的 Excalidraw+ 工作區"}},"modal":{"loadFromFile":{"title":"從檔案載入","button":"從檔案載入","description":"從檔案載入將取代您目前的內容。 可先使用下方的選項備份您的繪圖。"},"shareableLink":{"title":"從連結載入","button":"取代我的內容","description":"載入外部繪圖將取代您目前的內容。 可先使用下方的選項備份您的繪圖。"}}}}');
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/public/excalidraw/excalidraw-assets-dev/vendor-39727f4653a274cf18f6.js b/public/excalidraw/excalidraw-assets-dev/vendor-39727f4653a274cf18f6.js
new file mode 100644
index 0000000..d7fa966
--- /dev/null
+++ b/public/excalidraw/excalidraw-assets-dev/vendor-39727f4653a274cf18f6.js
@@ -0,0 +1,11393 @@
+/*
+ * ATTENTION: An "eval-source-map" devtool has been used.
+ * This devtool is neither made for production nor for readable output files.
+ * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
+ * or disable the default devtool with "devtool: false".
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
+ */
+(globalThis["webpackChunkExcalidrawLib"] = globalThis["webpackChunkExcalidrawLib"] || []).push([["vendor"],{
+
+/***/ "../../../node_modules/@excalidraw/markdown-to-text/dist/index.js":
+/*!************************************************************************!*\
+ !*** ../../../node_modules/@excalidraw/markdown-to-text/dist/index.js ***!
+ \************************************************************************/
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.removeMarkdown = void 0;\n/**\n * @function removeMarkdown\n *\n * @description\n * Parse the markdown and returns a string\n *\n * @param markdown - The markdown string to parse\n * @param options - The options for the function\n *\n * @returns The parsed plain text\n */\nvar removeMarkdown = function (markdown, options) {\n if (options === void 0) { options = {\n listUnicodeChar: \"\",\n }; }\n options = options || {};\n options.listUnicodeChar = options.hasOwnProperty(\"listUnicodeChar\")\n ? options.listUnicodeChar\n : false;\n options.stripListLeaders = options.hasOwnProperty(\"stripListLeaders\")\n ? options.stripListLeaders\n : true;\n options.gfm = options.hasOwnProperty(\"gfm\") ? options.gfm : true;\n options.useImgAltText = options.hasOwnProperty(\"useImgAltText\")\n ? options.useImgAltText\n : true;\n options.preserveLinks = options.hasOwnProperty(\"preserveLinks\")\n ? options.preserveLinks\n : false;\n var output = markdown || \"\";\n // Remove horizontal rules (stripListHeaders conflict with this rule, which is why it has been moved to the top)\n output = output.replace(/^(-\\s*?|\\*\\s*?|_\\s*?){3,}\\s*$/gm, \"\");\n try {\n if (options.stripListLeaders) {\n if (options.listUnicodeChar)\n output = output.replace(/^([\\s\\t]*)([\\*\\-\\+]|\\d+\\.)\\s+/gm, options.listUnicodeChar + \" $1\");\n else\n output = output.replace(/^([\\s\\t]*)([\\*\\-\\+]|\\d+\\.)\\s+/gm, \"$1\");\n }\n if (options.gfm) {\n output = output\n // Header\n .replace(/\\n={2,}/g, \"\\n\")\n // Fenced codeblocks\n .replace(/~{3}.*\\n/g, \"\")\n // Strikethrough\n .replace(/~~/g, \"\")\n // Fenced codeblocks\n .replace(/`{3}.*\\n/g, \"\");\n }\n if (options.preserveLinks) {\n // Remove inline links while preserving the links\n output = output.replace(/\\[(.*?)\\][\\[\\(](.*?)[\\]\\)]/g, \"$1 ($2)\");\n }\n output = output\n // Remove HTML tags\n .replace(/<[^>]*>/g, \"\")\n // Remove setext-style headers\n .replace(/^[=\\-]{2,}\\s*$/g, \"\")\n // Remove footnotes?\n .replace(/\\[\\^.+?\\](\\: .*?$)?/g, \"\")\n .replace(/\\s{0,2}\\[.*?\\]: .*?$/g, \"\")\n // Remove images\n .replace(/\\!\\[(.*?)\\][\\[\\(].*?[\\]\\)]/g, options.useImgAltText ? \"$1\" : \"\")\n // Remove inline links\n .replace(/\\[(.*?)\\][\\[\\(].*?[\\]\\)]/g, \"$1\")\n // Remove blockquotes\n .replace(/^\\s{0,3}>\\s?/g, \"\")\n .replace(/(^|\\n)\\s{0,3}>\\s?/g, \"\\n\\n\")\n // Remove reference-style links?\n .replace(/^\\s{1,2}\\[(.*?)\\]: (\\S+)( \".*?\")?\\s*$/g, \"\")\n // Remove atx-style headers\n .replace(/^(\\n)?\\s{0,}#{1,6}\\s+| {0,}(\\n)?\\s{0,}#{0,} {0,}(\\n)?\\s{0,}$/gm, \"$1$2$3\")\n // Remove emphasis (repeat the line to remove double emphasis)\n .replace(/([\\*_]{1,3})(\\S.*?\\S{0,1})\\1/g, \"$2\")\n .replace(/([\\*_]{1,3})(\\S.*?\\S{0,1})\\1/g, \"$2\")\n // Remove code blocks\n .replace(/(`{3,})(.*?)\\1/gm, \"$2\")\n // Remove inline code\n .replace(/`(.+?)`/g, \"$1\")\n // Replace two or more newlines with exactly two? Not entirely sure this belongs here...\n .replace(/\\n{2,}/g, \"\\n\\n\");\n }\n catch (e) {\n console.error(e);\n return markdown;\n }\n return output;\n};\nexports.removeMarkdown = removeMarkdown;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vLi4vbm9kZV9tb2R1bGVzL0BleGNhbGlkcmF3L21hcmtkb3duLXRvLXRleHQvZGlzdC9pbmRleC5qcy5qcyIsIm1hcHBpbmdzIjoiQUFBYTtBQUNiLDhDQUE2QyxFQUFFLGFBQWEsRUFBQztBQUM3RCxzQkFBc0I7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1EQUFtRCxHQUFHO0FBQ3REO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCLEdBQUc7QUFDakM7QUFDQSw0QkFBNEIsRUFBRTtBQUM5QjtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIsRUFBRTtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2QkFBNkIsR0FBRztBQUNoQztBQUNBO0FBQ0EseUJBQXlCLElBQUk7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixJQUFJO0FBQzlCLCtCQUErQixJQUFJO0FBQ25DO0FBQ0EsMEJBQTBCLElBQUk7QUFDOUI7QUFDQSwrQkFBK0IsR0FBRyxFQUFFLElBQUksTUFBTSxHQUFHLFFBQVEsR0FBRyxFQUFFLEtBQUssR0FBRyxRQUFRLEdBQUc7QUFDakY7QUFDQSw2QkFBNkIsSUFBSSxVQUFVLElBQUk7QUFDL0MsNkJBQTZCLElBQUksVUFBVSxJQUFJO0FBQy9DO0FBQ0EseUJBQXlCLEdBQUc7QUFDNUI7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLEdBQUc7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vLi4vbm9kZV9tb2R1bGVzL0BleGNhbGlkcmF3L21hcmtkb3duLXRvLXRleHQvZGlzdC9pbmRleC5qcz9jMDcyIl0sInNvdXJjZXNDb250ZW50IjpbIlwidXNlIHN0cmljdFwiO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZXhwb3J0cy5yZW1vdmVNYXJrZG93biA9IHZvaWQgMDtcbi8qKlxuICogQGZ1bmN0aW9uIHJlbW92ZU1hcmtkb3duXG4gKlxuICogQGRlc2NyaXB0aW9uXG4gKiBQYXJzZSB0aGUgbWFya2Rvd24gYW5kIHJldHVybnMgYSBzdHJpbmdcbiAqXG4gKiBAcGFyYW0gbWFya2Rvd24gLSBUaGUgbWFya2Rvd24gc3RyaW5nIHRvIHBhcnNlXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgZnVuY3Rpb25cbiAqXG4gKiBAcmV0dXJucyBUaGUgcGFyc2VkIHBsYWluIHRleHRcbiAqL1xudmFyIHJlbW92ZU1hcmtkb3duID0gZnVuY3Rpb24gKG1hcmtkb3duLCBvcHRpb25zKSB7XG4gICAgaWYgKG9wdGlvbnMgPT09IHZvaWQgMCkgeyBvcHRpb25zID0ge1xuICAgICAgICBsaXN0VW5pY29kZUNoYXI6IFwiXCIsXG4gICAgfTsgfVxuICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIG9wdGlvbnMubGlzdFVuaWNvZGVDaGFyID0gb3B0aW9ucy5oYXNPd25Qcm9wZXJ0eShcImxpc3RVbmljb2RlQ2hhclwiKVxuICAgICAgICA/IG9wdGlvbnMubGlzdFVuaWNvZGVDaGFyXG4gICAgICAgIDogZmFsc2U7XG4gICAgb3B0aW9ucy5zdHJpcExpc3RMZWFkZXJzID0gb3B0aW9ucy5oYXNPd25Qcm9wZXJ0eShcInN0cmlwTGlzdExlYWRlcnNcIilcbiAgICAgICAgPyBvcHRpb25zLnN0cmlwTGlzdExlYWRlcnNcbiAgICAgICAgOiB0cnVlO1xuICAgIG9wdGlvbnMuZ2ZtID0gb3B0aW9ucy5oYXNPd25Qcm9wZXJ0eShcImdmbVwiKSA/IG9wdGlvbnMuZ2ZtIDogdHJ1ZTtcbiAgICBvcHRpb25zLnVzZUltZ0FsdFRleHQgPSBvcHRpb25zLmhhc093blByb3BlcnR5KFwidXNlSW1nQWx0VGV4dFwiKVxuICAgICAgICA/IG9wdGlvbnMudXNlSW1nQWx0VGV4dFxuICAgICAgICA6IHRydWU7XG4gICAgb3B0aW9ucy5wcmVzZXJ2ZUxpbmtzID0gb3B0aW9ucy5oYXNPd25Qcm9wZXJ0eShcInByZXNlcnZlTGlua3NcIilcbiAgICAgICAgPyBvcHRpb25zLnByZXNlcnZlTGlua3NcbiAgICAgICAgOiBmYWxzZTtcbiAgICB2YXIgb3V0cHV0ID0gbWFya2Rvd24gfHwgXCJcIjtcbiAgICAvLyBSZW1vdmUgaG9yaXpvbnRhbCBydWxlcyAoc3RyaXBMaXN0SGVhZGVycyBjb25mbGljdCB3aXRoIHRoaXMgcnVsZSwgd2hpY2ggaXMgd2h5IGl0IGhhcyBiZWVuIG1vdmVkIHRvIHRoZSB0b3ApXG4gICAgb3V0cHV0ID0gb3V0cHV0LnJlcGxhY2UoL14oLVxccyo/fFxcKlxccyo/fF9cXHMqPyl7Myx9XFxzKiQvZ20sIFwiXCIpO1xuICAgIHRyeSB7XG4gICAgICAgIGlmIChvcHRpb25zLnN0cmlwTGlzdExlYWRlcnMpIHtcbiAgICAgICAgICAgIGlmIChvcHRpb25zLmxpc3RVbmljb2RlQ2hhcilcbiAgICAgICAgICAgICAgICBvdXRwdXQgPSBvdXRwdXQucmVwbGFjZSgvXihbXFxzXFx0XSopKFtcXCpcXC1cXCtdfFxcZCtcXC4pXFxzKy9nbSwgb3B0aW9ucy5saXN0VW5pY29kZUNoYXIgKyBcIiAkMVwiKTtcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBvdXRwdXQgPSBvdXRwdXQucmVwbGFjZSgvXihbXFxzXFx0XSopKFtcXCpcXC1cXCtdfFxcZCtcXC4pXFxzKy9nbSwgXCIkMVwiKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAob3B0aW9ucy5nZm0pIHtcbiAgICAgICAgICAgIG91dHB1dCA9IG91dHB1dFxuICAgICAgICAgICAgICAgIC8vIEhlYWRlclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXG49ezIsfS9nLCBcIlxcblwiKVxuICAgICAgICAgICAgICAgIC8vIEZlbmNlZCBjb2RlYmxvY2tzXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL357M30uKlxcbi9nLCBcIlwiKVxuICAgICAgICAgICAgICAgIC8vIFN0cmlrZXRocm91Z2hcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvfn4vZywgXCJcIilcbiAgICAgICAgICAgICAgICAvLyBGZW5jZWQgY29kZWJsb2Nrc1xuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9gezN9LipcXG4vZywgXCJcIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMucHJlc2VydmVMaW5rcykge1xuICAgICAgICAgICAgLy8gUmVtb3ZlIGlubGluZSBsaW5rcyB3aGlsZSBwcmVzZXJ2aW5nIHRoZSBsaW5rc1xuICAgICAgICAgICAgb3V0cHV0ID0gb3V0cHV0LnJlcGxhY2UoL1xcWyguKj8pXFxdW1xcW1xcKF0oLio/KVtcXF1cXCldL2csIFwiJDEgKCQyKVwiKTtcbiAgICAgICAgfVxuICAgICAgICBvdXRwdXQgPSBvdXRwdXRcbiAgICAgICAgICAgIC8vIFJlbW92ZSBIVE1MIHRhZ3NcbiAgICAgICAgICAgIC5yZXBsYWNlKC88W14+XSo+L2csIFwiXCIpXG4gICAgICAgICAgICAvLyBSZW1vdmUgc2V0ZXh0LXN0eWxlIGhlYWRlcnNcbiAgICAgICAgICAgIC5yZXBsYWNlKC9eWz1cXC1dezIsfVxccyokL2csIFwiXCIpXG4gICAgICAgICAgICAvLyBSZW1vdmUgZm9vdG5vdGVzP1xuICAgICAgICAgICAgLnJlcGxhY2UoL1xcW1xcXi4rP1xcXShcXDogLio/JCk/L2csIFwiXCIpXG4gICAgICAgICAgICAucmVwbGFjZSgvXFxzezAsMn1cXFsuKj9cXF06IC4qPyQvZywgXCJcIilcbiAgICAgICAgICAgIC8vIFJlbW92ZSBpbWFnZXNcbiAgICAgICAgICAgIC5yZXBsYWNlKC9cXCFcXFsoLio/KVxcXVtcXFtcXChdLio/W1xcXVxcKV0vZywgb3B0aW9ucy51c2VJbWdBbHRUZXh0ID8gXCIkMVwiIDogXCJcIilcbiAgICAgICAgICAgIC8vIFJlbW92ZSBpbmxpbmUgbGlua3NcbiAgICAgICAgICAgIC5yZXBsYWNlKC9cXFsoLio/KVxcXVtcXFtcXChdLio/W1xcXVxcKV0vZywgXCIkMVwiKVxuICAgICAgICAgICAgLy8gUmVtb3ZlIGJsb2NrcXVvdGVzXG4gICAgICAgICAgICAucmVwbGFjZSgvXlxcc3swLDN9Plxccz8vZywgXCJcIilcbiAgICAgICAgICAgIC5yZXBsYWNlKC8oXnxcXG4pXFxzezAsM30+XFxzPy9nLCBcIlxcblxcblwiKVxuICAgICAgICAgICAgLy8gUmVtb3ZlIHJlZmVyZW5jZS1zdHlsZSBsaW5rcz9cbiAgICAgICAgICAgIC5yZXBsYWNlKC9eXFxzezEsMn1cXFsoLio/KVxcXTogKFxcUyspKCBcIi4qP1wiKT9cXHMqJC9nLCBcIlwiKVxuICAgICAgICAgICAgLy8gUmVtb3ZlIGF0eC1zdHlsZSBoZWFkZXJzXG4gICAgICAgICAgICAucmVwbGFjZSgvXihcXG4pP1xcc3swLH0jezEsNn1cXHMrfCB7MCx9KFxcbik/XFxzezAsfSN7MCx9IHswLH0oXFxuKT9cXHN7MCx9JC9nbSwgXCIkMSQyJDNcIilcbiAgICAgICAgICAgIC8vIFJlbW92ZSBlbXBoYXNpcyAocmVwZWF0IHRoZSBsaW5lIHRvIHJlbW92ZSBkb3VibGUgZW1waGFzaXMpXG4gICAgICAgICAgICAucmVwbGFjZSgvKFtcXCpfXXsxLDN9KShcXFMuKj9cXFN7MCwxfSlcXDEvZywgXCIkMlwiKVxuICAgICAgICAgICAgLnJlcGxhY2UoLyhbXFwqX117MSwzfSkoXFxTLio/XFxTezAsMX0pXFwxL2csIFwiJDJcIilcbiAgICAgICAgICAgIC8vIFJlbW92ZSBjb2RlIGJsb2Nrc1xuICAgICAgICAgICAgLnJlcGxhY2UoLyhgezMsfSkoLio/KVxcMS9nbSwgXCIkMlwiKVxuICAgICAgICAgICAgLy8gUmVtb3ZlIGlubGluZSBjb2RlXG4gICAgICAgICAgICAucmVwbGFjZSgvYCguKz8pYC9nLCBcIiQxXCIpXG4gICAgICAgICAgICAvLyBSZXBsYWNlIHR3byBvciBtb3JlIG5ld2xpbmVzIHdpdGggZXhhY3RseSB0d28/IE5vdCBlbnRpcmVseSBzdXJlIHRoaXMgYmVsb25ncyBoZXJlLi4uXG4gICAgICAgICAgICAucmVwbGFjZSgvXFxuezIsfS9nLCBcIlxcblxcblwiKTtcbiAgICB9XG4gICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgICAgcmV0dXJuIG1hcmtkb3duO1xuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0O1xufTtcbmV4cG9ydHMucmVtb3ZlTWFya2Rvd24gPSByZW1vdmVNYXJrZG93bjtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../../node_modules/@excalidraw/markdown-to-text/dist/index.js\n");
+
+/***/ }),
+
+/***/ "../../../node_modules/cose-base/cose-base.js":
+/*!****************************************************!*\
+ !*** ../../../node_modules/cose-base/cose-base.js ***!
+ \****************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+eval("(function webpackUniversalModuleDefinition(root, factory) {\n\tif(true)\n\t\tmodule.exports = factory(__webpack_require__(/*! layout-base */ \"../../../node_modules/layout-base/layout-base.js\"));\n\telse {}\n})(this, function(__WEBPACK_EXTERNAL_MODULE_0__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __nested_webpack_require_643__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __nested_webpack_require_643__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__nested_webpack_require_643__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__nested_webpack_require_643__.c = installedModules;\n/******/\n/******/ \t// identity function for calling harmony imports with the correct context\n/******/ \t__nested_webpack_require_643__.i = function(value) { return value; };\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__nested_webpack_require_643__.d = function(exports, name, getter) {\n/******/ \t\tif(!__nested_webpack_require_643__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__nested_webpack_require_643__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__nested_webpack_require_643__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__nested_webpack_require_643__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__nested_webpack_require_643__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __nested_webpack_require_643__(__nested_webpack_require_643__.s = 7);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE_0__;\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __nested_webpack_require_3185__) {\n\n\"use strict\";\n\n\nvar FDLayoutConstants = __nested_webpack_require_3185__(0).FDLayoutConstants;\n\nfunction CoSEConstants() {}\n\n//CoSEConstants inherits static props in FDLayoutConstants\nfor (var prop in FDLayoutConstants) {\n CoSEConstants[prop] = FDLayoutConstants[prop];\n}\n\nCoSEConstants.DEFAULT_USE_MULTI_LEVEL_SCALING = false;\nCoSEConstants.DEFAULT_RADIAL_SEPARATION = FDLayoutConstants.DEFAULT_EDGE_LENGTH;\nCoSEConstants.DEFAULT_COMPONENT_SEPERATION = 60;\nCoSEConstants.TILE = true;\nCoSEConstants.TILING_PADDING_VERTICAL = 10;\nCoSEConstants.TILING_PADDING_HORIZONTAL = 10;\nCoSEConstants.TREE_REDUCTION_ON_INCREMENTAL = false; // make this true when cose is used incrementally as a part of other non-incremental layout\n\nmodule.exports = CoSEConstants;\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports, __nested_webpack_require_4002__) {\n\n\"use strict\";\n\n\nvar FDLayoutEdge = __nested_webpack_require_4002__(0).FDLayoutEdge;\n\nfunction CoSEEdge(source, target, vEdge) {\n FDLayoutEdge.call(this, source, target, vEdge);\n}\n\nCoSEEdge.prototype = Object.create(FDLayoutEdge.prototype);\nfor (var prop in FDLayoutEdge) {\n CoSEEdge[prop] = FDLayoutEdge[prop];\n}\n\nmodule.exports = CoSEEdge;\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __nested_webpack_require_4409__) {\n\n\"use strict\";\n\n\nvar LGraph = __nested_webpack_require_4409__(0).LGraph;\n\nfunction CoSEGraph(parent, graphMgr, vGraph) {\n LGraph.call(this, parent, graphMgr, vGraph);\n}\n\nCoSEGraph.prototype = Object.create(LGraph.prototype);\nfor (var prop in LGraph) {\n CoSEGraph[prop] = LGraph[prop];\n}\n\nmodule.exports = CoSEGraph;\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __nested_webpack_require_4790__) {\n\n\"use strict\";\n\n\nvar LGraphManager = __nested_webpack_require_4790__(0).LGraphManager;\n\nfunction CoSEGraphManager(layout) {\n LGraphManager.call(this, layout);\n}\n\nCoSEGraphManager.prototype = Object.create(LGraphManager.prototype);\nfor (var prop in LGraphManager) {\n CoSEGraphManager[prop] = LGraphManager[prop];\n}\n\nmodule.exports = CoSEGraphManager;\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports, __nested_webpack_require_5205__) {\n\n\"use strict\";\n\n\nvar FDLayoutNode = __nested_webpack_require_5205__(0).FDLayoutNode;\nvar IMath = __nested_webpack_require_5205__(0).IMath;\n\nfunction CoSENode(gm, loc, size, vNode) {\n FDLayoutNode.call(this, gm, loc, size, vNode);\n}\n\nCoSENode.prototype = Object.create(FDLayoutNode.prototype);\nfor (var prop in FDLayoutNode) {\n CoSENode[prop] = FDLayoutNode[prop];\n}\n\nCoSENode.prototype.move = function () {\n var layout = this.graphManager.getLayout();\n this.displacementX = layout.coolingFactor * (this.springForceX + this.repulsionForceX + this.gravitationForceX) / this.noOfChildren;\n this.displacementY = layout.coolingFactor * (this.springForceY + this.repulsionForceY + this.gravitationForceY) / this.noOfChildren;\n\n if (Math.abs(this.displacementX) > layout.coolingFactor * layout.maxNodeDisplacement) {\n this.displacementX = layout.coolingFactor * layout.maxNodeDisplacement * IMath.sign(this.displacementX);\n }\n\n if (Math.abs(this.displacementY) > layout.coolingFactor * layout.maxNodeDisplacement) {\n this.displacementY = layout.coolingFactor * layout.maxNodeDisplacement * IMath.sign(this.displacementY);\n }\n\n // a simple node, just move it\n if (this.child == null) {\n this.moveBy(this.displacementX, this.displacementY);\n }\n // an empty compound node, again just move it\n else if (this.child.getNodes().length == 0) {\n this.moveBy(this.displacementX, this.displacementY);\n }\n // non-empty compound node, propogate movement to children as well\n else {\n this.propogateDisplacementToChildren(this.displacementX, this.displacementY);\n }\n\n layout.totalDisplacement += Math.abs(this.displacementX) + Math.abs(this.displacementY);\n\n this.springForceX = 0;\n this.springForceY = 0;\n this.repulsionForceX = 0;\n this.repulsionForceY = 0;\n this.gravitationForceX = 0;\n this.gravitationForceY = 0;\n this.displacementX = 0;\n this.displacementY = 0;\n};\n\nCoSENode.prototype.propogateDisplacementToChildren = function (dX, dY) {\n var nodes = this.getChild().getNodes();\n var node;\n for (var i = 0; i < nodes.length; i++) {\n node = nodes[i];\n if (node.getChild() == null) {\n node.moveBy(dX, dY);\n node.displacementX += dX;\n node.displacementY += dY;\n } else {\n node.propogateDisplacementToChildren(dX, dY);\n }\n }\n};\n\nCoSENode.prototype.setPred1 = function (pred1) {\n this.pred1 = pred1;\n};\n\nCoSENode.prototype.getPred1 = function () {\n return pred1;\n};\n\nCoSENode.prototype.getPred2 = function () {\n return pred2;\n};\n\nCoSENode.prototype.setNext = function (next) {\n this.next = next;\n};\n\nCoSENode.prototype.getNext = function () {\n return next;\n};\n\nCoSENode.prototype.setProcessed = function (processed) {\n this.processed = processed;\n};\n\nCoSENode.prototype.isProcessed = function () {\n return processed;\n};\n\nmodule.exports = CoSENode;\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports, __nested_webpack_require_8085__) {\n\n\"use strict\";\n\n\nvar FDLayout = __nested_webpack_require_8085__(0).FDLayout;\nvar CoSEGraphManager = __nested_webpack_require_8085__(4);\nvar CoSEGraph = __nested_webpack_require_8085__(3);\nvar CoSENode = __nested_webpack_require_8085__(5);\nvar CoSEEdge = __nested_webpack_require_8085__(2);\nvar CoSEConstants = __nested_webpack_require_8085__(1);\nvar FDLayoutConstants = __nested_webpack_require_8085__(0).FDLayoutConstants;\nvar LayoutConstants = __nested_webpack_require_8085__(0).LayoutConstants;\nvar Point = __nested_webpack_require_8085__(0).Point;\nvar PointD = __nested_webpack_require_8085__(0).PointD;\nvar Layout = __nested_webpack_require_8085__(0).Layout;\nvar Integer = __nested_webpack_require_8085__(0).Integer;\nvar IGeometry = __nested_webpack_require_8085__(0).IGeometry;\nvar LGraph = __nested_webpack_require_8085__(0).LGraph;\nvar Transform = __nested_webpack_require_8085__(0).Transform;\n\nfunction CoSELayout() {\n FDLayout.call(this);\n\n this.toBeTiled = {}; // Memorize if a node is to be tiled or is tiled\n}\n\nCoSELayout.prototype = Object.create(FDLayout.prototype);\n\nfor (var prop in FDLayout) {\n CoSELayout[prop] = FDLayout[prop];\n}\n\nCoSELayout.prototype.newGraphManager = function () {\n var gm = new CoSEGraphManager(this);\n this.graphManager = gm;\n return gm;\n};\n\nCoSELayout.prototype.newGraph = function (vGraph) {\n return new CoSEGraph(null, this.graphManager, vGraph);\n};\n\nCoSELayout.prototype.newNode = function (vNode) {\n return new CoSENode(this.graphManager, vNode);\n};\n\nCoSELayout.prototype.newEdge = function (vEdge) {\n return new CoSEEdge(null, null, vEdge);\n};\n\nCoSELayout.prototype.initParameters = function () {\n FDLayout.prototype.initParameters.call(this, arguments);\n if (!this.isSubLayout) {\n if (CoSEConstants.DEFAULT_EDGE_LENGTH < 10) {\n this.idealEdgeLength = 10;\n } else {\n this.idealEdgeLength = CoSEConstants.DEFAULT_EDGE_LENGTH;\n }\n\n this.useSmartIdealEdgeLengthCalculation = CoSEConstants.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION;\n this.springConstant = FDLayoutConstants.DEFAULT_SPRING_STRENGTH;\n this.repulsionConstant = FDLayoutConstants.DEFAULT_REPULSION_STRENGTH;\n this.gravityConstant = FDLayoutConstants.DEFAULT_GRAVITY_STRENGTH;\n this.compoundGravityConstant = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_STRENGTH;\n this.gravityRangeFactor = FDLayoutConstants.DEFAULT_GRAVITY_RANGE_FACTOR;\n this.compoundGravityRangeFactor = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR;\n\n // variables for tree reduction support\n this.prunedNodesAll = [];\n this.growTreeIterations = 0;\n this.afterGrowthIterations = 0;\n this.isTreeGrowing = false;\n this.isGrowthFinished = false;\n\n // variables for cooling\n this.coolingCycle = 0;\n this.maxCoolingCycle = this.maxIterations / FDLayoutConstants.CONVERGENCE_CHECK_PERIOD;\n this.finalTemperature = FDLayoutConstants.CONVERGENCE_CHECK_PERIOD / this.maxIterations;\n this.coolingAdjuster = 1;\n }\n};\n\nCoSELayout.prototype.layout = function () {\n var createBendsAsNeeded = LayoutConstants.DEFAULT_CREATE_BENDS_AS_NEEDED;\n if (createBendsAsNeeded) {\n this.createBendpoints();\n this.graphManager.resetAllEdges();\n }\n\n this.level = 0;\n return this.classicLayout();\n};\n\nCoSELayout.prototype.classicLayout = function () {\n this.nodesWithGravity = this.calculateNodesToApplyGravitationTo();\n this.graphManager.setAllNodesToApplyGravitation(this.nodesWithGravity);\n this.calcNoOfChildrenForAllNodes();\n this.graphManager.calcLowestCommonAncestors();\n this.graphManager.calcInclusionTreeDepths();\n this.graphManager.getRoot().calcEstimatedSize();\n this.calcIdealEdgeLengths();\n\n if (!this.incremental) {\n var forest = this.getFlatForest();\n\n // The graph associated with this layout is flat and a forest\n if (forest.length > 0) {\n this.positionNodesRadially(forest);\n }\n // The graph associated with this layout is not flat or a forest\n else {\n // Reduce the trees when incremental mode is not enabled and graph is not a forest \n this.reduceTrees();\n // Update nodes that gravity will be applied\n this.graphManager.resetAllNodesToApplyGravitation();\n var allNodes = new Set(this.getAllNodes());\n var intersection = this.nodesWithGravity.filter(function (x) {\n return allNodes.has(x);\n });\n this.graphManager.setAllNodesToApplyGravitation(intersection);\n\n this.positionNodesRandomly();\n }\n } else {\n if (CoSEConstants.TREE_REDUCTION_ON_INCREMENTAL) {\n // Reduce the trees in incremental mode if only this constant is set to true \n this.reduceTrees();\n // Update nodes that gravity will be applied\n this.graphManager.resetAllNodesToApplyGravitation();\n var allNodes = new Set(this.getAllNodes());\n var intersection = this.nodesWithGravity.filter(function (x) {\n return allNodes.has(x);\n });\n this.graphManager.setAllNodesToApplyGravitation(intersection);\n }\n }\n\n this.initSpringEmbedder();\n this.runSpringEmbedder();\n\n return true;\n};\n\nCoSELayout.prototype.tick = function () {\n this.totalIterations++;\n\n if (this.totalIterations === this.maxIterations && !this.isTreeGrowing && !this.isGrowthFinished) {\n if (this.prunedNodesAll.length > 0) {\n this.isTreeGrowing = true;\n } else {\n return true;\n }\n }\n\n if (this.totalIterations % FDLayoutConstants.CONVERGENCE_CHECK_PERIOD == 0 && !this.isTreeGrowing && !this.isGrowthFinished) {\n if (this.isConverged()) {\n if (this.prunedNodesAll.length > 0) {\n this.isTreeGrowing = true;\n } else {\n return true;\n }\n }\n\n this.coolingCycle++;\n\n if (this.layoutQuality == 0) {\n // quality - \"draft\"\n this.coolingAdjuster = this.coolingCycle;\n } else if (this.layoutQuality == 1) {\n // quality - \"default\"\n this.coolingAdjuster = this.coolingCycle / 3;\n }\n\n // cooling schedule is based on http://www.btluke.com/simanf1.html -> cooling schedule 3\n this.coolingFactor = Math.max(this.initialCoolingFactor - Math.pow(this.coolingCycle, Math.log(100 * (this.initialCoolingFactor - this.finalTemperature)) / Math.log(this.maxCoolingCycle)) / 100 * this.coolingAdjuster, this.finalTemperature);\n this.animationPeriod = Math.ceil(this.initialAnimationPeriod * Math.sqrt(this.coolingFactor));\n }\n // Operations while tree is growing again \n if (this.isTreeGrowing) {\n if (this.growTreeIterations % 10 == 0) {\n if (this.prunedNodesAll.length > 0) {\n this.graphManager.updateBounds();\n this.updateGrid();\n this.growTree(this.prunedNodesAll);\n // Update nodes that gravity will be applied\n this.graphManager.resetAllNodesToApplyGravitation();\n var allNodes = new Set(this.getAllNodes());\n var intersection = this.nodesWithGravity.filter(function (x) {\n return allNodes.has(x);\n });\n this.graphManager.setAllNodesToApplyGravitation(intersection);\n\n this.graphManager.updateBounds();\n this.updateGrid();\n this.coolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL;\n } else {\n this.isTreeGrowing = false;\n this.isGrowthFinished = true;\n }\n }\n this.growTreeIterations++;\n }\n // Operations after growth is finished\n if (this.isGrowthFinished) {\n if (this.isConverged()) {\n return true;\n }\n if (this.afterGrowthIterations % 10 == 0) {\n this.graphManager.updateBounds();\n this.updateGrid();\n }\n this.coolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL * ((100 - this.afterGrowthIterations) / 100);\n this.afterGrowthIterations++;\n }\n\n var gridUpdateAllowed = !this.isTreeGrowing && !this.isGrowthFinished;\n var forceToNodeSurroundingUpdate = this.growTreeIterations % 10 == 1 && this.isTreeGrowing || this.afterGrowthIterations % 10 == 1 && this.isGrowthFinished;\n\n this.totalDisplacement = 0;\n this.graphManager.updateBounds();\n this.calcSpringForces();\n this.calcRepulsionForces(gridUpdateAllowed, forceToNodeSurroundingUpdate);\n this.calcGravitationalForces();\n this.moveNodes();\n this.animate();\n\n return false; // Layout is not ended yet return false\n};\n\nCoSELayout.prototype.getPositionsData = function () {\n var allNodes = this.graphManager.getAllNodes();\n var pData = {};\n for (var i = 0; i < allNodes.length; i++) {\n var rect = allNodes[i].rect;\n var id = allNodes[i].id;\n pData[id] = {\n id: id,\n x: rect.getCenterX(),\n y: rect.getCenterY(),\n w: rect.width,\n h: rect.height\n };\n }\n\n return pData;\n};\n\nCoSELayout.prototype.runSpringEmbedder = function () {\n this.initialAnimationPeriod = 25;\n this.animationPeriod = this.initialAnimationPeriod;\n var layoutEnded = false;\n\n // If aminate option is 'during' signal that layout is supposed to start iterating\n if (FDLayoutConstants.ANIMATE === 'during') {\n this.emit('layoutstarted');\n } else {\n // If aminate option is 'during' tick() function will be called on index.js\n while (!layoutEnded) {\n layoutEnded = this.tick();\n }\n\n this.graphManager.updateBounds();\n }\n};\n\nCoSELayout.prototype.calculateNodesToApplyGravitationTo = function () {\n var nodeList = [];\n var graph;\n\n var graphs = this.graphManager.getGraphs();\n var size = graphs.length;\n var i;\n for (i = 0; i < size; i++) {\n graph = graphs[i];\n\n graph.updateConnected();\n\n if (!graph.isConnected) {\n nodeList = nodeList.concat(graph.getNodes());\n }\n }\n\n return nodeList;\n};\n\nCoSELayout.prototype.createBendpoints = function () {\n var edges = [];\n edges = edges.concat(this.graphManager.getAllEdges());\n var visited = new Set();\n var i;\n for (i = 0; i < edges.length; i++) {\n var edge = edges[i];\n\n if (!visited.has(edge)) {\n var source = edge.getSource();\n var target = edge.getTarget();\n\n if (source == target) {\n edge.getBendpoints().push(new PointD());\n edge.getBendpoints().push(new PointD());\n this.createDummyNodesForBendpoints(edge);\n visited.add(edge);\n } else {\n var edgeList = [];\n\n edgeList = edgeList.concat(source.getEdgeListToNode(target));\n edgeList = edgeList.concat(target.getEdgeListToNode(source));\n\n if (!visited.has(edgeList[0])) {\n if (edgeList.length > 1) {\n var k;\n for (k = 0; k < edgeList.length; k++) {\n var multiEdge = edgeList[k];\n multiEdge.getBendpoints().push(new PointD());\n this.createDummyNodesForBendpoints(multiEdge);\n }\n }\n edgeList.forEach(function (edge) {\n visited.add(edge);\n });\n }\n }\n }\n\n if (visited.size == edges.length) {\n break;\n }\n }\n};\n\nCoSELayout.prototype.positionNodesRadially = function (forest) {\n // We tile the trees to a grid row by row; first tree starts at (0,0)\n var currentStartingPoint = new Point(0, 0);\n var numberOfColumns = Math.ceil(Math.sqrt(forest.length));\n var height = 0;\n var currentY = 0;\n var currentX = 0;\n var point = new PointD(0, 0);\n\n for (var i = 0; i < forest.length; i++) {\n if (i % numberOfColumns == 0) {\n // Start of a new row, make the x coordinate 0, increment the\n // y coordinate with the max height of the previous row\n currentX = 0;\n currentY = height;\n\n if (i != 0) {\n currentY += CoSEConstants.DEFAULT_COMPONENT_SEPERATION;\n }\n\n height = 0;\n }\n\n var tree = forest[i];\n\n // Find the center of the tree\n var centerNode = Layout.findCenterOfTree(tree);\n\n // Set the staring point of the next tree\n currentStartingPoint.x = currentX;\n currentStartingPoint.y = currentY;\n\n // Do a radial layout starting with the center\n point = CoSELayout.radialLayout(tree, centerNode, currentStartingPoint);\n\n if (point.y > height) {\n height = Math.floor(point.y);\n }\n\n currentX = Math.floor(point.x + CoSEConstants.DEFAULT_COMPONENT_SEPERATION);\n }\n\n this.transform(new PointD(LayoutConstants.WORLD_CENTER_X - point.x / 2, LayoutConstants.WORLD_CENTER_Y - point.y / 2));\n};\n\nCoSELayout.radialLayout = function (tree, centerNode, startingPoint) {\n var radialSep = Math.max(this.maxDiagonalInTree(tree), CoSEConstants.DEFAULT_RADIAL_SEPARATION);\n CoSELayout.branchRadialLayout(centerNode, null, 0, 359, 0, radialSep);\n var bounds = LGraph.calculateBounds(tree);\n\n var transform = new Transform();\n transform.setDeviceOrgX(bounds.getMinX());\n transform.setDeviceOrgY(bounds.getMinY());\n transform.setWorldOrgX(startingPoint.x);\n transform.setWorldOrgY(startingPoint.y);\n\n for (var i = 0; i < tree.length; i++) {\n var node = tree[i];\n node.transform(transform);\n }\n\n var bottomRight = new PointD(bounds.getMaxX(), bounds.getMaxY());\n\n return transform.inverseTransformPoint(bottomRight);\n};\n\nCoSELayout.branchRadialLayout = function (node, parentOfNode, startAngle, endAngle, distance, radialSeparation) {\n // First, position this node by finding its angle.\n var halfInterval = (endAngle - startAngle + 1) / 2;\n\n if (halfInterval < 0) {\n halfInterval += 180;\n }\n\n var nodeAngle = (halfInterval + startAngle) % 360;\n var teta = nodeAngle * IGeometry.TWO_PI / 360;\n\n // Make polar to java cordinate conversion.\n var cos_teta = Math.cos(teta);\n var x_ = distance * Math.cos(teta);\n var y_ = distance * Math.sin(teta);\n\n node.setCenter(x_, y_);\n\n // Traverse all neighbors of this node and recursively call this\n // function.\n var neighborEdges = [];\n neighborEdges = neighborEdges.concat(node.getEdges());\n var childCount = neighborEdges.length;\n\n if (parentOfNode != null) {\n childCount--;\n }\n\n var branchCount = 0;\n\n var incEdgesCount = neighborEdges.length;\n var startIndex;\n\n var edges = node.getEdgesBetween(parentOfNode);\n\n // If there are multiple edges, prune them until there remains only one\n // edge.\n while (edges.length > 1) {\n //neighborEdges.remove(edges.remove(0));\n var temp = edges[0];\n edges.splice(0, 1);\n var index = neighborEdges.indexOf(temp);\n if (index >= 0) {\n neighborEdges.splice(index, 1);\n }\n incEdgesCount--;\n childCount--;\n }\n\n if (parentOfNode != null) {\n //assert edges.length == 1;\n startIndex = (neighborEdges.indexOf(edges[0]) + 1) % incEdgesCount;\n } else {\n startIndex = 0;\n }\n\n var stepAngle = Math.abs(endAngle - startAngle) / childCount;\n\n for (var i = startIndex; branchCount != childCount; i = ++i % incEdgesCount) {\n var currentNeighbor = neighborEdges[i].getOtherEnd(node);\n\n // Don't back traverse to root node in current tree.\n if (currentNeighbor == parentOfNode) {\n continue;\n }\n\n var childStartAngle = (startAngle + branchCount * stepAngle) % 360;\n var childEndAngle = (childStartAngle + stepAngle) % 360;\n\n CoSELayout.branchRadialLayout(currentNeighbor, node, childStartAngle, childEndAngle, distance + radialSeparation, radialSeparation);\n\n branchCount++;\n }\n};\n\nCoSELayout.maxDiagonalInTree = function (tree) {\n var maxDiagonal = Integer.MIN_VALUE;\n\n for (var i = 0; i < tree.length; i++) {\n var node = tree[i];\n var diagonal = node.getDiagonal();\n\n if (diagonal > maxDiagonal) {\n maxDiagonal = diagonal;\n }\n }\n\n return maxDiagonal;\n};\n\nCoSELayout.prototype.calcRepulsionRange = function () {\n // formula is 2 x (level + 1) x idealEdgeLength\n return 2 * (this.level + 1) * this.idealEdgeLength;\n};\n\n// Tiling methods\n\n// Group zero degree members whose parents are not to be tiled, create dummy parents where needed and fill memberGroups by their dummp parent id's\nCoSELayout.prototype.groupZeroDegreeMembers = function () {\n var self = this;\n // array of [parent_id x oneDegreeNode_id]\n var tempMemberGroups = {}; // A temporary map of parent node and its zero degree members\n this.memberGroups = {}; // A map of dummy parent node and its zero degree members whose parents are not to be tiled\n this.idToDummyNode = {}; // A map of id to dummy node \n\n var zeroDegree = []; // List of zero degree nodes whose parents are not to be tiled\n var allNodes = this.graphManager.getAllNodes();\n\n // Fill zero degree list\n for (var i = 0; i < allNodes.length; i++) {\n var node = allNodes[i];\n var parent = node.getParent();\n // If a node has zero degree and its parent is not to be tiled if exists add that node to zeroDegres list\n if (this.getNodeDegreeWithChildren(node) === 0 && (parent.id == undefined || !this.getToBeTiled(parent))) {\n zeroDegree.push(node);\n }\n }\n\n // Create a map of parent node and its zero degree members\n for (var i = 0; i < zeroDegree.length; i++) {\n var node = zeroDegree[i]; // Zero degree node itself\n var p_id = node.getParent().id; // Parent id\n\n if (typeof tempMemberGroups[p_id] === \"undefined\") tempMemberGroups[p_id] = [];\n\n tempMemberGroups[p_id] = tempMemberGroups[p_id].concat(node); // Push node to the list belongs to its parent in tempMemberGroups\n }\n\n // If there are at least two nodes at a level, create a dummy compound for them\n Object.keys(tempMemberGroups).forEach(function (p_id) {\n if (tempMemberGroups[p_id].length > 1) {\n var dummyCompoundId = \"DummyCompound_\" + p_id; // The id of dummy compound which will be created soon\n self.memberGroups[dummyCompoundId] = tempMemberGroups[p_id]; // Add dummy compound to memberGroups\n\n var parent = tempMemberGroups[p_id][0].getParent(); // The parent of zero degree nodes will be the parent of new dummy compound\n\n // Create a dummy compound with calculated id\n var dummyCompound = new CoSENode(self.graphManager);\n dummyCompound.id = dummyCompoundId;\n dummyCompound.paddingLeft = parent.paddingLeft || 0;\n dummyCompound.paddingRight = parent.paddingRight || 0;\n dummyCompound.paddingBottom = parent.paddingBottom || 0;\n dummyCompound.paddingTop = parent.paddingTop || 0;\n\n self.idToDummyNode[dummyCompoundId] = dummyCompound;\n\n var dummyParentGraph = self.getGraphManager().add(self.newGraph(), dummyCompound);\n var parentGraph = parent.getChild();\n\n // Add dummy compound to parent the graph\n parentGraph.add(dummyCompound);\n\n // For each zero degree node in this level remove it from its parent graph and add it to the graph of dummy parent\n for (var i = 0; i < tempMemberGroups[p_id].length; i++) {\n var node = tempMemberGroups[p_id][i];\n\n parentGraph.remove(node);\n dummyParentGraph.add(node);\n }\n }\n });\n};\n\nCoSELayout.prototype.clearCompounds = function () {\n var childGraphMap = {};\n var idToNode = {};\n\n // Get compound ordering by finding the inner one first\n this.performDFSOnCompounds();\n\n for (var i = 0; i < this.compoundOrder.length; i++) {\n\n idToNode[this.compoundOrder[i].id] = this.compoundOrder[i];\n childGraphMap[this.compoundOrder[i].id] = [].concat(this.compoundOrder[i].getChild().getNodes());\n\n // Remove children of compounds\n this.graphManager.remove(this.compoundOrder[i].getChild());\n this.compoundOrder[i].child = null;\n }\n\n this.graphManager.resetAllNodes();\n\n // Tile the removed children\n this.tileCompoundMembers(childGraphMap, idToNode);\n};\n\nCoSELayout.prototype.clearZeroDegreeMembers = function () {\n var self = this;\n var tiledZeroDegreePack = this.tiledZeroDegreePack = [];\n\n Object.keys(this.memberGroups).forEach(function (id) {\n var compoundNode = self.idToDummyNode[id]; // Get the dummy compound\n\n tiledZeroDegreePack[id] = self.tileNodes(self.memberGroups[id], compoundNode.paddingLeft + compoundNode.paddingRight);\n\n // Set the width and height of the dummy compound as calculated\n compoundNode.rect.width = tiledZeroDegreePack[id].width;\n compoundNode.rect.height = tiledZeroDegreePack[id].height;\n });\n};\n\nCoSELayout.prototype.repopulateCompounds = function () {\n for (var i = this.compoundOrder.length - 1; i >= 0; i--) {\n var lCompoundNode = this.compoundOrder[i];\n var id = lCompoundNode.id;\n var horizontalMargin = lCompoundNode.paddingLeft;\n var verticalMargin = lCompoundNode.paddingTop;\n\n this.adjustLocations(this.tiledMemberPack[id], lCompoundNode.rect.x, lCompoundNode.rect.y, horizontalMargin, verticalMargin);\n }\n};\n\nCoSELayout.prototype.repopulateZeroDegreeMembers = function () {\n var self = this;\n var tiledPack = this.tiledZeroDegreePack;\n\n Object.keys(tiledPack).forEach(function (id) {\n var compoundNode = self.idToDummyNode[id]; // Get the dummy compound by its id\n var horizontalMargin = compoundNode.paddingLeft;\n var verticalMargin = compoundNode.paddingTop;\n\n // Adjust the positions of nodes wrt its compound\n self.adjustLocations(tiledPack[id], compoundNode.rect.x, compoundNode.rect.y, horizontalMargin, verticalMargin);\n });\n};\n\nCoSELayout.prototype.getToBeTiled = function (node) {\n var id = node.id;\n //firstly check the previous results\n if (this.toBeTiled[id] != null) {\n return this.toBeTiled[id];\n }\n\n //only compound nodes are to be tiled\n var childGraph = node.getChild();\n if (childGraph == null) {\n this.toBeTiled[id] = false;\n return false;\n }\n\n var children = childGraph.getNodes(); // Get the children nodes\n\n //a compound node is not to be tiled if all of its compound children are not to be tiled\n for (var i = 0; i < children.length; i++) {\n var theChild = children[i];\n\n if (this.getNodeDegree(theChild) > 0) {\n this.toBeTiled[id] = false;\n return false;\n }\n\n //pass the children not having the compound structure\n if (theChild.getChild() == null) {\n this.toBeTiled[theChild.id] = false;\n continue;\n }\n\n if (!this.getToBeTiled(theChild)) {\n this.toBeTiled[id] = false;\n return false;\n }\n }\n this.toBeTiled[id] = true;\n return true;\n};\n\n// Get degree of a node depending of its edges and independent of its children\nCoSELayout.prototype.getNodeDegree = function (node) {\n var id = node.id;\n var edges = node.getEdges();\n var degree = 0;\n\n // For the edges connected\n for (var i = 0; i < edges.length; i++) {\n var edge = edges[i];\n if (edge.getSource().id !== edge.getTarget().id) {\n degree = degree + 1;\n }\n }\n return degree;\n};\n\n// Get degree of a node with its children\nCoSELayout.prototype.getNodeDegreeWithChildren = function (node) {\n var degree = this.getNodeDegree(node);\n if (node.getChild() == null) {\n return degree;\n }\n var children = node.getChild().getNodes();\n for (var i = 0; i < children.length; i++) {\n var child = children[i];\n degree += this.getNodeDegreeWithChildren(child);\n }\n return degree;\n};\n\nCoSELayout.prototype.performDFSOnCompounds = function () {\n this.compoundOrder = [];\n this.fillCompexOrderByDFS(this.graphManager.getRoot().getNodes());\n};\n\nCoSELayout.prototype.fillCompexOrderByDFS = function (children) {\n for (var i = 0; i < children.length; i++) {\n var child = children[i];\n if (child.getChild() != null) {\n this.fillCompexOrderByDFS(child.getChild().getNodes());\n }\n if (this.getToBeTiled(child)) {\n this.compoundOrder.push(child);\n }\n }\n};\n\n/**\n* This method places each zero degree member wrt given (x,y) coordinates (top left).\n*/\nCoSELayout.prototype.adjustLocations = function (organization, x, y, compoundHorizontalMargin, compoundVerticalMargin) {\n x += compoundHorizontalMargin;\n y += compoundVerticalMargin;\n\n var left = x;\n\n for (var i = 0; i < organization.rows.length; i++) {\n var row = organization.rows[i];\n x = left;\n var maxHeight = 0;\n\n for (var j = 0; j < row.length; j++) {\n var lnode = row[j];\n\n lnode.rect.x = x; // + lnode.rect.width / 2;\n lnode.rect.y = y; // + lnode.rect.height / 2;\n\n x += lnode.rect.width + organization.horizontalPadding;\n\n if (lnode.rect.height > maxHeight) maxHeight = lnode.rect.height;\n }\n\n y += maxHeight + organization.verticalPadding;\n }\n};\n\nCoSELayout.prototype.tileCompoundMembers = function (childGraphMap, idToNode) {\n var self = this;\n this.tiledMemberPack = [];\n\n Object.keys(childGraphMap).forEach(function (id) {\n // Get the compound node\n var compoundNode = idToNode[id];\n\n self.tiledMemberPack[id] = self.tileNodes(childGraphMap[id], compoundNode.paddingLeft + compoundNode.paddingRight);\n\n compoundNode.rect.width = self.tiledMemberPack[id].width;\n compoundNode.rect.height = self.tiledMemberPack[id].height;\n });\n};\n\nCoSELayout.prototype.tileNodes = function (nodes, minWidth) {\n var verticalPadding = CoSEConstants.TILING_PADDING_VERTICAL;\n var horizontalPadding = CoSEConstants.TILING_PADDING_HORIZONTAL;\n var organization = {\n rows: [],\n rowWidth: [],\n rowHeight: [],\n width: 0,\n height: minWidth, // assume minHeight equals to minWidth\n verticalPadding: verticalPadding,\n horizontalPadding: horizontalPadding\n };\n\n // Sort the nodes in ascending order of their areas\n nodes.sort(function (n1, n2) {\n if (n1.rect.width * n1.rect.height > n2.rect.width * n2.rect.height) return -1;\n if (n1.rect.width * n1.rect.height < n2.rect.width * n2.rect.height) return 1;\n return 0;\n });\n\n // Create the organization -> tile members\n for (var i = 0; i < nodes.length; i++) {\n var lNode = nodes[i];\n\n if (organization.rows.length == 0) {\n this.insertNodeToRow(organization, lNode, 0, minWidth);\n } else if (this.canAddHorizontal(organization, lNode.rect.width, lNode.rect.height)) {\n this.insertNodeToRow(organization, lNode, this.getShortestRowIndex(organization), minWidth);\n } else {\n this.insertNodeToRow(organization, lNode, organization.rows.length, minWidth);\n }\n\n this.shiftToLastRow(organization);\n }\n\n return organization;\n};\n\nCoSELayout.prototype.insertNodeToRow = function (organization, node, rowIndex, minWidth) {\n var minCompoundSize = minWidth;\n\n // Add new row if needed\n if (rowIndex == organization.rows.length) {\n var secondDimension = [];\n\n organization.rows.push(secondDimension);\n organization.rowWidth.push(minCompoundSize);\n organization.rowHeight.push(0);\n }\n\n // Update row width\n var w = organization.rowWidth[rowIndex] + node.rect.width;\n\n if (organization.rows[rowIndex].length > 0) {\n w += organization.horizontalPadding;\n }\n\n organization.rowWidth[rowIndex] = w;\n // Update compound width\n if (organization.width < w) {\n organization.width = w;\n }\n\n // Update height\n var h = node.rect.height;\n if (rowIndex > 0) h += organization.verticalPadding;\n\n var extraHeight = 0;\n if (h > organization.rowHeight[rowIndex]) {\n extraHeight = organization.rowHeight[rowIndex];\n organization.rowHeight[rowIndex] = h;\n extraHeight = organization.rowHeight[rowIndex] - extraHeight;\n }\n\n organization.height += extraHeight;\n\n // Insert node\n organization.rows[rowIndex].push(node);\n};\n\n//Scans the rows of an organization and returns the one with the min width\nCoSELayout.prototype.getShortestRowIndex = function (organization) {\n var r = -1;\n var min = Number.MAX_VALUE;\n\n for (var i = 0; i < organization.rows.length; i++) {\n if (organization.rowWidth[i] < min) {\n r = i;\n min = organization.rowWidth[i];\n }\n }\n return r;\n};\n\n//Scans the rows of an organization and returns the one with the max width\nCoSELayout.prototype.getLongestRowIndex = function (organization) {\n var r = -1;\n var max = Number.MIN_VALUE;\n\n for (var i = 0; i < organization.rows.length; i++) {\n\n if (organization.rowWidth[i] > max) {\n r = i;\n max = organization.rowWidth[i];\n }\n }\n\n return r;\n};\n\n/**\n* This method checks whether adding extra width to the organization violates\n* the aspect ratio(1) or not.\n*/\nCoSELayout.prototype.canAddHorizontal = function (organization, extraWidth, extraHeight) {\n\n var sri = this.getShortestRowIndex(organization);\n\n if (sri < 0) {\n return true;\n }\n\n var min = organization.rowWidth[sri];\n\n if (min + organization.horizontalPadding + extraWidth <= organization.width) return true;\n\n var hDiff = 0;\n\n // Adding to an existing row\n if (organization.rowHeight[sri] < extraHeight) {\n if (sri > 0) hDiff = extraHeight + organization.verticalPadding - organization.rowHeight[sri];\n }\n\n var add_to_row_ratio;\n if (organization.width - min >= extraWidth + organization.horizontalPadding) {\n add_to_row_ratio = (organization.height + hDiff) / (min + extraWidth + organization.horizontalPadding);\n } else {\n add_to_row_ratio = (organization.height + hDiff) / organization.width;\n }\n\n // Adding a new row for this node\n hDiff = extraHeight + organization.verticalPadding;\n var add_new_row_ratio;\n if (organization.width < extraWidth) {\n add_new_row_ratio = (organization.height + hDiff) / extraWidth;\n } else {\n add_new_row_ratio = (organization.height + hDiff) / organization.width;\n }\n\n if (add_new_row_ratio < 1) add_new_row_ratio = 1 / add_new_row_ratio;\n\n if (add_to_row_ratio < 1) add_to_row_ratio = 1 / add_to_row_ratio;\n\n return add_to_row_ratio < add_new_row_ratio;\n};\n\n//If moving the last node from the longest row and adding it to the last\n//row makes the bounding box smaller, do it.\nCoSELayout.prototype.shiftToLastRow = function (organization) {\n var longest = this.getLongestRowIndex(organization);\n var last = organization.rowWidth.length - 1;\n var row = organization.rows[longest];\n var node = row[row.length - 1];\n\n var diff = node.width + organization.horizontalPadding;\n\n // Check if there is enough space on the last row\n if (organization.width - organization.rowWidth[last] > diff && longest != last) {\n // Remove the last element of the longest row\n row.splice(-1, 1);\n\n // Push it to the last row\n organization.rows[last].push(node);\n\n organization.rowWidth[longest] = organization.rowWidth[longest] - diff;\n organization.rowWidth[last] = organization.rowWidth[last] + diff;\n organization.width = organization.rowWidth[instance.getLongestRowIndex(organization)];\n\n // Update heights of the organization\n var maxHeight = Number.MIN_VALUE;\n for (var i = 0; i < row.length; i++) {\n if (row[i].height > maxHeight) maxHeight = row[i].height;\n }\n if (longest > 0) maxHeight += organization.verticalPadding;\n\n var prevTotal = organization.rowHeight[longest] + organization.rowHeight[last];\n\n organization.rowHeight[longest] = maxHeight;\n if (organization.rowHeight[last] < node.height + organization.verticalPadding) organization.rowHeight[last] = node.height + organization.verticalPadding;\n\n var finalTotal = organization.rowHeight[longest] + organization.rowHeight[last];\n organization.height += finalTotal - prevTotal;\n\n this.shiftToLastRow(organization);\n }\n};\n\nCoSELayout.prototype.tilingPreLayout = function () {\n if (CoSEConstants.TILE) {\n // Find zero degree nodes and create a compound for each level\n this.groupZeroDegreeMembers();\n // Tile and clear children of each compound\n this.clearCompounds();\n // Separately tile and clear zero degree nodes for each level\n this.clearZeroDegreeMembers();\n }\n};\n\nCoSELayout.prototype.tilingPostLayout = function () {\n if (CoSEConstants.TILE) {\n this.repopulateZeroDegreeMembers();\n this.repopulateCompounds();\n }\n};\n\n// -----------------------------------------------------------------------------\n// Section: Tree Reduction methods\n// -----------------------------------------------------------------------------\n// Reduce trees \nCoSELayout.prototype.reduceTrees = function () {\n var prunedNodesAll = [];\n var containsLeaf = true;\n var node;\n\n while (containsLeaf) {\n var allNodes = this.graphManager.getAllNodes();\n var prunedNodesInStepTemp = [];\n containsLeaf = false;\n\n for (var i = 0; i < allNodes.length; i++) {\n node = allNodes[i];\n if (node.getEdges().length == 1 && !node.getEdges()[0].isInterGraph && node.getChild() == null) {\n prunedNodesInStepTemp.push([node, node.getEdges()[0], node.getOwner()]);\n containsLeaf = true;\n }\n }\n if (containsLeaf == true) {\n var prunedNodesInStep = [];\n for (var j = 0; j < prunedNodesInStepTemp.length; j++) {\n if (prunedNodesInStepTemp[j][0].getEdges().length == 1) {\n prunedNodesInStep.push(prunedNodesInStepTemp[j]);\n prunedNodesInStepTemp[j][0].getOwner().remove(prunedNodesInStepTemp[j][0]);\n }\n }\n prunedNodesAll.push(prunedNodesInStep);\n this.graphManager.resetAllNodes();\n this.graphManager.resetAllEdges();\n }\n }\n this.prunedNodesAll = prunedNodesAll;\n};\n\n// Grow tree one step \nCoSELayout.prototype.growTree = function (prunedNodesAll) {\n var lengthOfPrunedNodesInStep = prunedNodesAll.length;\n var prunedNodesInStep = prunedNodesAll[lengthOfPrunedNodesInStep - 1];\n\n var nodeData;\n for (var i = 0; i < prunedNodesInStep.length; i++) {\n nodeData = prunedNodesInStep[i];\n\n this.findPlaceforPrunedNode(nodeData);\n\n nodeData[2].add(nodeData[0]);\n nodeData[2].add(nodeData[1], nodeData[1].source, nodeData[1].target);\n }\n\n prunedNodesAll.splice(prunedNodesAll.length - 1, 1);\n this.graphManager.resetAllNodes();\n this.graphManager.resetAllEdges();\n};\n\n// Find an appropriate position to replace pruned node, this method can be improved\nCoSELayout.prototype.findPlaceforPrunedNode = function (nodeData) {\n\n var gridForPrunedNode;\n var nodeToConnect;\n var prunedNode = nodeData[0];\n if (prunedNode == nodeData[1].source) {\n nodeToConnect = nodeData[1].target;\n } else {\n nodeToConnect = nodeData[1].source;\n }\n var startGridX = nodeToConnect.startX;\n var finishGridX = nodeToConnect.finishX;\n var startGridY = nodeToConnect.startY;\n var finishGridY = nodeToConnect.finishY;\n\n var upNodeCount = 0;\n var downNodeCount = 0;\n var rightNodeCount = 0;\n var leftNodeCount = 0;\n var controlRegions = [upNodeCount, rightNodeCount, downNodeCount, leftNodeCount];\n\n if (startGridY > 0) {\n for (var i = startGridX; i <= finishGridX; i++) {\n controlRegions[0] += this.grid[i][startGridY - 1].length + this.grid[i][startGridY].length - 1;\n }\n }\n if (finishGridX < this.grid.length - 1) {\n for (var i = startGridY; i <= finishGridY; i++) {\n controlRegions[1] += this.grid[finishGridX + 1][i].length + this.grid[finishGridX][i].length - 1;\n }\n }\n if (finishGridY < this.grid[0].length - 1) {\n for (var i = startGridX; i <= finishGridX; i++) {\n controlRegions[2] += this.grid[i][finishGridY + 1].length + this.grid[i][finishGridY].length - 1;\n }\n }\n if (startGridX > 0) {\n for (var i = startGridY; i <= finishGridY; i++) {\n controlRegions[3] += this.grid[startGridX - 1][i].length + this.grid[startGridX][i].length - 1;\n }\n }\n var min = Integer.MAX_VALUE;\n var minCount;\n var minIndex;\n for (var j = 0; j < controlRegions.length; j++) {\n if (controlRegions[j] < min) {\n min = controlRegions[j];\n minCount = 1;\n minIndex = j;\n } else if (controlRegions[j] == min) {\n minCount++;\n }\n }\n\n if (minCount == 3 && min == 0) {\n if (controlRegions[0] == 0 && controlRegions[1] == 0 && controlRegions[2] == 0) {\n gridForPrunedNode = 1;\n } else if (controlRegions[0] == 0 && controlRegions[1] == 0 && controlRegions[3] == 0) {\n gridForPrunedNode = 0;\n } else if (controlRegions[0] == 0 && controlRegions[2] == 0 && controlRegions[3] == 0) {\n gridForPrunedNode = 3;\n } else if (controlRegions[1] == 0 && controlRegions[2] == 0 && controlRegions[3] == 0) {\n gridForPrunedNode = 2;\n }\n } else if (minCount == 2 && min == 0) {\n var random = Math.floor(Math.random() * 2);\n if (controlRegions[0] == 0 && controlRegions[1] == 0) {\n ;\n if (random == 0) {\n gridForPrunedNode = 0;\n } else {\n gridForPrunedNode = 1;\n }\n } else if (controlRegions[0] == 0 && controlRegions[2] == 0) {\n if (random == 0) {\n gridForPrunedNode = 0;\n } else {\n gridForPrunedNode = 2;\n }\n } else if (controlRegions[0] == 0 && controlRegions[3] == 0) {\n if (random == 0) {\n gridForPrunedNode = 0;\n } else {\n gridForPrunedNode = 3;\n }\n } else if (controlRegions[1] == 0 && controlRegions[2] == 0) {\n if (random == 0) {\n gridForPrunedNode = 1;\n } else {\n gridForPrunedNode = 2;\n }\n } else if (controlRegions[1] == 0 && controlRegions[3] == 0) {\n if (random == 0) {\n gridForPrunedNode = 1;\n } else {\n gridForPrunedNode = 3;\n }\n } else {\n if (random == 0) {\n gridForPrunedNode = 2;\n } else {\n gridForPrunedNode = 3;\n }\n }\n } else if (minCount == 4 && min == 0) {\n var random = Math.floor(Math.random() * 4);\n gridForPrunedNode = random;\n } else {\n gridForPrunedNode = minIndex;\n }\n\n if (gridForPrunedNode == 0) {\n prunedNode.setCenter(nodeToConnect.getCenterX(), nodeToConnect.getCenterY() - nodeToConnect.getHeight() / 2 - FDLayoutConstants.DEFAULT_EDGE_LENGTH - prunedNode.getHeight() / 2);\n } else if (gridForPrunedNode == 1) {\n prunedNode.setCenter(nodeToConnect.getCenterX() + nodeToConnect.getWidth() / 2 + FDLayoutConstants.DEFAULT_EDGE_LENGTH + prunedNode.getWidth() / 2, nodeToConnect.getCenterY());\n } else if (gridForPrunedNode == 2) {\n prunedNode.setCenter(nodeToConnect.getCenterX(), nodeToConnect.getCenterY() + nodeToConnect.getHeight() / 2 + FDLayoutConstants.DEFAULT_EDGE_LENGTH + prunedNode.getHeight() / 2);\n } else {\n prunedNode.setCenter(nodeToConnect.getCenterX() - nodeToConnect.getWidth() / 2 - FDLayoutConstants.DEFAULT_EDGE_LENGTH - prunedNode.getWidth() / 2, nodeToConnect.getCenterY());\n }\n};\n\nmodule.exports = CoSELayout;\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports, __nested_webpack_require_45620__) {\n\n\"use strict\";\n\n\nvar coseBase = {};\n\ncoseBase.layoutBase = __nested_webpack_require_45620__(0);\ncoseBase.CoSEConstants = __nested_webpack_require_45620__(1);\ncoseBase.CoSEEdge = __nested_webpack_require_45620__(2);\ncoseBase.CoSEGraph = __nested_webpack_require_45620__(3);\ncoseBase.CoSEGraphManager = __nested_webpack_require_45620__(4);\ncoseBase.CoSELayout = __nested_webpack_require_45620__(6);\ncoseBase.CoSENode = __nested_webpack_require_45620__(5);\n\nmodule.exports = coseBase;\n\n/***/ })\n/******/ ]);\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2Nvc2UtYmFzZS9jb3NlLWJhc2UuanMuanMiLCJtYXBwaW5ncyI6IkFBQUE7QUFDQSxJQUFJLElBQXlEO0FBQzdELDJCQUEyQixtQkFBTyxDQUFDLHFFQUFhO0FBQ2hELE1BQU0sRUFLMkM7QUFDakQsQ0FBQztBQUNELHFDQUFxQztBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQiw4QkFBbUI7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwRUFBMEUsOEJBQW1CO0FBQzdGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSw4QkFBbUI7QUFDN0I7QUFDQTtBQUNBLFVBQVUsOEJBQW1CO0FBQzdCO0FBQ0E7QUFDQSxVQUFVLDhCQUFtQix1QkFBdUI7QUFDcEQ7QUFDQTtBQUNBLFVBQVUsOEJBQW1CO0FBQzdCLGVBQWUsOEJBQW1CO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSw4QkFBbUI7QUFDN0I7QUFDQSxvQ0FBb0MsNEJBQTRCO0FBQ2hFLDBDQUEwQztBQUMxQyxXQUFXLDhCQUFtQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsOEJBQW1CLGtDQUFrQztBQUMvRDtBQUNBO0FBQ0EsVUFBVSw4QkFBbUI7QUFDN0I7QUFDQTtBQUNBLGlCQUFpQiw4QkFBbUIsQ0FBQyw4QkFBbUI7QUFDeEQsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLE9BQU87QUFDUDtBQUNBLGlDQUFpQywrQkFBbUI7O0FBRXBEOzs7QUFHQSx3QkFBd0IsK0JBQW1COztBQUUzQzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxREFBcUQ7O0FBRXJEOztBQUVBLE9B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QSxrQkFBa0IsMkJBQTJCO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxNQUFNO0FBQ047QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxPQUFPO0FBQ1A7QUFDQSxpQ0FBaUMsZ0NBQW1COztBQUVwRDs7O0FBR0E7O0FBRUEsc0JBQXNCLGdDQUFtQjtBQUN6Qyx5QkFBeUIsZ0NBQW1CO0FBQzVDLG9CQUFvQixnQ0FBbUI7QUFDdkMscUJBQXFCLGdDQUFtQjtBQUN4Qyw0QkFBNEIsZ0NBQW1CO0FBQy9DLHNCQUFzQixnQ0FBbUI7QUFDekMsb0JBQW9CLGdDQUFtQjs7QUFFdkM7O0FBRUEsT0FBTztBQUNQO0FBQ0EsQ0FBQyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uLi8uLi8uLi9ub2RlX21vZHVsZXMvY29zZS1iYXNlL2Nvc2UtYmFzZS5qcz9jZGU5Il0sInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiB3ZWJwYWNrVW5pdmVyc2FsTW9kdWxlRGVmaW5pdGlvbihyb290LCBmYWN0b3J5KSB7XG5cdGlmKHR5cGVvZiBleHBvcnRzID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgbW9kdWxlID09PSAnb2JqZWN0Jylcblx0XHRtb2R1bGUuZXhwb3J0cyA9IGZhY3RvcnkocmVxdWlyZShcImxheW91dC1iYXNlXCIpKTtcblx0ZWxzZSBpZih0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQpXG5cdFx0ZGVmaW5lKFtcImxheW91dC1iYXNlXCJdLCBmYWN0b3J5KTtcblx0ZWxzZSBpZih0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcpXG5cdFx0ZXhwb3J0c1tcImNvc2VCYXNlXCJdID0gZmFjdG9yeShyZXF1aXJlKFwibGF5b3V0LWJhc2VcIikpO1xuXHRlbHNlXG5cdFx0cm9vdFtcImNvc2VCYXNlXCJdID0gZmFjdG9yeShyb290W1wibGF5b3V0QmFzZVwiXSk7XG59KSh0aGlzLCBmdW5jdGlvbihfX1dFQlBBQ0tfRVhURVJOQUxfTU9EVUxFXzBfXykge1xucmV0dXJuIC8qKioqKiovIChmdW5jdGlvbihtb2R1bGVzKSB7IC8vIHdlYnBhY2tCb290c3RyYXBcbi8qKioqKiovIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuLyoqKioqKi8gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuLyoqKioqKi9cbi8qKioqKiovIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbi8qKioqKiovIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuLyoqKioqKi9cbi8qKioqKiovIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbi8qKioqKiovIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuLyoqKioqKi8gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG4vKioqKioqLyBcdFx0fVxuLyoqKioqKi8gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4vKioqKioqLyBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuLyoqKioqKi8gXHRcdFx0aTogbW9kdWxlSWQsXG4vKioqKioqLyBcdFx0XHRsOiBmYWxzZSxcbi8qKioqKiovIFx0XHRcdGV4cG9ydHM6IHt9XG4vKioqKioqLyBcdFx0fTtcbi8qKioqKiovXG4vKioqKioqLyBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4vKioqKioqLyBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG4vKioqKioqL1xuLyoqKioqKi8gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbi8qKioqKiovIFx0XHRtb2R1bGUubCA9IHRydWU7XG4vKioqKioqL1xuLyoqKioqKi8gXHRcdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG4vKioqKioqLyBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuLyoqKioqKi8gXHR9XG4vKioqKioqL1xuLyoqKioqKi9cbi8qKioqKiovIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbi8qKioqKiovIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5tID0gbW9kdWxlcztcbi8qKioqKiovXG4vKioqKioqLyBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4vKioqKioqLyBcdF9fd2VicGFja19yZXF1aXJlX18uYyA9IGluc3RhbGxlZE1vZHVsZXM7XG4vKioqKioqL1xuLyoqKioqKi8gXHQvLyBpZGVudGl0eSBmdW5jdGlvbiBmb3IgY2FsbGluZyBoYXJtb255IGltcG9ydHMgd2l0aCB0aGUgY29ycmVjdCBjb250ZXh0XG4vKioqKioqLyBcdF9fd2VicGFja19yZXF1aXJlX18uaSA9IGZ1bmN0aW9uKHZhbHVlKSB7IHJldHVybiB2YWx1ZTsgfTtcbi8qKioqKiovXG4vKioqKioqLyBcdC8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb24gZm9yIGhhcm1vbnkgZXhwb3J0c1xuLyoqKioqKi8gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbi8qKioqKiovIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4vKioqKioqLyBcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgbmFtZSwge1xuLyoqKioqKi8gXHRcdFx0XHRjb25maWd1cmFibGU6IGZhbHNlLFxuLyoqKioqKi8gXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuLyoqKioqKi8gXHRcdFx0XHRnZXQ6IGdldHRlclxuLyoqKioqKi8gXHRcdFx0fSk7XG4vKioqKioqLyBcdFx0fVxuLyoqKioqKi8gXHR9O1xuLyoqKioqKi9cbi8qKioqKiovIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbi8qKioqKiovIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4vKioqKioqLyBcdFx0dmFyIGdldHRlciA9IG1vZHVsZSAmJiBtb2R1bGUuX19lc01vZHVsZSA/XG4vKioqKioqLyBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuLyoqKioqKi8gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbi8qKioqKiovIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQoZ2V0dGVyLCAnYScsIGdldHRlcik7XG4vKioqKioqLyBcdFx0cmV0dXJuIGdldHRlcjtcbi8qKioqKiovIFx0fTtcbi8qKioqKiovXG4vKioqKioqLyBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuLyoqKioqKi8gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG4vKioqKioqL1xuLyoqKioqKi8gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuLyoqKioqKi8gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuLyoqKioqKi9cbi8qKioqKiovIFx0Ly8gTG9hZCBlbnRyeSBtb2R1bGUgYW5kIHJldHVybiBleHBvcnRzXG4vKioqKioqLyBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IDcpO1xuLyoqKioqKi8gfSlcbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG4vKioqKioqLyAoW1xuLyogMCAqL1xuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cykge1xuXG5tb2R1bGUuZXhwb3J0cyA9IF9fV0VCUEFDS19FWFRFUk5BTF9NT0RVTEVfMF9fO1xuXG4vKioqLyB9KSxcbi8qIDEgKi9cbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcblxuXCJ1c2Ugc3RyaWN0XCI7XG5cblxudmFyIEZETGF5b3V0Q29uc3RhbnRzID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5GRExheW91dENvbnN0YW50cztcblxuZnVuY3Rpb24gQ29TRUNvbnN0YW50cygpIHt9XG5cbi8vQ29TRUNvbnN0YW50cyBpbmhlcml0cyBzdGF0aWMgcHJvcHMgaW4gRkRMYXlvdXRDb25zdGFudHNcbmZvciAodmFyIHByb3AgaW4gRkRMYXlvdXRDb25zdGFudHMpIHtcbiAgQ29TRUNvbnN0YW50c1twcm9wXSA9IEZETGF5b3V0Q29uc3RhbnRzW3Byb3BdO1xufVxuXG5Db1NFQ29uc3RhbnRzLkRFRkFVTFRfVVNFX01VTFRJX0xFVkVMX1NDQUxJTkcgPSBmYWxzZTtcbkNvU0VDb25zdGFudHMuREVGQVVMVF9SQURJQUxfU0VQQVJBVElPTiA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEg7XG5Db1NFQ29uc3RhbnRzLkRFRkFVTFRfQ09NUE9ORU5UX1NFUEVSQVRJT04gPSA2MDtcbkNvU0VDb25zdGFudHMuVElMRSA9IHRydWU7XG5Db1NFQ29uc3RhbnRzLlRJTElOR19QQURESU5HX1ZFUlRJQ0FMID0gMTA7XG5Db1NFQ29uc3RhbnRzLlRJTElOR19QQURESU5HX0hPUklaT05UQUwgPSAxMDtcbkNvU0VDb25zdGFudHMuVFJFRV9SRURVQ1RJT05fT05fSU5DUkVNRU5UQUwgPSBmYWxzZTsgLy8gbWFrZSB0aGlzIHRydWUgd2hlbiBjb3NlIGlzIHVzZWQgaW5jcmVtZW50YWxseSBhcyBhIHBhcnQgb2Ygb3RoZXIgbm9uLWluY3JlbWVudGFsIGxheW91dFxuXG5tb2R1bGUuZXhwb3J0cyA9IENvU0VDb25zdGFudHM7XG5cbi8qKiovIH0pLFxuLyogMiAqL1xuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuXG5cInVzZSBzdHJpY3RcIjtcblxuXG52YXIgRkRMYXlvdXRFZGdlID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5GRExheW91dEVkZ2U7XG5cbmZ1bmN0aW9uIENvU0VFZGdlKHNvdXJjZSwgdGFyZ2V0LCB2RWRnZSkge1xuICBGRExheW91dEVkZ2UuY2FsbCh0aGlzLCBzb3VyY2UsIHRhcmdldCwgdkVkZ2UpO1xufVxuXG5Db1NFRWRnZS5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEZETGF5b3V0RWRnZS5wcm90b3R5cGUpO1xuZm9yICh2YXIgcHJvcCBpbiBGRExheW91dEVkZ2UpIHtcbiAgQ29TRUVkZ2VbcHJvcF0gPSBGRExheW91dEVkZ2VbcHJvcF07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gQ29TRUVkZ2U7XG5cbi8qKiovIH0pLFxuLyogMyAqL1xuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuXG5cInVzZSBzdHJpY3RcIjtcblxuXG52YXIgTEdyYXBoID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5MR3JhcGg7XG5cbmZ1bmN0aW9uIENvU0VHcmFwaChwYXJlbnQsIGdyYXBoTWdyLCB2R3JhcGgpIHtcbiAgTEdyYXBoLmNhbGwodGhpcywgcGFyZW50LCBncmFwaE1nciwgdkdyYXBoKTtcbn1cblxuQ29TRUdyYXBoLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoTEdyYXBoLnByb3RvdHlwZSk7XG5mb3IgKHZhciBwcm9wIGluIExHcmFwaCkge1xuICBDb1NFR3JhcGhbcHJvcF0gPSBMR3JhcGhbcHJvcF07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gQ29TRUdyYXBoO1xuXG4vKioqLyB9KSxcbi8qIDQgKi9cbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcblxuXCJ1c2Ugc3RyaWN0XCI7XG5cblxudmFyIExHcmFwaE1hbmFnZXIgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApLkxHcmFwaE1hbmFnZXI7XG5cbmZ1bmN0aW9uIENvU0VHcmFwaE1hbmFnZXIobGF5b3V0KSB7XG4gIExHcmFwaE1hbmFnZXIuY2FsbCh0aGlzLCBsYXlvdXQpO1xufVxuXG5Db1NFR3JhcGhNYW5hZ2VyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoTEdyYXBoTWFuYWdlci5wcm90b3R5cGUpO1xuZm9yICh2YXIgcHJvcCBpbiBMR3JhcGhNYW5hZ2VyKSB7XG4gIENvU0VHcmFwaE1hbmFnZXJbcHJvcF0gPSBMR3JhcGhNYW5hZ2VyW3Byb3BdO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IENvU0VHcmFwaE1hbmFnZXI7XG5cbi8qKiovIH0pLFxuLyogNSAqL1xuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuXG5cInVzZSBzdHJpY3RcIjtcblxuXG52YXIgRkRMYXlvdXROb2RlID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5GRExheW91dE5vZGU7XG52YXIgSU1hdGggPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApLklNYXRoO1xuXG5mdW5jdGlvbiBDb1NFTm9kZShnbSwgbG9jLCBzaXplLCB2Tm9kZSkge1xuICBGRExheW91dE5vZGUuY2FsbCh0aGlzLCBnbSwgbG9jLCBzaXplLCB2Tm9kZSk7XG59XG5cbkNvU0VOb2RlLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoRkRMYXlvdXROb2RlLnByb3RvdHlwZSk7XG5mb3IgKHZhciBwcm9wIGluIEZETGF5b3V0Tm9kZSkge1xuICBDb1NFTm9kZVtwcm9wXSA9IEZETGF5b3V0Tm9kZVtwcm9wXTtcbn1cblxuQ29TRU5vZGUucHJvdG90eXBlLm1vdmUgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBsYXlvdXQgPSB0aGlzLmdyYXBoTWFuYWdlci5nZXRMYXlvdXQoKTtcbiAgdGhpcy5kaXNwbGFjZW1lbnRYID0gbGF5b3V0LmNvb2xpbmdGYWN0b3IgKiAodGhpcy5zcHJpbmdGb3JjZVggKyB0aGlzLnJlcHVsc2lvbkZvcmNlWCArIHRoaXMuZ3Jhdml0YXRpb25Gb3JjZVgpIC8gdGhpcy5ub09mQ2hpbGRyZW47XG4gIHRoaXMuZGlzcGxhY2VtZW50WSA9IGxheW91dC5jb29saW5nRmFjdG9yICogKHRoaXMuc3ByaW5nRm9yY2VZICsgdGhpcy5yZXB1bHNpb25Gb3JjZVkgKyB0aGlzLmdyYXZpdGF0aW9uRm9yY2VZKSAvIHRoaXMubm9PZkNoaWxkcmVuO1xuXG4gIGlmIChNYXRoLmFicyh0aGlzLmRpc3BsYWNlbWVudFgpID4gbGF5b3V0LmNvb2xpbmdGYWN0b3IgKiBsYXlvdXQubWF4Tm9kZURpc3BsYWNlbWVudCkge1xuICAgIHRoaXMuZGlzcGxhY2VtZW50WCA9IGxheW91dC5jb29saW5nRmFjdG9yICogbGF5b3V0Lm1heE5vZGVEaXNwbGFjZW1lbnQgKiBJTWF0aC5zaWduKHRoaXMuZGlzcGxhY2VtZW50WCk7XG4gIH1cblxuICBpZiAoTWF0aC5hYnModGhpcy5kaXNwbGFjZW1lbnRZKSA+IGxheW91dC5jb29saW5nRmFjdG9yICogbGF5b3V0Lm1heE5vZGVEaXNwbGFjZW1lbnQpIHtcbiAgICB0aGlzLmRpc3BsYWNlbWVudFkgPSBsYXlvdXQuY29vbGluZ0ZhY3RvciAqIGxheW91dC5tYXhOb2RlRGlzcGxhY2VtZW50ICogSU1hdGguc2lnbih0aGlzLmRpc3BsYWNlbWVudFkpO1xuICB9XG5cbiAgLy8gYSBzaW1wbGUgbm9kZSwganVzdCBtb3ZlIGl0XG4gIGlmICh0aGlzLmNoaWxkID09IG51bGwpIHtcbiAgICB0aGlzLm1vdmVCeSh0aGlzLmRpc3BsYWNlbWVudFgsIHRoaXMuZGlzcGxhY2VtZW50WSk7XG4gIH1cbiAgLy8gYW4gZW1wdHkgY29tcG91bmQgbm9kZSwgYWdhaW4ganVzdCBtb3ZlIGl0XG4gIGVsc2UgaWYgKHRoaXMuY2hpbGQuZ2V0Tm9kZXMoKS5sZW5ndGggPT0gMCkge1xuICAgICAgdGhpcy5tb3ZlQnkodGhpcy5kaXNwbGFjZW1lbnRYLCB0aGlzLmRpc3BsYWNlbWVudFkpO1xuICAgIH1cbiAgICAvLyBub24tZW1wdHkgY29tcG91bmQgbm9kZSwgcHJvcG9nYXRlIG1vdmVtZW50IHRvIGNoaWxkcmVuIGFzIHdlbGxcbiAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5wcm9wb2dhdGVEaXNwbGFjZW1lbnRUb0NoaWxkcmVuKHRoaXMuZGlzcGxhY2VtZW50WCwgdGhpcy5kaXNwbGFjZW1lbnRZKTtcbiAgICAgIH1cblxuICBsYXlvdXQudG90YWxEaXNwbGFjZW1lbnQgKz0gTWF0aC5hYnModGhpcy5kaXNwbGFjZW1lbnRYKSArIE1hdGguYWJzKHRoaXMuZGlzcGxhY2VtZW50WSk7XG5cbiAgdGhpcy5zcHJpbmdGb3JjZVggPSAwO1xuICB0aGlzLnNwcmluZ0ZvcmNlWSA9IDA7XG4gIHRoaXMucmVwdWxzaW9uRm9yY2VYID0gMDtcbiAgdGhpcy5yZXB1bHNpb25Gb3JjZVkgPSAwO1xuICB0aGlzLmdyYXZpdGF0aW9uRm9yY2VYID0gMDtcbiAgdGhpcy5ncmF2aXRhdGlvbkZvcmNlWSA9IDA7XG4gIHRoaXMuZGlzcGxhY2VtZW50WCA9IDA7XG4gIHRoaXMuZGlzcGxhY2VtZW50WSA9IDA7XG59O1xuXG5Db1NFTm9kZS5wcm90b3R5cGUucHJvcG9nYXRlRGlzcGxhY2VtZW50VG9DaGlsZHJlbiA9IGZ1bmN0aW9uIChkWCwgZFkpIHtcbiAgdmFyIG5vZGVzID0gdGhpcy5nZXRDaGlsZCgpLmdldE5vZGVzKCk7XG4gIHZhciBub2RlO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgbm9kZSA9IG5vZGVzW2ldO1xuICAgIGlmIChub2RlLmdldENoaWxkKCkgPT0gbnVsbCkge1xuICAgICAgbm9kZS5tb3ZlQnkoZFgsIGRZKTtcbiAgICAgIG5vZGUuZGlzcGxhY2VtZW50WCArPSBkWDtcbiAgICAgIG5vZGUuZGlzcGxhY2VtZW50WSArPSBkWTtcbiAgICB9IGVsc2Uge1xuICAgICAgbm9kZS5wcm9wb2dhdGVEaXNwbGFjZW1lbnRUb0NoaWxkcmVuKGRYLCBkWSk7XG4gICAgfVxuICB9XG59O1xuXG5Db1NFTm9kZS5wcm90b3R5cGUuc2V0UHJlZDEgPSBmdW5jdGlvbiAocHJlZDEpIHtcbiAgdGhpcy5wcmVkMSA9IHByZWQxO1xufTtcblxuQ29TRU5vZGUucHJvdG90eXBlLmdldFByZWQxID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gcHJlZDE7XG59O1xuXG5Db1NFTm9kZS5wcm90b3R5cGUuZ2V0UHJlZDIgPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiBwcmVkMjtcbn07XG5cbkNvU0VOb2RlLnByb3RvdHlwZS5zZXROZXh0ID0gZnVuY3Rpb24gKG5leHQpIHtcbiAgdGhpcy5uZXh0ID0gbmV4dDtcbn07XG5cbkNvU0VOb2RlLnByb3RvdHlwZS5nZXROZXh0ID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gbmV4dDtcbn07XG5cbkNvU0VOb2RlLnByb3RvdHlwZS5zZXRQcm9jZXNzZWQgPSBmdW5jdGlvbiAocHJvY2Vzc2VkKSB7XG4gIHRoaXMucHJvY2Vzc2VkID0gcHJvY2Vzc2VkO1xufTtcblxuQ29TRU5vZGUucHJvdG90eXBlLmlzUHJvY2Vzc2VkID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gcHJvY2Vzc2VkO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDb1NFTm9kZTtcblxuLyoqKi8gfSksXG4vKiA2ICovXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG5cblwidXNlIHN0cmljdFwiO1xuXG5cbnZhciBGRExheW91dCA9IF9fd2VicGFja19yZXF1aXJlX18oMCkuRkRMYXlvdXQ7XG52YXIgQ29TRUdyYXBoTWFuYWdlciA9IF9fd2VicGFja19yZXF1aXJlX18oNCk7XG52YXIgQ29TRUdyYXBoID0gX193ZWJwYWNrX3JlcXVpcmVfXygzKTtcbnZhciBDb1NFTm9kZSA9IF9fd2VicGFja19yZXF1aXJlX18oNSk7XG52YXIgQ29TRUVkZ2UgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDIpO1xudmFyIENvU0VDb25zdGFudHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDEpO1xudmFyIEZETGF5b3V0Q29uc3RhbnRzID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5GRExheW91dENvbnN0YW50cztcbnZhciBMYXlvdXRDb25zdGFudHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApLkxheW91dENvbnN0YW50cztcbnZhciBQb2ludCA9IF9fd2VicGFja19yZXF1aXJlX18oMCkuUG9pbnQ7XG52YXIgUG9pbnREID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5Qb2ludEQ7XG52YXIgTGF5b3V0ID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5MYXlvdXQ7XG52YXIgSW50ZWdlciA9IF9fd2VicGFja19yZXF1aXJlX18oMCkuSW50ZWdlcjtcbnZhciBJR2VvbWV0cnkgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApLklHZW9tZXRyeTtcbnZhciBMR3JhcGggPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApLkxHcmFwaDtcbnZhciBUcmFuc2Zvcm0gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApLlRyYW5zZm9ybTtcblxuZnVuY3Rpb24gQ29TRUxheW91dCgpIHtcbiAgRkRMYXlvdXQuY2FsbCh0aGlzKTtcblxuICB0aGlzLnRvQmVUaWxlZCA9IHt9OyAvLyBNZW1vcml6ZSBpZiBhIG5vZGUgaXMgdG8gYmUgdGlsZWQgb3IgaXMgdGlsZWRcbn1cblxuQ29TRUxheW91dC5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEZETGF5b3V0LnByb3RvdHlwZSk7XG5cbmZvciAodmFyIHByb3AgaW4gRkRMYXlvdXQpIHtcbiAgQ29TRUxheW91dFtwcm9wXSA9IEZETGF5b3V0W3Byb3BdO1xufVxuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5uZXdHcmFwaE1hbmFnZXIgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBnbSA9IG5ldyBDb1NFR3JhcGhNYW5hZ2VyKHRoaXMpO1xuICB0aGlzLmdyYXBoTWFuYWdlciA9IGdtO1xuICByZXR1cm4gZ207XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5uZXdHcmFwaCA9IGZ1bmN0aW9uICh2R3JhcGgpIHtcbiAgcmV0dXJuIG5ldyBDb1NFR3JhcGgobnVsbCwgdGhpcy5ncmFwaE1hbmFnZXIsIHZHcmFwaCk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5uZXdOb2RlID0gZnVuY3Rpb24gKHZOb2RlKSB7XG4gIHJldHVybiBuZXcgQ29TRU5vZGUodGhpcy5ncmFwaE1hbmFnZXIsIHZOb2RlKTtcbn07XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlLm5ld0VkZ2UgPSBmdW5jdGlvbiAodkVkZ2UpIHtcbiAgcmV0dXJuIG5ldyBDb1NFRWRnZShudWxsLCBudWxsLCB2RWRnZSk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5pbml0UGFyYW1ldGVycyA9IGZ1bmN0aW9uICgpIHtcbiAgRkRMYXlvdXQucHJvdG90eXBlLmluaXRQYXJhbWV0ZXJzLmNhbGwodGhpcywgYXJndW1lbnRzKTtcbiAgaWYgKCF0aGlzLmlzU3ViTGF5b3V0KSB7XG4gICAgaWYgKENvU0VDb25zdGFudHMuREVGQVVMVF9FREdFX0xFTkdUSCA8IDEwKSB7XG4gICAgICB0aGlzLmlkZWFsRWRnZUxlbmd0aCA9IDEwO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmlkZWFsRWRnZUxlbmd0aCA9IENvU0VDb25zdGFudHMuREVGQVVMVF9FREdFX0xFTkdUSDtcbiAgICB9XG5cbiAgICB0aGlzLnVzZVNtYXJ0SWRlYWxFZGdlTGVuZ3RoQ2FsY3VsYXRpb24gPSBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfVVNFX1NNQVJUX0lERUFMX0VER0VfTEVOR1RIX0NBTENVTEFUSU9OO1xuICAgIHRoaXMuc3ByaW5nQ29uc3RhbnQgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX1NQUklOR19TVFJFTkdUSDtcbiAgICB0aGlzLnJlcHVsc2lvbkNvbnN0YW50ID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9SRVBVTFNJT05fU1RSRU5HVEg7XG4gICAgdGhpcy5ncmF2aXR5Q29uc3RhbnQgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0dSQVZJVFlfU1RSRU5HVEg7XG4gICAgdGhpcy5jb21wb3VuZEdyYXZpdHlDb25zdGFudCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09NUE9VTkRfR1JBVklUWV9TVFJFTkdUSDtcbiAgICB0aGlzLmdyYXZpdHlSYW5nZUZhY3RvciA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfR1JBVklUWV9SQU5HRV9GQUNUT1I7XG4gICAgdGhpcy5jb21wb3VuZEdyYXZpdHlSYW5nZUZhY3RvciA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09NUE9VTkRfR1JBVklUWV9SQU5HRV9GQUNUT1I7XG5cbiAgICAvLyB2YXJpYWJsZXMgZm9yIHRyZWUgcmVkdWN0aW9uIHN1cHBvcnRcbiAgICB0aGlzLnBydW5lZE5vZGVzQWxsID0gW107XG4gICAgdGhpcy5ncm93VHJlZUl0ZXJhdGlvbnMgPSAwO1xuICAgIHRoaXMuYWZ0ZXJHcm93dGhJdGVyYXRpb25zID0gMDtcbiAgICB0aGlzLmlzVHJlZUdyb3dpbmcgPSBmYWxzZTtcbiAgICB0aGlzLmlzR3Jvd3RoRmluaXNoZWQgPSBmYWxzZTtcblxuICAgIC8vIHZhcmlhYmxlcyBmb3IgY29vbGluZ1xuICAgIHRoaXMuY29vbGluZ0N5Y2xlID0gMDtcbiAgICB0aGlzLm1heENvb2xpbmdDeWNsZSA9IHRoaXMubWF4SXRlcmF0aW9ucyAvIEZETGF5b3V0Q29uc3RhbnRzLkNPTlZFUkdFTkNFX0NIRUNLX1BFUklPRDtcbiAgICB0aGlzLmZpbmFsVGVtcGVyYXR1cmUgPSBGRExheW91dENvbnN0YW50cy5DT05WRVJHRU5DRV9DSEVDS19QRVJJT0QgLyB0aGlzLm1heEl0ZXJhdGlvbnM7XG4gICAgdGhpcy5jb29saW5nQWRqdXN0ZXIgPSAxO1xuICB9XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5sYXlvdXQgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBjcmVhdGVCZW5kc0FzTmVlZGVkID0gTGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ1JFQVRFX0JFTkRTX0FTX05FRURFRDtcbiAgaWYgKGNyZWF0ZUJlbmRzQXNOZWVkZWQpIHtcbiAgICB0aGlzLmNyZWF0ZUJlbmRwb2ludHMoKTtcbiAgICB0aGlzLmdyYXBoTWFuYWdlci5yZXNldEFsbEVkZ2VzKCk7XG4gIH1cblxuICB0aGlzLmxldmVsID0gMDtcbiAgcmV0dXJuIHRoaXMuY2xhc3NpY0xheW91dCgpO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuY2xhc3NpY0xheW91dCA9IGZ1bmN0aW9uICgpIHtcbiAgdGhpcy5ub2Rlc1dpdGhHcmF2aXR5ID0gdGhpcy5jYWxjdWxhdGVOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvblRvKCk7XG4gIHRoaXMuZ3JhcGhNYW5hZ2VyLnNldEFsbE5vZGVzVG9BcHBseUdyYXZpdGF0aW9uKHRoaXMubm9kZXNXaXRoR3Jhdml0eSk7XG4gIHRoaXMuY2FsY05vT2ZDaGlsZHJlbkZvckFsbE5vZGVzKCk7XG4gIHRoaXMuZ3JhcGhNYW5hZ2VyLmNhbGNMb3dlc3RDb21tb25BbmNlc3RvcnMoKTtcbiAgdGhpcy5ncmFwaE1hbmFnZXIuY2FsY0luY2x1c2lvblRyZWVEZXB0aHMoKTtcbiAgdGhpcy5ncmFwaE1hbmFnZXIuZ2V0Um9vdCgpLmNhbGNFc3RpbWF0ZWRTaXplKCk7XG4gIHRoaXMuY2FsY0lkZWFsRWRnZUxlbmd0aHMoKTtcblxuICBpZiAoIXRoaXMuaW5jcmVtZW50YWwpIHtcbiAgICB2YXIgZm9yZXN0ID0gdGhpcy5nZXRGbGF0Rm9yZXN0KCk7XG5cbiAgICAvLyBUaGUgZ3JhcGggYXNzb2NpYXRlZCB3aXRoIHRoaXMgbGF5b3V0IGlzIGZsYXQgYW5kIGEgZm9yZXN0XG4gICAgaWYgKGZvcmVzdC5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnBvc2l0aW9uTm9kZXNSYWRpYWxseShmb3Jlc3QpO1xuICAgIH1cbiAgICAvLyBUaGUgZ3JhcGggYXNzb2NpYXRlZCB3aXRoIHRoaXMgbGF5b3V0IGlzIG5vdCBmbGF0IG9yIGEgZm9yZXN0XG4gICAgZWxzZSB7XG4gICAgICAgIC8vIFJlZHVjZSB0aGUgdHJlZXMgd2hlbiBpbmNyZW1lbnRhbCBtb2RlIGlzIG5vdCBlbmFibGVkIGFuZCBncmFwaCBpcyBub3QgYSBmb3Jlc3QgXG4gICAgICAgIHRoaXMucmVkdWNlVHJlZXMoKTtcbiAgICAgICAgLy8gVXBkYXRlIG5vZGVzIHRoYXQgZ3Jhdml0eSB3aWxsIGJlIGFwcGxpZWRcbiAgICAgICAgdGhpcy5ncmFwaE1hbmFnZXIucmVzZXRBbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbigpO1xuICAgICAgICB2YXIgYWxsTm9kZXMgPSBuZXcgU2V0KHRoaXMuZ2V0QWxsTm9kZXMoKSk7XG4gICAgICAgIHZhciBpbnRlcnNlY3Rpb24gPSB0aGlzLm5vZGVzV2l0aEdyYXZpdHkuZmlsdGVyKGZ1bmN0aW9uICh4KSB7XG4gICAgICAgICAgcmV0dXJuIGFsbE5vZGVzLmhhcyh4KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZ3JhcGhNYW5hZ2VyLnNldEFsbE5vZGVzVG9BcHBseUdyYXZpdGF0aW9uKGludGVyc2VjdGlvbik7XG5cbiAgICAgICAgdGhpcy5wb3NpdGlvbk5vZGVzUmFuZG9tbHkoKTtcbiAgICAgIH1cbiAgfSBlbHNlIHtcbiAgICBpZiAoQ29TRUNvbnN0YW50cy5UUkVFX1JFRFVDVElPTl9PTl9JTkNSRU1FTlRBTCkge1xuICAgICAgLy8gUmVkdWNlIHRoZSB0cmVlcyBpbiBpbmNyZW1lbnRhbCBtb2RlIGlmIG9ubHkgdGhpcyBjb25zdGFudCBpcyBzZXQgdG8gdHJ1ZSBcbiAgICAgIHRoaXMucmVkdWNlVHJlZXMoKTtcbiAgICAgIC8vIFVwZGF0ZSBub2RlcyB0aGF0IGdyYXZpdHkgd2lsbCBiZSBhcHBsaWVkXG4gICAgICB0aGlzLmdyYXBoTWFuYWdlci5yZXNldEFsbE5vZGVzVG9BcHBseUdyYXZpdGF0aW9uKCk7XG4gICAgICB2YXIgYWxsTm9kZXMgPSBuZXcgU2V0KHRoaXMuZ2V0QWxsTm9kZXMoKSk7XG4gICAgICB2YXIgaW50ZXJzZWN0aW9uID0gdGhpcy5ub2Rlc1dpdGhHcmF2aXR5LmZpbHRlcihmdW5jdGlvbiAoeCkge1xuICAgICAgICByZXR1cm4gYWxsTm9kZXMuaGFzKHgpO1xuICAgICAgfSk7XG4gICAgICB0aGlzLmdyYXBoTWFuYWdlci5zZXRBbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbihpbnRlcnNlY3Rpb24pO1xuICAgIH1cbiAgfVxuXG4gIHRoaXMuaW5pdFNwcmluZ0VtYmVkZGVyKCk7XG4gIHRoaXMucnVuU3ByaW5nRW1iZWRkZXIoKTtcblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlLnRpY2sgPSBmdW5jdGlvbiAoKSB7XG4gIHRoaXMudG90YWxJdGVyYXRpb25zKys7XG5cbiAgaWYgKHRoaXMudG90YWxJdGVyYXRpb25zID09PSB0aGlzLm1heEl0ZXJhdGlvbnMgJiYgIXRoaXMuaXNUcmVlR3Jvd2luZyAmJiAhdGhpcy5pc0dyb3d0aEZpbmlzaGVkKSB7XG4gICAgaWYgKHRoaXMucHJ1bmVkTm9kZXNBbGwubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5pc1RyZWVHcm93aW5nID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9XG5cbiAgaWYgKHRoaXMudG90YWxJdGVyYXRpb25zICUgRkRMYXlvdXRDb25zdGFudHMuQ09OVkVSR0VOQ0VfQ0hFQ0tfUEVSSU9EID09IDAgJiYgIXRoaXMuaXNUcmVlR3Jvd2luZyAmJiAhdGhpcy5pc0dyb3d0aEZpbmlzaGVkKSB7XG4gICAgaWYgKHRoaXMuaXNDb252ZXJnZWQoKSkge1xuICAgICAgaWYgKHRoaXMucHJ1bmVkTm9kZXNBbGwubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLmlzVHJlZUdyb3dpbmcgPSB0cnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5jb29saW5nQ3ljbGUrKztcblxuICAgIGlmICh0aGlzLmxheW91dFF1YWxpdHkgPT0gMCkge1xuICAgICAgLy8gcXVhbGl0eSAtIFwiZHJhZnRcIlxuICAgICAgdGhpcy5jb29saW5nQWRqdXN0ZXIgPSB0aGlzLmNvb2xpbmdDeWNsZTtcbiAgICB9IGVsc2UgaWYgKHRoaXMubGF5b3V0UXVhbGl0eSA9PSAxKSB7XG4gICAgICAvLyBxdWFsaXR5IC0gXCJkZWZhdWx0XCJcbiAgICAgIHRoaXMuY29vbGluZ0FkanVzdGVyID0gdGhpcy5jb29saW5nQ3ljbGUgLyAzO1xuICAgIH1cblxuICAgIC8vIGNvb2xpbmcgc2NoZWR1bGUgaXMgYmFzZWQgb24gaHR0cDovL3d3dy5idGx1a2UuY29tL3NpbWFuZjEuaHRtbCAtPiBjb29saW5nIHNjaGVkdWxlIDNcbiAgICB0aGlzLmNvb2xpbmdGYWN0b3IgPSBNYXRoLm1heCh0aGlzLmluaXRpYWxDb29saW5nRmFjdG9yIC0gTWF0aC5wb3codGhpcy5jb29saW5nQ3ljbGUsIE1hdGgubG9nKDEwMCAqICh0aGlzLmluaXRpYWxDb29saW5nRmFjdG9yIC0gdGhpcy5maW5hbFRlbXBlcmF0dXJlKSkgLyBNYXRoLmxvZyh0aGlzLm1heENvb2xpbmdDeWNsZSkpIC8gMTAwICogdGhpcy5jb29saW5nQWRqdXN0ZXIsIHRoaXMuZmluYWxUZW1wZXJhdHVyZSk7XG4gICAgdGhpcy5hbmltYXRpb25QZXJpb2QgPSBNYXRoLmNlaWwodGhpcy5pbml0aWFsQW5pbWF0aW9uUGVyaW9kICogTWF0aC5zcXJ0KHRoaXMuY29vbGluZ0ZhY3RvcikpO1xuICB9XG4gIC8vIE9wZXJhdGlvbnMgd2hpbGUgdHJlZSBpcyBncm93aW5nIGFnYWluIFxuICBpZiAodGhpcy5pc1RyZWVHcm93aW5nKSB7XG4gICAgaWYgKHRoaXMuZ3Jvd1RyZWVJdGVyYXRpb25zICUgMTAgPT0gMCkge1xuICAgICAgaWYgKHRoaXMucHJ1bmVkTm9kZXNBbGwubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLmdyYXBoTWFuYWdlci51cGRhdGVCb3VuZHMoKTtcbiAgICAgICAgdGhpcy51cGRhdGVHcmlkKCk7XG4gICAgICAgIHRoaXMuZ3Jvd1RyZWUodGhpcy5wcnVuZWROb2Rlc0FsbCk7XG4gICAgICAgIC8vIFVwZGF0ZSBub2RlcyB0aGF0IGdyYXZpdHkgd2lsbCBiZSBhcHBsaWVkXG4gICAgICAgIHRoaXMuZ3JhcGhNYW5hZ2VyLnJlc2V0QWxsTm9kZXNUb0FwcGx5R3Jhdml0YXRpb24oKTtcbiAgICAgICAgdmFyIGFsbE5vZGVzID0gbmV3IFNldCh0aGlzLmdldEFsbE5vZGVzKCkpO1xuICAgICAgICB2YXIgaW50ZXJzZWN0aW9uID0gdGhpcy5ub2Rlc1dpdGhHcmF2aXR5LmZpbHRlcihmdW5jdGlvbiAoeCkge1xuICAgICAgICAgIHJldHVybiBhbGxOb2Rlcy5oYXMoeCk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmdyYXBoTWFuYWdlci5zZXRBbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbihpbnRlcnNlY3Rpb24pO1xuXG4gICAgICAgIHRoaXMuZ3JhcGhNYW5hZ2VyLnVwZGF0ZUJvdW5kcygpO1xuICAgICAgICB0aGlzLnVwZGF0ZUdyaWQoKTtcbiAgICAgICAgdGhpcy5jb29saW5nRmFjdG9yID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9DT09MSU5HX0ZBQ1RPUl9JTkNSRU1FTlRBTDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuaXNUcmVlR3Jvd2luZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmlzR3Jvd3RoRmluaXNoZWQgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmdyb3dUcmVlSXRlcmF0aW9ucysrO1xuICB9XG4gIC8vIE9wZXJhdGlvbnMgYWZ0ZXIgZ3Jvd3RoIGlzIGZpbmlzaGVkXG4gIGlmICh0aGlzLmlzR3Jvd3RoRmluaXNoZWQpIHtcbiAgICBpZiAodGhpcy5pc0NvbnZlcmdlZCgpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKHRoaXMuYWZ0ZXJHcm93dGhJdGVyYXRpb25zICUgMTAgPT0gMCkge1xuICAgICAgdGhpcy5ncmFwaE1hbmFnZXIudXBkYXRlQm91bmRzKCk7XG4gICAgICB0aGlzLnVwZGF0ZUdyaWQoKTtcbiAgICB9XG4gICAgdGhpcy5jb29saW5nRmFjdG9yID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9DT09MSU5HX0ZBQ1RPUl9JTkNSRU1FTlRBTCAqICgoMTAwIC0gdGhpcy5hZnRlckdyb3d0aEl0ZXJhdGlvbnMpIC8gMTAwKTtcbiAgICB0aGlzLmFmdGVyR3Jvd3RoSXRlcmF0aW9ucysrO1xuICB9XG5cbiAgdmFyIGdyaWRVcGRhdGVBbGxvd2VkID0gIXRoaXMuaXNUcmVlR3Jvd2luZyAmJiAhdGhpcy5pc0dyb3d0aEZpbmlzaGVkO1xuICB2YXIgZm9yY2VUb05vZGVTdXJyb3VuZGluZ1VwZGF0ZSA9IHRoaXMuZ3Jvd1RyZWVJdGVyYXRpb25zICUgMTAgPT0gMSAmJiB0aGlzLmlzVHJlZUdyb3dpbmcgfHwgdGhpcy5hZnRlckdyb3d0aEl0ZXJhdGlvbnMgJSAxMCA9PSAxICYmIHRoaXMuaXNHcm93dGhGaW5pc2hlZDtcblxuICB0aGlzLnRvdGFsRGlzcGxhY2VtZW50ID0gMDtcbiAgdGhpcy5ncmFwaE1hbmFnZXIudXBkYXRlQm91bmRzKCk7XG4gIHRoaXMuY2FsY1NwcmluZ0ZvcmNlcygpO1xuICB0aGlzLmNhbGNSZXB1bHNpb25Gb3JjZXMoZ3JpZFVwZGF0ZUFsbG93ZWQsIGZvcmNlVG9Ob2RlU3Vycm91bmRpbmdVcGRhdGUpO1xuICB0aGlzLmNhbGNHcmF2aXRhdGlvbmFsRm9yY2VzKCk7XG4gIHRoaXMubW92ZU5vZGVzKCk7XG4gIHRoaXMuYW5pbWF0ZSgpO1xuXG4gIHJldHVybiBmYWxzZTsgLy8gTGF5b3V0IGlzIG5vdCBlbmRlZCB5ZXQgcmV0dXJuIGZhbHNlXG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5nZXRQb3NpdGlvbnNEYXRhID0gZnVuY3Rpb24gKCkge1xuICB2YXIgYWxsTm9kZXMgPSB0aGlzLmdyYXBoTWFuYWdlci5nZXRBbGxOb2RlcygpO1xuICB2YXIgcERhdGEgPSB7fTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBhbGxOb2Rlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciByZWN0ID0gYWxsTm9kZXNbaV0ucmVjdDtcbiAgICB2YXIgaWQgPSBhbGxOb2Rlc1tpXS5pZDtcbiAgICBwRGF0YVtpZF0gPSB7XG4gICAgICBpZDogaWQsXG4gICAgICB4OiByZWN0LmdldENlbnRlclgoKSxcbiAgICAgIHk6IHJlY3QuZ2V0Q2VudGVyWSgpLFxuICAgICAgdzogcmVjdC53aWR0aCxcbiAgICAgIGg6IHJlY3QuaGVpZ2h0XG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiBwRGF0YTtcbn07XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlLnJ1blNwcmluZ0VtYmVkZGVyID0gZnVuY3Rpb24gKCkge1xuICB0aGlzLmluaXRpYWxBbmltYXRpb25QZXJpb2QgPSAyNTtcbiAgdGhpcy5hbmltYXRpb25QZXJpb2QgPSB0aGlzLmluaXRpYWxBbmltYXRpb25QZXJpb2Q7XG4gIHZhciBsYXlvdXRFbmRlZCA9IGZhbHNlO1xuXG4gIC8vIElmIGFtaW5hdGUgb3B0aW9uIGlzICdkdXJpbmcnIHNpZ25hbCB0aGF0IGxheW91dCBpcyBzdXBwb3NlZCB0byBzdGFydCBpdGVyYXRpbmdcbiAgaWYgKEZETGF5b3V0Q29uc3RhbnRzLkFOSU1BVEUgPT09ICdkdXJpbmcnKSB7XG4gICAgdGhpcy5lbWl0KCdsYXlvdXRzdGFydGVkJyk7XG4gIH0gZWxzZSB7XG4gICAgLy8gSWYgYW1pbmF0ZSBvcHRpb24gaXMgJ2R1cmluZycgdGljaygpIGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkIG9uIGluZGV4LmpzXG4gICAgd2hpbGUgKCFsYXlvdXRFbmRlZCkge1xuICAgICAgbGF5b3V0RW5kZWQgPSB0aGlzLnRpY2soKTtcbiAgICB9XG5cbiAgICB0aGlzLmdyYXBoTWFuYWdlci51cGRhdGVCb3VuZHMoKTtcbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuY2FsY3VsYXRlTm9kZXNUb0FwcGx5R3Jhdml0YXRpb25UbyA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIG5vZGVMaXN0ID0gW107XG4gIHZhciBncmFwaDtcblxuICB2YXIgZ3JhcGhzID0gdGhpcy5ncmFwaE1hbmFnZXIuZ2V0R3JhcGhzKCk7XG4gIHZhciBzaXplID0gZ3JhcGhzLmxlbmd0aDtcbiAgdmFyIGk7XG4gIGZvciAoaSA9IDA7IGkgPCBzaXplOyBpKyspIHtcbiAgICBncmFwaCA9IGdyYXBoc1tpXTtcblxuICAgIGdyYXBoLnVwZGF0ZUNvbm5lY3RlZCgpO1xuXG4gICAgaWYgKCFncmFwaC5pc0Nvbm5lY3RlZCkge1xuICAgICAgbm9kZUxpc3QgPSBub2RlTGlzdC5jb25jYXQoZ3JhcGguZ2V0Tm9kZXMoKSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG5vZGVMaXN0O1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuY3JlYXRlQmVuZHBvaW50cyA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIGVkZ2VzID0gW107XG4gIGVkZ2VzID0gZWRnZXMuY29uY2F0KHRoaXMuZ3JhcGhNYW5hZ2VyLmdldEFsbEVkZ2VzKCkpO1xuICB2YXIgdmlzaXRlZCA9IG5ldyBTZXQoKTtcbiAgdmFyIGk7XG4gIGZvciAoaSA9IDA7IGkgPCBlZGdlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBlZGdlID0gZWRnZXNbaV07XG5cbiAgICBpZiAoIXZpc2l0ZWQuaGFzKGVkZ2UpKSB7XG4gICAgICB2YXIgc291cmNlID0gZWRnZS5nZXRTb3VyY2UoKTtcbiAgICAgIHZhciB0YXJnZXQgPSBlZGdlLmdldFRhcmdldCgpO1xuXG4gICAgICBpZiAoc291cmNlID09IHRhcmdldCkge1xuICAgICAgICBlZGdlLmdldEJlbmRwb2ludHMoKS5wdXNoKG5ldyBQb2ludEQoKSk7XG4gICAgICAgIGVkZ2UuZ2V0QmVuZHBvaW50cygpLnB1c2gobmV3IFBvaW50RCgpKTtcbiAgICAgICAgdGhpcy5jcmVhdGVEdW1teU5vZGVzRm9yQmVuZHBvaW50cyhlZGdlKTtcbiAgICAgICAgdmlzaXRlZC5hZGQoZWRnZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgZWRnZUxpc3QgPSBbXTtcblxuICAgICAgICBlZGdlTGlzdCA9IGVkZ2VMaXN0LmNvbmNhdChzb3VyY2UuZ2V0RWRnZUxpc3RUb05vZGUodGFyZ2V0KSk7XG4gICAgICAgIGVkZ2VMaXN0ID0gZWRnZUxpc3QuY29uY2F0KHRhcmdldC5nZXRFZGdlTGlzdFRvTm9kZShzb3VyY2UpKTtcblxuICAgICAgICBpZiAoIXZpc2l0ZWQuaGFzKGVkZ2VMaXN0WzBdKSkge1xuICAgICAgICAgIGlmIChlZGdlTGlzdC5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICB2YXIgaztcbiAgICAgICAgICAgIGZvciAoayA9IDA7IGsgPCBlZGdlTGlzdC5sZW5ndGg7IGsrKykge1xuICAgICAgICAgICAgICB2YXIgbXVsdGlFZGdlID0gZWRnZUxpc3Rba107XG4gICAgICAgICAgICAgIG11bHRpRWRnZS5nZXRCZW5kcG9pbnRzKCkucHVzaChuZXcgUG9pbnREKCkpO1xuICAgICAgICAgICAgICB0aGlzLmNyZWF0ZUR1bW15Tm9kZXNGb3JCZW5kcG9pbnRzKG11bHRpRWRnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGVkZ2VMaXN0LmZvckVhY2goZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICAgICAgICAgIHZpc2l0ZWQuYWRkKGVkZ2UpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHZpc2l0ZWQuc2l6ZSA9PSBlZGdlcy5sZW5ndGgpIHtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUucG9zaXRpb25Ob2Rlc1JhZGlhbGx5ID0gZnVuY3Rpb24gKGZvcmVzdCkge1xuICAvLyBXZSB0aWxlIHRoZSB0cmVlcyB0byBhIGdyaWQgcm93IGJ5IHJvdzsgZmlyc3QgdHJlZSBzdGFydHMgYXQgKDAsMClcbiAgdmFyIGN1cnJlbnRTdGFydGluZ1BvaW50ID0gbmV3IFBvaW50KDAsIDApO1xuICB2YXIgbnVtYmVyT2ZDb2x1bW5zID0gTWF0aC5jZWlsKE1hdGguc3FydChmb3Jlc3QubGVuZ3RoKSk7XG4gIHZhciBoZWlnaHQgPSAwO1xuICB2YXIgY3VycmVudFkgPSAwO1xuICB2YXIgY3VycmVudFggPSAwO1xuICB2YXIgcG9pbnQgPSBuZXcgUG9pbnREKDAsIDApO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgZm9yZXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKGkgJSBudW1iZXJPZkNvbHVtbnMgPT0gMCkge1xuICAgICAgLy8gU3RhcnQgb2YgYSBuZXcgcm93LCBtYWtlIHRoZSB4IGNvb3JkaW5hdGUgMCwgaW5jcmVtZW50IHRoZVxuICAgICAgLy8geSBjb29yZGluYXRlIHdpdGggdGhlIG1heCBoZWlnaHQgb2YgdGhlIHByZXZpb3VzIHJvd1xuICAgICAgY3VycmVudFggPSAwO1xuICAgICAgY3VycmVudFkgPSBoZWlnaHQ7XG5cbiAgICAgIGlmIChpICE9IDApIHtcbiAgICAgICAgY3VycmVudFkgKz0gQ29TRUNvbnN0YW50cy5ERUZBVUxUX0NPTVBPTkVOVF9TRVBFUkFUSU9OO1xuICAgICAgfVxuXG4gICAgICBoZWlnaHQgPSAwO1xuICAgIH1cblxuICAgIHZhciB0cmVlID0gZm9yZXN0W2ldO1xuXG4gICAgLy8gRmluZCB0aGUgY2VudGVyIG9mIHRoZSB0cmVlXG4gICAgdmFyIGNlbnRlck5vZGUgPSBMYXlvdXQuZmluZENlbnRlck9mVHJlZSh0cmVlKTtcblxuICAgIC8vIFNldCB0aGUgc3RhcmluZyBwb2ludCBvZiB0aGUgbmV4dCB0cmVlXG4gICAgY3VycmVudFN0YXJ0aW5nUG9pbnQueCA9IGN1cnJlbnRYO1xuICAgIGN1cnJlbnRTdGFydGluZ1BvaW50LnkgPSBjdXJyZW50WTtcblxuICAgIC8vIERvIGEgcmFkaWFsIGxheW91dCBzdGFydGluZyB3aXRoIHRoZSBjZW50ZXJcbiAgICBwb2ludCA9IENvU0VMYXlvdXQucmFkaWFsTGF5b3V0KHRyZWUsIGNlbnRlck5vZGUsIGN1cnJlbnRTdGFydGluZ1BvaW50KTtcblxuICAgIGlmIChwb2ludC55ID4gaGVpZ2h0KSB7XG4gICAgICBoZWlnaHQgPSBNYXRoLmZsb29yKHBvaW50LnkpO1xuICAgIH1cblxuICAgIGN1cnJlbnRYID0gTWF0aC5mbG9vcihwb2ludC54ICsgQ29TRUNvbnN0YW50cy5ERUZBVUxUX0NPTVBPTkVOVF9TRVBFUkFUSU9OKTtcbiAgfVxuXG4gIHRoaXMudHJhbnNmb3JtKG5ldyBQb2ludEQoTGF5b3V0Q29uc3RhbnRzLldPUkxEX0NFTlRFUl9YIC0gcG9pbnQueCAvIDIsIExheW91dENvbnN0YW50cy5XT1JMRF9DRU5URVJfWSAtIHBvaW50LnkgLyAyKSk7XG59O1xuXG5Db1NFTGF5b3V0LnJhZGlhbExheW91dCA9IGZ1bmN0aW9uICh0cmVlLCBjZW50ZXJOb2RlLCBzdGFydGluZ1BvaW50KSB7XG4gIHZhciByYWRpYWxTZXAgPSBNYXRoLm1heCh0aGlzLm1heERpYWdvbmFsSW5UcmVlKHRyZWUpLCBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfUkFESUFMX1NFUEFSQVRJT04pO1xuICBDb1NFTGF5b3V0LmJyYW5jaFJhZGlhbExheW91dChjZW50ZXJOb2RlLCBudWxsLCAwLCAzNTksIDAsIHJhZGlhbFNlcCk7XG4gIHZhciBib3VuZHMgPSBMR3JhcGguY2FsY3VsYXRlQm91bmRzKHRyZWUpO1xuXG4gIHZhciB0cmFuc2Zvcm0gPSBuZXcgVHJhbnNmb3JtKCk7XG4gIHRyYW5zZm9ybS5zZXREZXZpY2VPcmdYKGJvdW5kcy5nZXRNaW5YKCkpO1xuICB0cmFuc2Zvcm0uc2V0RGV2aWNlT3JnWShib3VuZHMuZ2V0TWluWSgpKTtcbiAgdHJhbnNmb3JtLnNldFdvcmxkT3JnWChzdGFydGluZ1BvaW50LngpO1xuICB0cmFuc2Zvcm0uc2V0V29ybGRPcmdZKHN0YXJ0aW5nUG9pbnQueSk7XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0cmVlLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIG5vZGUgPSB0cmVlW2ldO1xuICAgIG5vZGUudHJhbnNmb3JtKHRyYW5zZm9ybSk7XG4gIH1cblxuICB2YXIgYm90dG9tUmlnaHQgPSBuZXcgUG9pbnREKGJvdW5kcy5nZXRNYXhYKCksIGJvdW5kcy5nZXRNYXhZKCkpO1xuXG4gIHJldHVybiB0cmFuc2Zvcm0uaW52ZXJzZVRyYW5zZm9ybVBvaW50KGJvdHRvbVJpZ2h0KTtcbn07XG5cbkNvU0VMYXlvdXQuYnJhbmNoUmFkaWFsTGF5b3V0ID0gZnVuY3Rpb24gKG5vZGUsIHBhcmVudE9mTm9kZSwgc3RhcnRBbmdsZSwgZW5kQW5nbGUsIGRpc3RhbmNlLCByYWRpYWxTZXBhcmF0aW9uKSB7XG4gIC8vIEZpcnN0LCBwb3NpdGlvbiB0aGlzIG5vZGUgYnkgZmluZGluZyBpdHMgYW5nbGUuXG4gIHZhciBoYWxmSW50ZXJ2YWwgPSAoZW5kQW5nbGUgLSBzdGFydEFuZ2xlICsgMSkgLyAyO1xuXG4gIGlmIChoYWxmSW50ZXJ2YWwgPCAwKSB7XG4gICAgaGFsZkludGVydmFsICs9IDE4MDtcbiAgfVxuXG4gIHZhciBub2RlQW5nbGUgPSAoaGFsZkludGVydmFsICsgc3RhcnRBbmdsZSkgJSAzNjA7XG4gIHZhciB0ZXRhID0gbm9kZUFuZ2xlICogSUdlb21ldHJ5LlRXT19QSSAvIDM2MDtcblxuICAvLyBNYWtlIHBvbGFyIHRvIGphdmEgY29yZGluYXRlIGNvbnZlcnNpb24uXG4gIHZhciBjb3NfdGV0YSA9IE1hdGguY29zKHRldGEpO1xuICB2YXIgeF8gPSBkaXN0YW5jZSAqIE1hdGguY29zKHRldGEpO1xuICB2YXIgeV8gPSBkaXN0YW5jZSAqIE1hdGguc2luKHRldGEpO1xuXG4gIG5vZGUuc2V0Q2VudGVyKHhfLCB5Xyk7XG5cbiAgLy8gVHJhdmVyc2UgYWxsIG5laWdoYm9ycyBvZiB0aGlzIG5vZGUgYW5kIHJlY3Vyc2l2ZWx5IGNhbGwgdGhpc1xuICAvLyBmdW5jdGlvbi5cbiAgdmFyIG5laWdoYm9yRWRnZXMgPSBbXTtcbiAgbmVpZ2hib3JFZGdlcyA9IG5laWdoYm9yRWRnZXMuY29uY2F0KG5vZGUuZ2V0RWRnZXMoKSk7XG4gIHZhciBjaGlsZENvdW50ID0gbmVpZ2hib3JFZGdlcy5sZW5ndGg7XG5cbiAgaWYgKHBhcmVudE9mTm9kZSAhPSBudWxsKSB7XG4gICAgY2hpbGRDb3VudC0tO1xuICB9XG5cbiAgdmFyIGJyYW5jaENvdW50ID0gMDtcblxuICB2YXIgaW5jRWRnZXNDb3VudCA9IG5laWdoYm9yRWRnZXMubGVuZ3RoO1xuICB2YXIgc3RhcnRJbmRleDtcblxuICB2YXIgZWRnZXMgPSBub2RlLmdldEVkZ2VzQmV0d2VlbihwYXJlbnRPZk5vZGUpO1xuXG4gIC8vIElmIHRoZXJlIGFyZSBtdWx0aXBsZSBlZGdlcywgcHJ1bmUgdGhlbSB1bnRpbCB0aGVyZSByZW1haW5zIG9ubHkgb25lXG4gIC8vIGVkZ2UuXG4gIHdoaWxlIChlZGdlcy5sZW5ndGggPiAxKSB7XG4gICAgLy9uZWlnaGJvckVkZ2VzLnJlbW92ZShlZGdlcy5yZW1vdmUoMCkpO1xuICAgIHZhciB0ZW1wID0gZWRnZXNbMF07XG4gICAgZWRnZXMuc3BsaWNlKDAsIDEpO1xuICAgIHZhciBpbmRleCA9IG5laWdoYm9yRWRnZXMuaW5kZXhPZih0ZW1wKTtcbiAgICBpZiAoaW5kZXggPj0gMCkge1xuICAgICAgbmVpZ2hib3JFZGdlcy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgIH1cbiAgICBpbmNFZGdlc0NvdW50LS07XG4gICAgY2hpbGRDb3VudC0tO1xuICB9XG5cbiAgaWYgKHBhcmVudE9mTm9kZSAhPSBudWxsKSB7XG4gICAgLy9hc3NlcnQgZWRnZXMubGVuZ3RoID09IDE7XG4gICAgc3RhcnRJbmRleCA9IChuZWlnaGJvckVkZ2VzLmluZGV4T2YoZWRnZXNbMF0pICsgMSkgJSBpbmNFZGdlc0NvdW50O1xuICB9IGVsc2Uge1xuICAgIHN0YXJ0SW5kZXggPSAwO1xuICB9XG5cbiAgdmFyIHN0ZXBBbmdsZSA9IE1hdGguYWJzKGVuZEFuZ2xlIC0gc3RhcnRBbmdsZSkgLyBjaGlsZENvdW50O1xuXG4gIGZvciAodmFyIGkgPSBzdGFydEluZGV4OyBicmFuY2hDb3VudCAhPSBjaGlsZENvdW50OyBpID0gKytpICUgaW5jRWRnZXNDb3VudCkge1xuICAgIHZhciBjdXJyZW50TmVpZ2hib3IgPSBuZWlnaGJvckVkZ2VzW2ldLmdldE90aGVyRW5kKG5vZGUpO1xuXG4gICAgLy8gRG9uJ3QgYmFjayB0cmF2ZXJzZSB0byByb290IG5vZGUgaW4gY3VycmVudCB0cmVlLlxuICAgIGlmIChjdXJyZW50TmVpZ2hib3IgPT0gcGFyZW50T2ZOb2RlKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICB2YXIgY2hpbGRTdGFydEFuZ2xlID0gKHN0YXJ0QW5nbGUgKyBicmFuY2hDb3VudCAqIHN0ZXBBbmdsZSkgJSAzNjA7XG4gICAgdmFyIGNoaWxkRW5kQW5nbGUgPSAoY2hpbGRTdGFydEFuZ2xlICsgc3RlcEFuZ2xlKSAlIDM2MDtcblxuICAgIENvU0VMYXlvdXQuYnJhbmNoUmFkaWFsTGF5b3V0KGN1cnJlbnROZWlnaGJvciwgbm9kZSwgY2hpbGRTdGFydEFuZ2xlLCBjaGlsZEVuZEFuZ2xlLCBkaXN0YW5jZSArIHJhZGlhbFNlcGFyYXRpb24sIHJhZGlhbFNlcGFyYXRpb24pO1xuXG4gICAgYnJhbmNoQ291bnQrKztcbiAgfVxufTtcblxuQ29TRUxheW91dC5tYXhEaWFnb25hbEluVHJlZSA9IGZ1bmN0aW9uICh0cmVlKSB7XG4gIHZhciBtYXhEaWFnb25hbCA9IEludGVnZXIuTUlOX1ZBTFVFO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdHJlZS5sZW5ndGg7IGkrKykge1xuICAgIHZhciBub2RlID0gdHJlZVtpXTtcbiAgICB2YXIgZGlhZ29uYWwgPSBub2RlLmdldERpYWdvbmFsKCk7XG5cbiAgICBpZiAoZGlhZ29uYWwgPiBtYXhEaWFnb25hbCkge1xuICAgICAgbWF4RGlhZ29uYWwgPSBkaWFnb25hbDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gbWF4RGlhZ29uYWw7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5jYWxjUmVwdWxzaW9uUmFuZ2UgPSBmdW5jdGlvbiAoKSB7XG4gIC8vIGZvcm11bGEgaXMgMiB4IChsZXZlbCArIDEpIHggaWRlYWxFZGdlTGVuZ3RoXG4gIHJldHVybiAyICogKHRoaXMubGV2ZWwgKyAxKSAqIHRoaXMuaWRlYWxFZGdlTGVuZ3RoO1xufTtcblxuLy8gVGlsaW5nIG1ldGhvZHNcblxuLy8gR3JvdXAgemVybyBkZWdyZWUgbWVtYmVycyB3aG9zZSBwYXJlbnRzIGFyZSBub3QgdG8gYmUgdGlsZWQsIGNyZWF0ZSBkdW1teSBwYXJlbnRzIHdoZXJlIG5lZWRlZCBhbmQgZmlsbCBtZW1iZXJHcm91cHMgYnkgdGhlaXIgZHVtbXAgcGFyZW50IGlkJ3NcbkNvU0VMYXlvdXQucHJvdG90eXBlLmdyb3VwWmVyb0RlZ3JlZU1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgLy8gYXJyYXkgb2YgW3BhcmVudF9pZCB4IG9uZURlZ3JlZU5vZGVfaWRdXG4gIHZhciB0ZW1wTWVtYmVyR3JvdXBzID0ge307IC8vIEEgdGVtcG9yYXJ5IG1hcCBvZiBwYXJlbnQgbm9kZSBhbmQgaXRzIHplcm8gZGVncmVlIG1lbWJlcnNcbiAgdGhpcy5tZW1iZXJHcm91cHMgPSB7fTsgLy8gQSBtYXAgb2YgZHVtbXkgcGFyZW50IG5vZGUgYW5kIGl0cyB6ZXJvIGRlZ3JlZSBtZW1iZXJzIHdob3NlIHBhcmVudHMgYXJlIG5vdCB0byBiZSB0aWxlZFxuICB0aGlzLmlkVG9EdW1teU5vZGUgPSB7fTsgLy8gQSBtYXAgb2YgaWQgdG8gZHVtbXkgbm9kZSBcblxuICB2YXIgemVyb0RlZ3JlZSA9IFtdOyAvLyBMaXN0IG9mIHplcm8gZGVncmVlIG5vZGVzIHdob3NlIHBhcmVudHMgYXJlIG5vdCB0byBiZSB0aWxlZFxuICB2YXIgYWxsTm9kZXMgPSB0aGlzLmdyYXBoTWFuYWdlci5nZXRBbGxOb2RlcygpO1xuXG4gIC8vIEZpbGwgemVybyBkZWdyZWUgbGlzdFxuICBmb3IgKHZhciBpID0gMDsgaSA8IGFsbE5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIG5vZGUgPSBhbGxOb2Rlc1tpXTtcbiAgICB2YXIgcGFyZW50ID0gbm9kZS5nZXRQYXJlbnQoKTtcbiAgICAvLyBJZiBhIG5vZGUgaGFzIHplcm8gZGVncmVlIGFuZCBpdHMgcGFyZW50IGlzIG5vdCB0byBiZSB0aWxlZCBpZiBleGlzdHMgYWRkIHRoYXQgbm9kZSB0byB6ZXJvRGVncmVzIGxpc3RcbiAgICBpZiAodGhpcy5nZXROb2RlRGVncmVlV2l0aENoaWxkcmVuKG5vZGUpID09PSAwICYmIChwYXJlbnQuaWQgPT0gdW5kZWZpbmVkIHx8ICF0aGlzLmdldFRvQmVUaWxlZChwYXJlbnQpKSkge1xuICAgICAgemVyb0RlZ3JlZS5wdXNoKG5vZGUpO1xuICAgIH1cbiAgfVxuXG4gIC8vIENyZWF0ZSBhIG1hcCBvZiBwYXJlbnQgbm9kZSBhbmQgaXRzIHplcm8gZGVncmVlIG1lbWJlcnNcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB6ZXJvRGVncmVlLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIG5vZGUgPSB6ZXJvRGVncmVlW2ldOyAvLyBaZXJvIGRlZ3JlZSBub2RlIGl0c2VsZlxuICAgIHZhciBwX2lkID0gbm9kZS5nZXRQYXJlbnQoKS5pZDsgLy8gUGFyZW50IGlkXG5cbiAgICBpZiAodHlwZW9mIHRlbXBNZW1iZXJHcm91cHNbcF9pZF0gPT09IFwidW5kZWZpbmVkXCIpIHRlbXBNZW1iZXJHcm91cHNbcF9pZF0gPSBbXTtcblxuICAgIHRlbXBNZW1iZXJHcm91cHNbcF9pZF0gPSB0ZW1wTWVtYmVyR3JvdXBzW3BfaWRdLmNvbmNhdChub2RlKTsgLy8gUHVzaCBub2RlIHRvIHRoZSBsaXN0IGJlbG9uZ3MgdG8gaXRzIHBhcmVudCBpbiB0ZW1wTWVtYmVyR3JvdXBzXG4gIH1cblxuICAvLyBJZiB0aGVyZSBhcmUgYXQgbGVhc3QgdHdvIG5vZGVzIGF0IGEgbGV2ZWwsIGNyZWF0ZSBhIGR1bW15IGNvbXBvdW5kIGZvciB0aGVtXG4gIE9iamVjdC5rZXlzKHRlbXBNZW1iZXJHcm91cHMpLmZvckVhY2goZnVuY3Rpb24gKHBfaWQpIHtcbiAgICBpZiAodGVtcE1lbWJlckdyb3Vwc1twX2lkXS5sZW5ndGggPiAxKSB7XG4gICAgICB2YXIgZHVtbXlDb21wb3VuZElkID0gXCJEdW1teUNvbXBvdW5kX1wiICsgcF9pZDsgLy8gVGhlIGlkIG9mIGR1bW15IGNvbXBvdW5kIHdoaWNoIHdpbGwgYmUgY3JlYXRlZCBzb29uXG4gICAgICBzZWxmLm1lbWJlckdyb3Vwc1tkdW1teUNvbXBvdW5kSWRdID0gdGVtcE1lbWJlckdyb3Vwc1twX2lkXTsgLy8gQWRkIGR1bW15IGNvbXBvdW5kIHRvIG1lbWJlckdyb3Vwc1xuXG4gICAgICB2YXIgcGFyZW50ID0gdGVtcE1lbWJlckdyb3Vwc1twX2lkXVswXS5nZXRQYXJlbnQoKTsgLy8gVGhlIHBhcmVudCBvZiB6ZXJvIGRlZ3JlZSBub2RlcyB3aWxsIGJlIHRoZSBwYXJlbnQgb2YgbmV3IGR1bW15IGNvbXBvdW5kXG5cbiAgICAgIC8vIENyZWF0ZSBhIGR1bW15IGNvbXBvdW5kIHdpdGggY2FsY3VsYXRlZCBpZFxuICAgICAgdmFyIGR1bW15Q29tcG91bmQgPSBuZXcgQ29TRU5vZGUoc2VsZi5ncmFwaE1hbmFnZXIpO1xuICAgICAgZHVtbXlDb21wb3VuZC5pZCA9IGR1bW15Q29tcG91bmRJZDtcbiAgICAgIGR1bW15Q29tcG91bmQucGFkZGluZ0xlZnQgPSBwYXJlbnQucGFkZGluZ0xlZnQgfHwgMDtcbiAgICAgIGR1bW15Q29tcG91bmQucGFkZGluZ1JpZ2h0ID0gcGFyZW50LnBhZGRpbmdSaWdodCB8fCAwO1xuICAgICAgZHVtbXlDb21wb3VuZC5wYWRkaW5nQm90dG9tID0gcGFyZW50LnBhZGRpbmdCb3R0b20gfHwgMDtcbiAgICAgIGR1bW15Q29tcG91bmQucGFkZGluZ1RvcCA9IHBhcmVudC5wYWRkaW5nVG9wIHx8IDA7XG5cbiAgICAgIHNlbGYuaWRUb0R1bW15Tm9kZVtkdW1teUNvbXBvdW5kSWRdID0gZHVtbXlDb21wb3VuZDtcblxuICAgICAgdmFyIGR1bW15UGFyZW50R3JhcGggPSBzZWxmLmdldEdyYXBoTWFuYWdlcigpLmFkZChzZWxmLm5ld0dyYXBoKCksIGR1bW15Q29tcG91bmQpO1xuICAgICAgdmFyIHBhcmVudEdyYXBoID0gcGFyZW50LmdldENoaWxkKCk7XG5cbiAgICAgIC8vIEFkZCBkdW1teSBjb21wb3VuZCB0byBwYXJlbnQgdGhlIGdyYXBoXG4gICAgICBwYXJlbnRHcmFwaC5hZGQoZHVtbXlDb21wb3VuZCk7XG5cbiAgICAgIC8vIEZvciBlYWNoIHplcm8gZGVncmVlIG5vZGUgaW4gdGhpcyBsZXZlbCByZW1vdmUgaXQgZnJvbSBpdHMgcGFyZW50IGdyYXBoIGFuZCBhZGQgaXQgdG8gdGhlIGdyYXBoIG9mIGR1bW15IHBhcmVudFxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0ZW1wTWVtYmVyR3JvdXBzW3BfaWRdLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBub2RlID0gdGVtcE1lbWJlckdyb3Vwc1twX2lkXVtpXTtcblxuICAgICAgICBwYXJlbnRHcmFwaC5yZW1vdmUobm9kZSk7XG4gICAgICAgIGR1bW15UGFyZW50R3JhcGguYWRkKG5vZGUpO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5jbGVhckNvbXBvdW5kcyA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIGNoaWxkR3JhcGhNYXAgPSB7fTtcbiAgdmFyIGlkVG9Ob2RlID0ge307XG5cbiAgLy8gR2V0IGNvbXBvdW5kIG9yZGVyaW5nIGJ5IGZpbmRpbmcgdGhlIGlubmVyIG9uZSBmaXJzdFxuICB0aGlzLnBlcmZvcm1ERlNPbkNvbXBvdW5kcygpO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jb21wb3VuZE9yZGVyLmxlbmd0aDsgaSsrKSB7XG5cbiAgICBpZFRvTm9kZVt0aGlzLmNvbXBvdW5kT3JkZXJbaV0uaWRdID0gdGhpcy5jb21wb3VuZE9yZGVyW2ldO1xuICAgIGNoaWxkR3JhcGhNYXBbdGhpcy5jb21wb3VuZE9yZGVyW2ldLmlkXSA9IFtdLmNvbmNhdCh0aGlzLmNvbXBvdW5kT3JkZXJbaV0uZ2V0Q2hpbGQoKS5nZXROb2RlcygpKTtcblxuICAgIC8vIFJlbW92ZSBjaGlsZHJlbiBvZiBjb21wb3VuZHNcbiAgICB0aGlzLmdyYXBoTWFuYWdlci5yZW1vdmUodGhpcy5jb21wb3VuZE9yZGVyW2ldLmdldENoaWxkKCkpO1xuICAgIHRoaXMuY29tcG91bmRPcmRlcltpXS5jaGlsZCA9IG51bGw7XG4gIH1cblxuICB0aGlzLmdyYXBoTWFuYWdlci5yZXNldEFsbE5vZGVzKCk7XG5cbiAgLy8gVGlsZSB0aGUgcmVtb3ZlZCBjaGlsZHJlblxuICB0aGlzLnRpbGVDb21wb3VuZE1lbWJlcnMoY2hpbGRHcmFwaE1hcCwgaWRUb05vZGUpO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuY2xlYXJaZXJvRGVncmVlTWVtYmVycyA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICB2YXIgdGlsZWRaZXJvRGVncmVlUGFjayA9IHRoaXMudGlsZWRaZXJvRGVncmVlUGFjayA9IFtdO1xuXG4gIE9iamVjdC5rZXlzKHRoaXMubWVtYmVyR3JvdXBzKS5mb3JFYWNoKGZ1bmN0aW9uIChpZCkge1xuICAgIHZhciBjb21wb3VuZE5vZGUgPSBzZWxmLmlkVG9EdW1teU5vZGVbaWRdOyAvLyBHZXQgdGhlIGR1bW15IGNvbXBvdW5kXG5cbiAgICB0aWxlZFplcm9EZWdyZWVQYWNrW2lkXSA9IHNlbGYudGlsZU5vZGVzKHNlbGYubWVtYmVyR3JvdXBzW2lkXSwgY29tcG91bmROb2RlLnBhZGRpbmdMZWZ0ICsgY29tcG91bmROb2RlLnBhZGRpbmdSaWdodCk7XG5cbiAgICAvLyBTZXQgdGhlIHdpZHRoIGFuZCBoZWlnaHQgb2YgdGhlIGR1bW15IGNvbXBvdW5kIGFzIGNhbGN1bGF0ZWRcbiAgICBjb21wb3VuZE5vZGUucmVjdC53aWR0aCA9IHRpbGVkWmVyb0RlZ3JlZVBhY2tbaWRdLndpZHRoO1xuICAgIGNvbXBvdW5kTm9kZS5yZWN0LmhlaWdodCA9IHRpbGVkWmVyb0RlZ3JlZVBhY2tbaWRdLmhlaWdodDtcbiAgfSk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5yZXBvcHVsYXRlQ29tcG91bmRzID0gZnVuY3Rpb24gKCkge1xuICBmb3IgKHZhciBpID0gdGhpcy5jb21wb3VuZE9yZGVyLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgdmFyIGxDb21wb3VuZE5vZGUgPSB0aGlzLmNvbXBvdW5kT3JkZXJbaV07XG4gICAgdmFyIGlkID0gbENvbXBvdW5kTm9kZS5pZDtcbiAgICB2YXIgaG9yaXpvbnRhbE1hcmdpbiA9IGxDb21wb3VuZE5vZGUucGFkZGluZ0xlZnQ7XG4gICAgdmFyIHZlcnRpY2FsTWFyZ2luID0gbENvbXBvdW5kTm9kZS5wYWRkaW5nVG9wO1xuXG4gICAgdGhpcy5hZGp1c3RMb2NhdGlvbnModGhpcy50aWxlZE1lbWJlclBhY2tbaWRdLCBsQ29tcG91bmROb2RlLnJlY3QueCwgbENvbXBvdW5kTm9kZS5yZWN0LnksIGhvcml6b250YWxNYXJnaW4sIHZlcnRpY2FsTWFyZ2luKTtcbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUucmVwb3B1bGF0ZVplcm9EZWdyZWVNZW1iZXJzID0gZnVuY3Rpb24gKCkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHZhciB0aWxlZFBhY2sgPSB0aGlzLnRpbGVkWmVyb0RlZ3JlZVBhY2s7XG5cbiAgT2JqZWN0LmtleXModGlsZWRQYWNrKS5mb3JFYWNoKGZ1bmN0aW9uIChpZCkge1xuICAgIHZhciBjb21wb3VuZE5vZGUgPSBzZWxmLmlkVG9EdW1teU5vZGVbaWRdOyAvLyBHZXQgdGhlIGR1bW15IGNvbXBvdW5kIGJ5IGl0cyBpZFxuICAgIHZhciBob3Jpem9udGFsTWFyZ2luID0gY29tcG91bmROb2RlLnBhZGRpbmdMZWZ0O1xuICAgIHZhciB2ZXJ0aWNhbE1hcmdpbiA9IGNvbXBvdW5kTm9kZS5wYWRkaW5nVG9wO1xuXG4gICAgLy8gQWRqdXN0IHRoZSBwb3NpdGlvbnMgb2Ygbm9kZXMgd3J0IGl0cyBjb21wb3VuZFxuICAgIHNlbGYuYWRqdXN0TG9jYXRpb25zKHRpbGVkUGFja1tpZF0sIGNvbXBvdW5kTm9kZS5yZWN0LngsIGNvbXBvdW5kTm9kZS5yZWN0LnksIGhvcml6b250YWxNYXJnaW4sIHZlcnRpY2FsTWFyZ2luKTtcbiAgfSk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5nZXRUb0JlVGlsZWQgPSBmdW5jdGlvbiAobm9kZSkge1xuICB2YXIgaWQgPSBub2RlLmlkO1xuICAvL2ZpcnN0bHkgY2hlY2sgdGhlIHByZXZpb3VzIHJlc3VsdHNcbiAgaWYgKHRoaXMudG9CZVRpbGVkW2lkXSAhPSBudWxsKSB7XG4gICAgcmV0dXJuIHRoaXMudG9CZVRpbGVkW2lkXTtcbiAgfVxuXG4gIC8vb25seSBjb21wb3VuZCBub2RlcyBhcmUgdG8gYmUgdGlsZWRcbiAgdmFyIGNoaWxkR3JhcGggPSBub2RlLmdldENoaWxkKCk7XG4gIGlmIChjaGlsZEdyYXBoID09IG51bGwpIHtcbiAgICB0aGlzLnRvQmVUaWxlZFtpZF0gPSBmYWxzZTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICB2YXIgY2hpbGRyZW4gPSBjaGlsZEdyYXBoLmdldE5vZGVzKCk7IC8vIEdldCB0aGUgY2hpbGRyZW4gbm9kZXNcblxuICAvL2EgY29tcG91bmQgbm9kZSBpcyBub3QgdG8gYmUgdGlsZWQgaWYgYWxsIG9mIGl0cyBjb21wb3VuZCBjaGlsZHJlbiBhcmUgbm90IHRvIGJlIHRpbGVkXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgdGhlQ2hpbGQgPSBjaGlsZHJlbltpXTtcblxuICAgIGlmICh0aGlzLmdldE5vZGVEZWdyZWUodGhlQ2hpbGQpID4gMCkge1xuICAgICAgdGhpcy50b0JlVGlsZWRbaWRdID0gZmFsc2U7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy9wYXNzIHRoZSBjaGlsZHJlbiBub3QgaGF2aW5nIHRoZSBjb21wb3VuZCBzdHJ1Y3R1cmVcbiAgICBpZiAodGhlQ2hpbGQuZ2V0Q2hpbGQoKSA9PSBudWxsKSB7XG4gICAgICB0aGlzLnRvQmVUaWxlZFt0aGVDaGlsZC5pZF0gPSBmYWxzZTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5nZXRUb0JlVGlsZWQodGhlQ2hpbGQpKSB7XG4gICAgICB0aGlzLnRvQmVUaWxlZFtpZF0gPSBmYWxzZTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgdGhpcy50b0JlVGlsZWRbaWRdID0gdHJ1ZTtcbiAgcmV0dXJuIHRydWU7XG59O1xuXG4vLyBHZXQgZGVncmVlIG9mIGEgbm9kZSBkZXBlbmRpbmcgb2YgaXRzIGVkZ2VzIGFuZCBpbmRlcGVuZGVudCBvZiBpdHMgY2hpbGRyZW5cbkNvU0VMYXlvdXQucHJvdG90eXBlLmdldE5vZGVEZWdyZWUgPSBmdW5jdGlvbiAobm9kZSkge1xuICB2YXIgaWQgPSBub2RlLmlkO1xuICB2YXIgZWRnZXMgPSBub2RlLmdldEVkZ2VzKCk7XG4gIHZhciBkZWdyZWUgPSAwO1xuXG4gIC8vIEZvciB0aGUgZWRnZXMgY29ubmVjdGVkXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgZWRnZXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgZWRnZSA9IGVkZ2VzW2ldO1xuICAgIGlmIChlZGdlLmdldFNvdXJjZSgpLmlkICE9PSBlZGdlLmdldFRhcmdldCgpLmlkKSB7XG4gICAgICBkZWdyZWUgPSBkZWdyZWUgKyAxO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZGVncmVlO1xufTtcblxuLy8gR2V0IGRlZ3JlZSBvZiBhIG5vZGUgd2l0aCBpdHMgY2hpbGRyZW5cbkNvU0VMYXlvdXQucHJvdG90eXBlLmdldE5vZGVEZWdyZWVXaXRoQ2hpbGRyZW4gPSBmdW5jdGlvbiAobm9kZSkge1xuICB2YXIgZGVncmVlID0gdGhpcy5nZXROb2RlRGVncmVlKG5vZGUpO1xuICBpZiAobm9kZS5nZXRDaGlsZCgpID09IG51bGwpIHtcbiAgICByZXR1cm4gZGVncmVlO1xuICB9XG4gIHZhciBjaGlsZHJlbiA9IG5vZGUuZ2V0Q2hpbGQoKS5nZXROb2RlcygpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGNoaWxkID0gY2hpbGRyZW5baV07XG4gICAgZGVncmVlICs9IHRoaXMuZ2V0Tm9kZURlZ3JlZVdpdGhDaGlsZHJlbihjaGlsZCk7XG4gIH1cbiAgcmV0dXJuIGRlZ3JlZTtcbn07XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlLnBlcmZvcm1ERlNPbkNvbXBvdW5kcyA9IGZ1bmN0aW9uICgpIHtcbiAgdGhpcy5jb21wb3VuZE9yZGVyID0gW107XG4gIHRoaXMuZmlsbENvbXBleE9yZGVyQnlERlModGhpcy5ncmFwaE1hbmFnZXIuZ2V0Um9vdCgpLmdldE5vZGVzKCkpO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuZmlsbENvbXBleE9yZGVyQnlERlMgPSBmdW5jdGlvbiAoY2hpbGRyZW4pIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgIHZhciBjaGlsZCA9IGNoaWxkcmVuW2ldO1xuICAgIGlmIChjaGlsZC5nZXRDaGlsZCgpICE9IG51bGwpIHtcbiAgICAgIHRoaXMuZmlsbENvbXBleE9yZGVyQnlERlMoY2hpbGQuZ2V0Q2hpbGQoKS5nZXROb2RlcygpKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuZ2V0VG9CZVRpbGVkKGNoaWxkKSkge1xuICAgICAgdGhpcy5jb21wb3VuZE9yZGVyLnB1c2goY2hpbGQpO1xuICAgIH1cbiAgfVxufTtcblxuLyoqXG4qIFRoaXMgbWV0aG9kIHBsYWNlcyBlYWNoIHplcm8gZGVncmVlIG1lbWJlciB3cnQgZ2l2ZW4gKHgseSkgY29vcmRpbmF0ZXMgKHRvcCBsZWZ0KS5cbiovXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5hZGp1c3RMb2NhdGlvbnMgPSBmdW5jdGlvbiAob3JnYW5pemF0aW9uLCB4LCB5LCBjb21wb3VuZEhvcml6b250YWxNYXJnaW4sIGNvbXBvdW5kVmVydGljYWxNYXJnaW4pIHtcbiAgeCArPSBjb21wb3VuZEhvcml6b250YWxNYXJnaW47XG4gIHkgKz0gY29tcG91bmRWZXJ0aWNhbE1hcmdpbjtcblxuICB2YXIgbGVmdCA9IHg7XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcmdhbml6YXRpb24ucm93cy5sZW5ndGg7IGkrKykge1xuICAgIHZhciByb3cgPSBvcmdhbml6YXRpb24ucm93c1tpXTtcbiAgICB4ID0gbGVmdDtcbiAgICB2YXIgbWF4SGVpZ2h0ID0gMDtcblxuICAgIGZvciAodmFyIGogPSAwOyBqIDwgcm93Lmxlbmd0aDsgaisrKSB7XG4gICAgICB2YXIgbG5vZGUgPSByb3dbal07XG5cbiAgICAgIGxub2RlLnJlY3QueCA9IHg7IC8vICsgbG5vZGUucmVjdC53aWR0aCAvIDI7XG4gICAgICBsbm9kZS5yZWN0LnkgPSB5OyAvLyArIGxub2RlLnJlY3QuaGVpZ2h0IC8gMjtcblxuICAgICAgeCArPSBsbm9kZS5yZWN0LndpZHRoICsgb3JnYW5pemF0aW9uLmhvcml6b250YWxQYWRkaW5nO1xuXG4gICAgICBpZiAobG5vZGUucmVjdC5oZWlnaHQgPiBtYXhIZWlnaHQpIG1heEhlaWdodCA9IGxub2RlLnJlY3QuaGVpZ2h0O1xuICAgIH1cblxuICAgIHkgKz0gbWF4SGVpZ2h0ICsgb3JnYW5pemF0aW9uLnZlcnRpY2FsUGFkZGluZztcbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUudGlsZUNvbXBvdW5kTWVtYmVycyA9IGZ1bmN0aW9uIChjaGlsZEdyYXBoTWFwLCBpZFRvTm9kZSkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHRoaXMudGlsZWRNZW1iZXJQYWNrID0gW107XG5cbiAgT2JqZWN0LmtleXMoY2hpbGRHcmFwaE1hcCkuZm9yRWFjaChmdW5jdGlvbiAoaWQpIHtcbiAgICAvLyBHZXQgdGhlIGNvbXBvdW5kIG5vZGVcbiAgICB2YXIgY29tcG91bmROb2RlID0gaWRUb05vZGVbaWRdO1xuXG4gICAgc2VsZi50aWxlZE1lbWJlclBhY2tbaWRdID0gc2VsZi50aWxlTm9kZXMoY2hpbGRHcmFwaE1hcFtpZF0sIGNvbXBvdW5kTm9kZS5wYWRkaW5nTGVmdCArIGNvbXBvdW5kTm9kZS5wYWRkaW5nUmlnaHQpO1xuXG4gICAgY29tcG91bmROb2RlLnJlY3Qud2lkdGggPSBzZWxmLnRpbGVkTWVtYmVyUGFja1tpZF0ud2lkdGg7XG4gICAgY29tcG91bmROb2RlLnJlY3QuaGVpZ2h0ID0gc2VsZi50aWxlZE1lbWJlclBhY2tbaWRdLmhlaWdodDtcbiAgfSk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS50aWxlTm9kZXMgPSBmdW5jdGlvbiAobm9kZXMsIG1pbldpZHRoKSB7XG4gIHZhciB2ZXJ0aWNhbFBhZGRpbmcgPSBDb1NFQ29uc3RhbnRzLlRJTElOR19QQURESU5HX1ZFUlRJQ0FMO1xuICB2YXIgaG9yaXpvbnRhbFBhZGRpbmcgPSBDb1NFQ29uc3RhbnRzLlRJTElOR19QQURESU5HX0hPUklaT05UQUw7XG4gIHZhciBvcmdhbml6YXRpb24gPSB7XG4gICAgcm93czogW10sXG4gICAgcm93V2lkdGg6IFtdLFxuICAgIHJvd0hlaWdodDogW10sXG4gICAgd2lkdGg6IDAsXG4gICAgaGVpZ2h0OiBtaW5XaWR0aCwgLy8gYXNzdW1lIG1pbkhlaWdodCBlcXVhbHMgdG8gbWluV2lkdGhcbiAgICB2ZXJ0aWNhbFBhZGRpbmc6IHZlcnRpY2FsUGFkZGluZyxcbiAgICBob3Jpem9udGFsUGFkZGluZzogaG9yaXpvbnRhbFBhZGRpbmdcbiAgfTtcblxuICAvLyBTb3J0IHRoZSBub2RlcyBpbiBhc2NlbmRpbmcgb3JkZXIgb2YgdGhlaXIgYXJlYXNcbiAgbm9kZXMuc29ydChmdW5jdGlvbiAobjEsIG4yKSB7XG4gICAgaWYgKG4xLnJlY3Qud2lkdGggKiBuMS5yZWN0LmhlaWdodCA+IG4yLnJlY3Qud2lkdGggKiBuMi5yZWN0LmhlaWdodCkgcmV0dXJuIC0xO1xuICAgIGlmIChuMS5yZWN0LndpZHRoICogbjEucmVjdC5oZWlnaHQgPCBuMi5yZWN0LndpZHRoICogbjIucmVjdC5oZWlnaHQpIHJldHVybiAxO1xuICAgIHJldHVybiAwO1xuICB9KTtcblxuICAvLyBDcmVhdGUgdGhlIG9yZ2FuaXphdGlvbiAtPiB0aWxlIG1lbWJlcnNcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBsTm9kZSA9IG5vZGVzW2ldO1xuXG4gICAgaWYgKG9yZ2FuaXphdGlvbi5yb3dzLmxlbmd0aCA9PSAwKSB7XG4gICAgICB0aGlzLmluc2VydE5vZGVUb1Jvdyhvcmdhbml6YXRpb24sIGxOb2RlLCAwLCBtaW5XaWR0aCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmNhbkFkZEhvcml6b250YWwob3JnYW5pemF0aW9uLCBsTm9kZS5yZWN0LndpZHRoLCBsTm9kZS5yZWN0LmhlaWdodCkpIHtcbiAgICAgIHRoaXMuaW5zZXJ0Tm9kZVRvUm93KG9yZ2FuaXphdGlvbiwgbE5vZGUsIHRoaXMuZ2V0U2hvcnRlc3RSb3dJbmRleChvcmdhbml6YXRpb24pLCBtaW5XaWR0aCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaW5zZXJ0Tm9kZVRvUm93KG9yZ2FuaXphdGlvbiwgbE5vZGUsIG9yZ2FuaXphdGlvbi5yb3dzLmxlbmd0aCwgbWluV2lkdGgpO1xuICAgIH1cblxuICAgIHRoaXMuc2hpZnRUb0xhc3RSb3cob3JnYW5pemF0aW9uKTtcbiAgfVxuXG4gIHJldHVybiBvcmdhbml6YXRpb247XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5pbnNlcnROb2RlVG9Sb3cgPSBmdW5jdGlvbiAob3JnYW5pemF0aW9uLCBub2RlLCByb3dJbmRleCwgbWluV2lkdGgpIHtcbiAgdmFyIG1pbkNvbXBvdW5kU2l6ZSA9IG1pbldpZHRoO1xuXG4gIC8vIEFkZCBuZXcgcm93IGlmIG5lZWRlZFxuICBpZiAocm93SW5kZXggPT0gb3JnYW5pemF0aW9uLnJvd3MubGVuZ3RoKSB7XG4gICAgdmFyIHNlY29uZERpbWVuc2lvbiA9IFtdO1xuXG4gICAgb3JnYW5pemF0aW9uLnJvd3MucHVzaChzZWNvbmREaW1lbnNpb24pO1xuICAgIG9yZ2FuaXphdGlvbi5yb3dXaWR0aC5wdXNoKG1pbkNvbXBvdW5kU2l6ZSk7XG4gICAgb3JnYW5pemF0aW9uLnJvd0hlaWdodC5wdXNoKDApO1xuICB9XG5cbiAgLy8gVXBkYXRlIHJvdyB3aWR0aFxuICB2YXIgdyA9IG9yZ2FuaXphdGlvbi5yb3dXaWR0aFtyb3dJbmRleF0gKyBub2RlLnJlY3Qud2lkdGg7XG5cbiAgaWYgKG9yZ2FuaXphdGlvbi5yb3dzW3Jvd0luZGV4XS5sZW5ndGggPiAwKSB7XG4gICAgdyArPSBvcmdhbml6YXRpb24uaG9yaXpvbnRhbFBhZGRpbmc7XG4gIH1cblxuICBvcmdhbml6YXRpb24ucm93V2lkdGhbcm93SW5kZXhdID0gdztcbiAgLy8gVXBkYXRlIGNvbXBvdW5kIHdpZHRoXG4gIGlmIChvcmdhbml6YXRpb24ud2lkdGggPCB3KSB7XG4gICAgb3JnYW5pemF0aW9uLndpZHRoID0gdztcbiAgfVxuXG4gIC8vIFVwZGF0ZSBoZWlnaHRcbiAgdmFyIGggPSBub2RlLnJlY3QuaGVpZ2h0O1xuICBpZiAocm93SW5kZXggPiAwKSBoICs9IG9yZ2FuaXphdGlvbi52ZXJ0aWNhbFBhZGRpbmc7XG5cbiAgdmFyIGV4dHJhSGVpZ2h0ID0gMDtcbiAgaWYgKGggPiBvcmdhbml6YXRpb24ucm93SGVpZ2h0W3Jvd0luZGV4XSkge1xuICAgIGV4dHJhSGVpZ2h0ID0gb3JnYW5pemF0aW9uLnJvd0hlaWdodFtyb3dJbmRleF07XG4gICAgb3JnYW5pemF0aW9uLnJvd0hlaWdodFtyb3dJbmRleF0gPSBoO1xuICAgIGV4dHJhSGVpZ2h0ID0gb3JnYW5pemF0aW9uLnJvd0hlaWdodFtyb3dJbmRleF0gLSBleHRyYUhlaWdodDtcbiAgfVxuXG4gIG9yZ2FuaXphdGlvbi5oZWlnaHQgKz0gZXh0cmFIZWlnaHQ7XG5cbiAgLy8gSW5zZXJ0IG5vZGVcbiAgb3JnYW5pemF0aW9uLnJvd3Nbcm93SW5kZXhdLnB1c2gobm9kZSk7XG59O1xuXG4vL1NjYW5zIHRoZSByb3dzIG9mIGFuIG9yZ2FuaXphdGlvbiBhbmQgcmV0dXJucyB0aGUgb25lIHdpdGggdGhlIG1pbiB3aWR0aFxuQ29TRUxheW91dC5wcm90b3R5cGUuZ2V0U2hvcnRlc3RSb3dJbmRleCA9IGZ1bmN0aW9uIChvcmdhbml6YXRpb24pIHtcbiAgdmFyIHIgPSAtMTtcbiAgdmFyIG1pbiA9IE51bWJlci5NQVhfVkFMVUU7XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcmdhbml6YXRpb24ucm93cy5sZW5ndGg7IGkrKykge1xuICAgIGlmIChvcmdhbml6YXRpb24ucm93V2lkdGhbaV0gPCBtaW4pIHtcbiAgICAgIHIgPSBpO1xuICAgICAgbWluID0gb3JnYW5pemF0aW9uLnJvd1dpZHRoW2ldO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcjtcbn07XG5cbi8vU2NhbnMgdGhlIHJvd3Mgb2YgYW4gb3JnYW5pemF0aW9uIGFuZCByZXR1cm5zIHRoZSBvbmUgd2l0aCB0aGUgbWF4IHdpZHRoXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5nZXRMb25nZXN0Um93SW5kZXggPSBmdW5jdGlvbiAob3JnYW5pemF0aW9uKSB7XG4gIHZhciByID0gLTE7XG4gIHZhciBtYXggPSBOdW1iZXIuTUlOX1ZBTFVFO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgb3JnYW5pemF0aW9uLnJvd3MubGVuZ3RoOyBpKyspIHtcblxuICAgIGlmIChvcmdhbml6YXRpb24ucm93V2lkdGhbaV0gPiBtYXgpIHtcbiAgICAgIHIgPSBpO1xuICAgICAgbWF4ID0gb3JnYW5pemF0aW9uLnJvd1dpZHRoW2ldO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiByO1xufTtcblxuLyoqXG4qIFRoaXMgbWV0aG9kIGNoZWNrcyB3aGV0aGVyIGFkZGluZyBleHRyYSB3aWR0aCB0byB0aGUgb3JnYW5pemF0aW9uIHZpb2xhdGVzXG4qIHRoZSBhc3BlY3QgcmF0aW8oMSkgb3Igbm90LlxuKi9cbkNvU0VMYXlvdXQucHJvdG90eXBlLmNhbkFkZEhvcml6b250YWwgPSBmdW5jdGlvbiAob3JnYW5pemF0aW9uLCBleHRyYVdpZHRoLCBleHRyYUhlaWdodCkge1xuXG4gIHZhciBzcmkgPSB0aGlzLmdldFNob3J0ZXN0Um93SW5kZXgob3JnYW5pemF0aW9uKTtcblxuICBpZiAoc3JpIDwgMCkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgdmFyIG1pbiA9IG9yZ2FuaXphdGlvbi5yb3dXaWR0aFtzcmldO1xuXG4gIGlmIChtaW4gKyBvcmdhbml6YXRpb24uaG9yaXpvbnRhbFBhZGRpbmcgKyBleHRyYVdpZHRoIDw9IG9yZ2FuaXphdGlvbi53aWR0aCkgcmV0dXJuIHRydWU7XG5cbiAgdmFyIGhEaWZmID0gMDtcblxuICAvLyBBZGRpbmcgdG8gYW4gZXhpc3Rpbmcgcm93XG4gIGlmIChvcmdhbml6YXRpb24ucm93SGVpZ2h0W3NyaV0gPCBleHRyYUhlaWdodCkge1xuICAgIGlmIChzcmkgPiAwKSBoRGlmZiA9IGV4dHJhSGVpZ2h0ICsgb3JnYW5pemF0aW9uLnZlcnRpY2FsUGFkZGluZyAtIG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbc3JpXTtcbiAgfVxuXG4gIHZhciBhZGRfdG9fcm93X3JhdGlvO1xuICBpZiAob3JnYW5pemF0aW9uLndpZHRoIC0gbWluID49IGV4dHJhV2lkdGggKyBvcmdhbml6YXRpb24uaG9yaXpvbnRhbFBhZGRpbmcpIHtcbiAgICBhZGRfdG9fcm93X3JhdGlvID0gKG9yZ2FuaXphdGlvbi5oZWlnaHQgKyBoRGlmZikgLyAobWluICsgZXh0cmFXaWR0aCArIG9yZ2FuaXphdGlvbi5ob3Jpem9udGFsUGFkZGluZyk7XG4gIH0gZWxzZSB7XG4gICAgYWRkX3RvX3Jvd19yYXRpbyA9IChvcmdhbml6YXRpb24uaGVpZ2h0ICsgaERpZmYpIC8gb3JnYW5pemF0aW9uLndpZHRoO1xuICB9XG5cbiAgLy8gQWRkaW5nIGEgbmV3IHJvdyBmb3IgdGhpcyBub2RlXG4gIGhEaWZmID0gZXh0cmFIZWlnaHQgKyBvcmdhbml6YXRpb24udmVydGljYWxQYWRkaW5nO1xuICB2YXIgYWRkX25ld19yb3dfcmF0aW87XG4gIGlmIChvcmdhbml6YXRpb24ud2lkdGggPCBleHRyYVdpZHRoKSB7XG4gICAgYWRkX25ld19yb3dfcmF0aW8gPSAob3JnYW5pemF0aW9uLmhlaWdodCArIGhEaWZmKSAvIGV4dHJhV2lkdGg7XG4gIH0gZWxzZSB7XG4gICAgYWRkX25ld19yb3dfcmF0aW8gPSAob3JnYW5pemF0aW9uLmhlaWdodCArIGhEaWZmKSAvIG9yZ2FuaXphdGlvbi53aWR0aDtcbiAgfVxuXG4gIGlmIChhZGRfbmV3X3Jvd19yYXRpbyA8IDEpIGFkZF9uZXdfcm93X3JhdGlvID0gMSAvIGFkZF9uZXdfcm93X3JhdGlvO1xuXG4gIGlmIChhZGRfdG9fcm93X3JhdGlvIDwgMSkgYWRkX3RvX3Jvd19yYXRpbyA9IDEgLyBhZGRfdG9fcm93X3JhdGlvO1xuXG4gIHJldHVybiBhZGRfdG9fcm93X3JhdGlvIDwgYWRkX25ld19yb3dfcmF0aW87XG59O1xuXG4vL0lmIG1vdmluZyB0aGUgbGFzdCBub2RlIGZyb20gdGhlIGxvbmdlc3Qgcm93IGFuZCBhZGRpbmcgaXQgdG8gdGhlIGxhc3Rcbi8vcm93IG1ha2VzIHRoZSBib3VuZGluZyBib3ggc21hbGxlciwgZG8gaXQuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5zaGlmdFRvTGFzdFJvdyA9IGZ1bmN0aW9uIChvcmdhbml6YXRpb24pIHtcbiAgdmFyIGxvbmdlc3QgPSB0aGlzLmdldExvbmdlc3RSb3dJbmRleChvcmdhbml6YXRpb24pO1xuICB2YXIgbGFzdCA9IG9yZ2FuaXphdGlvbi5yb3dXaWR0aC5sZW5ndGggLSAxO1xuICB2YXIgcm93ID0gb3JnYW5pemF0aW9uLnJvd3NbbG9uZ2VzdF07XG4gIHZhciBub2RlID0gcm93W3Jvdy5sZW5ndGggLSAxXTtcblxuICB2YXIgZGlmZiA9IG5vZGUud2lkdGggKyBvcmdhbml6YXRpb24uaG9yaXpvbnRhbFBhZGRpbmc7XG5cbiAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgZW5vdWdoIHNwYWNlIG9uIHRoZSBsYXN0IHJvd1xuICBpZiAob3JnYW5pemF0aW9uLndpZHRoIC0gb3JnYW5pemF0aW9uLnJvd1dpZHRoW2xhc3RdID4gZGlmZiAmJiBsb25nZXN0ICE9IGxhc3QpIHtcbiAgICAvLyBSZW1vdmUgdGhlIGxhc3QgZWxlbWVudCBvZiB0aGUgbG9uZ2VzdCByb3dcbiAgICByb3cuc3BsaWNlKC0xLCAxKTtcblxuICAgIC8vIFB1c2ggaXQgdG8gdGhlIGxhc3Qgcm93XG4gICAgb3JnYW5pemF0aW9uLnJvd3NbbGFzdF0ucHVzaChub2RlKTtcblxuICAgIG9yZ2FuaXphdGlvbi5yb3dXaWR0aFtsb25nZXN0XSA9IG9yZ2FuaXphdGlvbi5yb3dXaWR0aFtsb25nZXN0XSAtIGRpZmY7XG4gICAgb3JnYW5pemF0aW9uLnJvd1dpZHRoW2xhc3RdID0gb3JnYW5pemF0aW9uLnJvd1dpZHRoW2xhc3RdICsgZGlmZjtcbiAgICBvcmdhbml6YXRpb24ud2lkdGggPSBvcmdhbml6YXRpb24ucm93V2lkdGhbaW5zdGFuY2UuZ2V0TG9uZ2VzdFJvd0luZGV4KG9yZ2FuaXphdGlvbildO1xuXG4gICAgLy8gVXBkYXRlIGhlaWdodHMgb2YgdGhlIG9yZ2FuaXphdGlvblxuICAgIHZhciBtYXhIZWlnaHQgPSBOdW1iZXIuTUlOX1ZBTFVFO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcm93Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAocm93W2ldLmhlaWdodCA+IG1heEhlaWdodCkgbWF4SGVpZ2h0ID0gcm93W2ldLmhlaWdodDtcbiAgICB9XG4gICAgaWYgKGxvbmdlc3QgPiAwKSBtYXhIZWlnaHQgKz0gb3JnYW5pemF0aW9uLnZlcnRpY2FsUGFkZGluZztcblxuICAgIHZhciBwcmV2VG90YWwgPSBvcmdhbml6YXRpb24ucm93SGVpZ2h0W2xvbmdlc3RdICsgb3JnYW5pemF0aW9uLnJvd0hlaWdodFtsYXN0XTtcblxuICAgIG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbbG9uZ2VzdF0gPSBtYXhIZWlnaHQ7XG4gICAgaWYgKG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbbGFzdF0gPCBub2RlLmhlaWdodCArIG9yZ2FuaXphdGlvbi52ZXJ0aWNhbFBhZGRpbmcpIG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbbGFzdF0gPSBub2RlLmhlaWdodCArIG9yZ2FuaXphdGlvbi52ZXJ0aWNhbFBhZGRpbmc7XG5cbiAgICB2YXIgZmluYWxUb3RhbCA9IG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbbG9uZ2VzdF0gKyBvcmdhbml6YXRpb24ucm93SGVpZ2h0W2xhc3RdO1xuICAgIG9yZ2FuaXphdGlvbi5oZWlnaHQgKz0gZmluYWxUb3RhbCAtIHByZXZUb3RhbDtcblxuICAgIHRoaXMuc2hpZnRUb0xhc3RSb3cob3JnYW5pemF0aW9uKTtcbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUudGlsaW5nUHJlTGF5b3V0ID0gZnVuY3Rpb24gKCkge1xuICBpZiAoQ29TRUNvbnN0YW50cy5USUxFKSB7XG4gICAgLy8gRmluZCB6ZXJvIGRlZ3JlZSBub2RlcyBhbmQgY3JlYXRlIGEgY29tcG91bmQgZm9yIGVhY2ggbGV2ZWxcbiAgICB0aGlzLmdyb3VwWmVyb0RlZ3JlZU1lbWJlcnMoKTtcbiAgICAvLyBUaWxlIGFuZCBjbGVhciBjaGlsZHJlbiBvZiBlYWNoIGNvbXBvdW5kXG4gICAgdGhpcy5jbGVhckNvbXBvdW5kcygpO1xuICAgIC8vIFNlcGFyYXRlbHkgdGlsZSBhbmQgY2xlYXIgemVybyBkZWdyZWUgbm9kZXMgZm9yIGVhY2ggbGV2ZWxcbiAgICB0aGlzLmNsZWFyWmVyb0RlZ3JlZU1lbWJlcnMoKTtcbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUudGlsaW5nUG9zdExheW91dCA9IGZ1bmN0aW9uICgpIHtcbiAgaWYgKENvU0VDb25zdGFudHMuVElMRSkge1xuICAgIHRoaXMucmVwb3B1bGF0ZVplcm9EZWdyZWVNZW1iZXJzKCk7XG4gICAgdGhpcy5yZXBvcHVsYXRlQ29tcG91bmRzKCk7XG4gIH1cbn07XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBTZWN0aW9uOiBUcmVlIFJlZHVjdGlvbiBtZXRob2RzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gUmVkdWNlIHRyZWVzIFxuQ29TRUxheW91dC5wcm90b3R5cGUucmVkdWNlVHJlZXMgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBwcnVuZWROb2Rlc0FsbCA9IFtdO1xuICB2YXIgY29udGFpbnNMZWFmID0gdHJ1ZTtcbiAgdmFyIG5vZGU7XG5cbiAgd2hpbGUgKGNvbnRhaW5zTGVhZikge1xuICAgIHZhciBhbGxOb2RlcyA9IHRoaXMuZ3JhcGhNYW5hZ2VyLmdldEFsbE5vZGVzKCk7XG4gICAgdmFyIHBydW5lZE5vZGVzSW5TdGVwVGVtcCA9IFtdO1xuICAgIGNvbnRhaW5zTGVhZiA9IGZhbHNlO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhbGxOb2Rlcy5sZW5ndGg7IGkrKykge1xuICAgICAgbm9kZSA9IGFsbE5vZGVzW2ldO1xuICAgICAgaWYgKG5vZGUuZ2V0RWRnZXMoKS5sZW5ndGggPT0gMSAmJiAhbm9kZS5nZXRFZGdlcygpWzBdLmlzSW50ZXJHcmFwaCAmJiBub2RlLmdldENoaWxkKCkgPT0gbnVsbCkge1xuICAgICAgICBwcnVuZWROb2Rlc0luU3RlcFRlbXAucHVzaChbbm9kZSwgbm9kZS5nZXRFZGdlcygpWzBdLCBub2RlLmdldE93bmVyKCldKTtcbiAgICAgICAgY29udGFpbnNMZWFmID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGNvbnRhaW5zTGVhZiA9PSB0cnVlKSB7XG4gICAgICB2YXIgcHJ1bmVkTm9kZXNJblN0ZXAgPSBbXTtcbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgcHJ1bmVkTm9kZXNJblN0ZXBUZW1wLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIGlmIChwcnVuZWROb2Rlc0luU3RlcFRlbXBbal1bMF0uZ2V0RWRnZXMoKS5sZW5ndGggPT0gMSkge1xuICAgICAgICAgIHBydW5lZE5vZGVzSW5TdGVwLnB1c2gocHJ1bmVkTm9kZXNJblN0ZXBUZW1wW2pdKTtcbiAgICAgICAgICBwcnVuZWROb2Rlc0luU3RlcFRlbXBbal1bMF0uZ2V0T3duZXIoKS5yZW1vdmUocHJ1bmVkTm9kZXNJblN0ZXBUZW1wW2pdWzBdKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcHJ1bmVkTm9kZXNBbGwucHVzaChwcnVuZWROb2Rlc0luU3RlcCk7XG4gICAgICB0aGlzLmdyYXBoTWFuYWdlci5yZXNldEFsbE5vZGVzKCk7XG4gICAgICB0aGlzLmdyYXBoTWFuYWdlci5yZXNldEFsbEVkZ2VzKCk7XG4gICAgfVxuICB9XG4gIHRoaXMucHJ1bmVkTm9kZXNBbGwgPSBwcnVuZWROb2Rlc0FsbDtcbn07XG5cbi8vIEdyb3cgdHJlZSBvbmUgc3RlcCBcbkNvU0VMYXlvdXQucHJvdG90eXBlLmdyb3dUcmVlID0gZnVuY3Rpb24gKHBydW5lZE5vZGVzQWxsKSB7XG4gIHZhciBsZW5ndGhPZlBydW5lZE5vZGVzSW5TdGVwID0gcHJ1bmVkTm9kZXNBbGwubGVuZ3RoO1xuICB2YXIgcHJ1bmVkTm9kZXNJblN0ZXAgPSBwcnVuZWROb2Rlc0FsbFtsZW5ndGhPZlBydW5lZE5vZGVzSW5TdGVwIC0gMV07XG5cbiAgdmFyIG5vZGVEYXRhO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHBydW5lZE5vZGVzSW5TdGVwLmxlbmd0aDsgaSsrKSB7XG4gICAgbm9kZURhdGEgPSBwcnVuZWROb2Rlc0luU3RlcFtpXTtcblxuICAgIHRoaXMuZmluZFBsYWNlZm9yUHJ1bmVkTm9kZShub2RlRGF0YSk7XG5cbiAgICBub2RlRGF0YVsyXS5hZGQobm9kZURhdGFbMF0pO1xuICAgIG5vZGVEYXRhWzJdLmFkZChub2RlRGF0YVsxXSwgbm9kZURhdGFbMV0uc291cmNlLCBub2RlRGF0YVsxXS50YXJnZXQpO1xuICB9XG5cbiAgcHJ1bmVkTm9kZXNBbGwuc3BsaWNlKHBydW5lZE5vZGVzQWxsLmxlbmd0aCAtIDEsIDEpO1xuICB0aGlzLmdyYXBoTWFuYWdlci5yZXNldEFsbE5vZGVzKCk7XG4gIHRoaXMuZ3JhcGhNYW5hZ2VyLnJlc2V0QWxsRWRnZXMoKTtcbn07XG5cbi8vIEZpbmQgYW4gYXBwcm9wcmlhdGUgcG9zaXRpb24gdG8gcmVwbGFjZSBwcnVuZWQgbm9kZSwgdGhpcyBtZXRob2QgY2FuIGJlIGltcHJvdmVkXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5maW5kUGxhY2Vmb3JQcnVuZWROb2RlID0gZnVuY3Rpb24gKG5vZGVEYXRhKSB7XG5cbiAgdmFyIGdyaWRGb3JQcnVuZWROb2RlO1xuICB2YXIgbm9kZVRvQ29ubmVjdDtcbiAgdmFyIHBydW5lZE5vZGUgPSBub2RlRGF0YVswXTtcbiAgaWYgKHBydW5lZE5vZGUgPT0gbm9kZURhdGFbMV0uc291cmNlKSB7XG4gICAgbm9kZVRvQ29ubmVjdCA9IG5vZGVEYXRhWzFdLnRhcmdldDtcbiAgfSBlbHNlIHtcbiAgICBub2RlVG9Db25uZWN0ID0gbm9kZURhdGFbMV0uc291cmNlO1xuICB9XG4gIHZhciBzdGFydEdyaWRYID0gbm9kZVRvQ29ubmVjdC5zdGFydFg7XG4gIHZhciBmaW5pc2hHcmlkWCA9IG5vZGVUb0Nvbm5lY3QuZmluaXNoWDtcbiAgdmFyIHN0YXJ0R3JpZFkgPSBub2RlVG9Db25uZWN0LnN0YXJ0WTtcbiAgdmFyIGZpbmlzaEdyaWRZID0gbm9kZVRvQ29ubmVjdC5maW5pc2hZO1xuXG4gIHZhciB1cE5vZGVDb3VudCA9IDA7XG4gIHZhciBkb3duTm9kZUNvdW50ID0gMDtcbiAgdmFyIHJpZ2h0Tm9kZUNvdW50ID0gMDtcbiAgdmFyIGxlZnROb2RlQ291bnQgPSAwO1xuICB2YXIgY29udHJvbFJlZ2lvbnMgPSBbdXBOb2RlQ291bnQsIHJpZ2h0Tm9kZUNvdW50LCBkb3duTm9kZUNvdW50LCBsZWZ0Tm9kZUNvdW50XTtcblxuICBpZiAoc3RhcnRHcmlkWSA+IDApIHtcbiAgICBmb3IgKHZhciBpID0gc3RhcnRHcmlkWDsgaSA8PSBmaW5pc2hHcmlkWDsgaSsrKSB7XG4gICAgICBjb250cm9sUmVnaW9uc1swXSArPSB0aGlzLmdyaWRbaV1bc3RhcnRHcmlkWSAtIDFdLmxlbmd0aCArIHRoaXMuZ3JpZFtpXVtzdGFydEdyaWRZXS5sZW5ndGggLSAxO1xuICAgIH1cbiAgfVxuICBpZiAoZmluaXNoR3JpZFggPCB0aGlzLmdyaWQubGVuZ3RoIC0gMSkge1xuICAgIGZvciAodmFyIGkgPSBzdGFydEdyaWRZOyBpIDw9IGZpbmlzaEdyaWRZOyBpKyspIHtcbiAgICAgIGNvbnRyb2xSZWdpb25zWzFdICs9IHRoaXMuZ3JpZFtmaW5pc2hHcmlkWCArIDFdW2ldLmxlbmd0aCArIHRoaXMuZ3JpZFtmaW5pc2hHcmlkWF1baV0ubGVuZ3RoIC0gMTtcbiAgICB9XG4gIH1cbiAgaWYgKGZpbmlzaEdyaWRZIDwgdGhpcy5ncmlkWzBdLmxlbmd0aCAtIDEpIHtcbiAgICBmb3IgKHZhciBpID0gc3RhcnRHcmlkWDsgaSA8PSBmaW5pc2hHcmlkWDsgaSsrKSB7XG4gICAgICBjb250cm9sUmVnaW9uc1syXSArPSB0aGlzLmdyaWRbaV1bZmluaXNoR3JpZFkgKyAxXS5sZW5ndGggKyB0aGlzLmdyaWRbaV1bZmluaXNoR3JpZFldLmxlbmd0aCAtIDE7XG4gICAgfVxuICB9XG4gIGlmIChzdGFydEdyaWRYID4gMCkge1xuICAgIGZvciAodmFyIGkgPSBzdGFydEdyaWRZOyBpIDw9IGZpbmlzaEdyaWRZOyBpKyspIHtcbiAgICAgIGNvbnRyb2xSZWdpb25zWzNdICs9IHRoaXMuZ3JpZFtzdGFydEdyaWRYIC0gMV1baV0ubGVuZ3RoICsgdGhpcy5ncmlkW3N0YXJ0R3JpZFhdW2ldLmxlbmd0aCAtIDE7XG4gICAgfVxuICB9XG4gIHZhciBtaW4gPSBJbnRlZ2VyLk1BWF9WQUxVRTtcbiAgdmFyIG1pbkNvdW50O1xuICB2YXIgbWluSW5kZXg7XG4gIGZvciAodmFyIGogPSAwOyBqIDwgY29udHJvbFJlZ2lvbnMubGVuZ3RoOyBqKyspIHtcbiAgICBpZiAoY29udHJvbFJlZ2lvbnNbal0gPCBtaW4pIHtcbiAgICAgIG1pbiA9IGNvbnRyb2xSZWdpb25zW2pdO1xuICAgICAgbWluQ291bnQgPSAxO1xuICAgICAgbWluSW5kZXggPSBqO1xuICAgIH0gZWxzZSBpZiAoY29udHJvbFJlZ2lvbnNbal0gPT0gbWluKSB7XG4gICAgICBtaW5Db3VudCsrO1xuICAgIH1cbiAgfVxuXG4gIGlmIChtaW5Db3VudCA9PSAzICYmIG1pbiA9PSAwKSB7XG4gICAgaWYgKGNvbnRyb2xSZWdpb25zWzBdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbMV0gPT0gMCAmJiBjb250cm9sUmVnaW9uc1syXSA9PSAwKSB7XG4gICAgICBncmlkRm9yUHJ1bmVkTm9kZSA9IDE7XG4gICAgfSBlbHNlIGlmIChjb250cm9sUmVnaW9uc1swXSA9PSAwICYmIGNvbnRyb2xSZWdpb25zWzFdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbM10gPT0gMCkge1xuICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAwO1xuICAgIH0gZWxzZSBpZiAoY29udHJvbFJlZ2lvbnNbMF0gPT0gMCAmJiBjb250cm9sUmVnaW9uc1syXSA9PSAwICYmIGNvbnRyb2xSZWdpb25zWzNdID09IDApIHtcbiAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMztcbiAgICB9IGVsc2UgaWYgKGNvbnRyb2xSZWdpb25zWzFdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbMl0gPT0gMCAmJiBjb250cm9sUmVnaW9uc1szXSA9PSAwKSB7XG4gICAgICBncmlkRm9yUHJ1bmVkTm9kZSA9IDI7XG4gICAgfVxuICB9IGVsc2UgaWYgKG1pbkNvdW50ID09IDIgJiYgbWluID09IDApIHtcbiAgICB2YXIgcmFuZG9tID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMik7XG4gICAgaWYgKGNvbnRyb2xSZWdpb25zWzBdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbMV0gPT0gMCkge1xuICAgICAgO1xuICAgICAgaWYgKHJhbmRvbSA9PSAwKSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGNvbnRyb2xSZWdpb25zWzBdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbMl0gPT0gMCkge1xuICAgICAgaWYgKHJhbmRvbSA9PSAwKSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMjtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGNvbnRyb2xSZWdpb25zWzBdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbM10gPT0gMCkge1xuICAgICAgaWYgKHJhbmRvbSA9PSAwKSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMztcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGNvbnRyb2xSZWdpb25zWzFdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbMl0gPT0gMCkge1xuICAgICAgaWYgKHJhbmRvbSA9PSAwKSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMjtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGNvbnRyb2xSZWdpb25zWzFdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbM10gPT0gMCkge1xuICAgICAgaWYgKHJhbmRvbSA9PSAwKSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMztcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHJhbmRvbSA9PSAwKSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMztcbiAgICAgIH1cbiAgICB9XG4gIH0gZWxzZSBpZiAobWluQ291bnQgPT0gNCAmJiBtaW4gPT0gMCkge1xuICAgIHZhciByYW5kb20gPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiA0KTtcbiAgICBncmlkRm9yUHJ1bmVkTm9kZSA9IHJhbmRvbTtcbiAgfSBlbHNlIHtcbiAgICBncmlkRm9yUHJ1bmVkTm9kZSA9IG1pbkluZGV4O1xuICB9XG5cbiAgaWYgKGdyaWRGb3JQcnVuZWROb2RlID09IDApIHtcbiAgICBwcnVuZWROb2RlLnNldENlbnRlcihub2RlVG9Db25uZWN0LmdldENlbnRlclgoKSwgbm9kZVRvQ29ubmVjdC5nZXRDZW50ZXJZKCkgLSBub2RlVG9Db25uZWN0LmdldEhlaWdodCgpIC8gMiAtIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggLSBwcnVuZWROb2RlLmdldEhlaWdodCgpIC8gMik7XG4gIH0gZWxzZSBpZiAoZ3JpZEZvclBydW5lZE5vZGUgPT0gMSkge1xuICAgIHBydW5lZE5vZGUuc2V0Q2VudGVyKG5vZGVUb0Nvbm5lY3QuZ2V0Q2VudGVyWCgpICsgbm9kZVRvQ29ubmVjdC5nZXRXaWR0aCgpIC8gMiArIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggKyBwcnVuZWROb2RlLmdldFdpZHRoKCkgLyAyLCBub2RlVG9Db25uZWN0LmdldENlbnRlclkoKSk7XG4gIH0gZWxzZSBpZiAoZ3JpZEZvclBydW5lZE5vZGUgPT0gMikge1xuICAgIHBydW5lZE5vZGUuc2V0Q2VudGVyKG5vZGVUb0Nvbm5lY3QuZ2V0Q2VudGVyWCgpLCBub2RlVG9Db25uZWN0LmdldENlbnRlclkoKSArIG5vZGVUb0Nvbm5lY3QuZ2V0SGVpZ2h0KCkgLyAyICsgRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9FREdFX0xFTkdUSCArIHBydW5lZE5vZGUuZ2V0SGVpZ2h0KCkgLyAyKTtcbiAgfSBlbHNlIHtcbiAgICBwcnVuZWROb2RlLnNldENlbnRlcihub2RlVG9Db25uZWN0LmdldENlbnRlclgoKSAtIG5vZGVUb0Nvbm5lY3QuZ2V0V2lkdGgoKSAvIDIgLSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0VER0VfTEVOR1RIIC0gcHJ1bmVkTm9kZS5nZXRXaWR0aCgpIC8gMiwgbm9kZVRvQ29ubmVjdC5nZXRDZW50ZXJZKCkpO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IENvU0VMYXlvdXQ7XG5cbi8qKiovIH0pLFxuLyogNyAqL1xuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuXG5cInVzZSBzdHJpY3RcIjtcblxuXG52YXIgY29zZUJhc2UgPSB7fTtcblxuY29zZUJhc2UubGF5b3V0QmFzZSA9IF9fd2VicGFja19yZXF1aXJlX18oMCk7XG5jb3NlQmFzZS5Db1NFQ29uc3RhbnRzID0gX193ZWJwYWNrX3JlcXVpcmVfXygxKTtcbmNvc2VCYXNlLkNvU0VFZGdlID0gX193ZWJwYWNrX3JlcXVpcmVfXygyKTtcbmNvc2VCYXNlLkNvU0VHcmFwaCA9IF9fd2VicGFja19yZXF1aXJlX18oMyk7XG5jb3NlQmFzZS5Db1NFR3JhcGhNYW5hZ2VyID0gX193ZWJwYWNrX3JlcXVpcmVfXyg0KTtcbmNvc2VCYXNlLkNvU0VMYXlvdXQgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDYpO1xuY29zZUJhc2UuQ29TRU5vZGUgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNvc2VCYXNlO1xuXG4vKioqLyB9KVxuLyoqKioqKi8gXSk7XG59KTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../../node_modules/cose-base/cose-base.js\n");
+
+/***/ }),
+
+/***/ "../../../node_modules/cytoscape-cose-bilkent/cytoscape-cose-bilkent.js":
+/*!******************************************************************************!*\
+ !*** ../../../node_modules/cytoscape-cose-bilkent/cytoscape-cose-bilkent.js ***!
+ \******************************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+eval("(function webpackUniversalModuleDefinition(root, factory) {\n\tif(true)\n\t\tmodule.exports = factory(__webpack_require__(/*! cose-base */ \"../../../node_modules/cose-base/cose-base.js\"));\n\telse {}\n})(this, function(__WEBPACK_EXTERNAL_MODULE_0__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __nested_webpack_require_659__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __nested_webpack_require_659__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__nested_webpack_require_659__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__nested_webpack_require_659__.c = installedModules;\n/******/\n/******/ \t// identity function for calling harmony imports with the correct context\n/******/ \t__nested_webpack_require_659__.i = function(value) { return value; };\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__nested_webpack_require_659__.d = function(exports, name, getter) {\n/******/ \t\tif(!__nested_webpack_require_659__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__nested_webpack_require_659__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__nested_webpack_require_659__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__nested_webpack_require_659__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__nested_webpack_require_659__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __nested_webpack_require_659__(__nested_webpack_require_659__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE_0__;\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __nested_webpack_require_3201__) {\n\n\"use strict\";\n\n\nvar LayoutConstants = __nested_webpack_require_3201__(0).layoutBase.LayoutConstants;\nvar FDLayoutConstants = __nested_webpack_require_3201__(0).layoutBase.FDLayoutConstants;\nvar CoSEConstants = __nested_webpack_require_3201__(0).CoSEConstants;\nvar CoSELayout = __nested_webpack_require_3201__(0).CoSELayout;\nvar CoSENode = __nested_webpack_require_3201__(0).CoSENode;\nvar PointD = __nested_webpack_require_3201__(0).layoutBase.PointD;\nvar DimensionD = __nested_webpack_require_3201__(0).layoutBase.DimensionD;\n\nvar defaults = {\n // Called on `layoutready`\n ready: function ready() {},\n // Called on `layoutstop`\n stop: function stop() {},\n // 'draft', 'default' or 'proof\" \n // - 'draft' fast cooling rate \n // - 'default' moderate cooling rate \n // - \"proof\" slow cooling rate\n quality: 'default',\n // include labels in node dimensions\n nodeDimensionsIncludeLabels: false,\n // number of ticks per frame; higher is faster but more jerky\n refresh: 30,\n // Whether to fit the network view after when done\n fit: true,\n // Padding on fit\n padding: 10,\n // Whether to enable incremental mode\n randomize: true,\n // Node repulsion (non overlapping) multiplier\n nodeRepulsion: 4500,\n // Ideal edge (non nested) length\n idealEdgeLength: 50,\n // Divisor to compute edge forces\n edgeElasticity: 0.45,\n // Nesting factor (multiplier) to compute ideal edge length for nested edges\n nestingFactor: 0.1,\n // Gravity force (constant)\n gravity: 0.25,\n // Maximum number of iterations to perform\n numIter: 2500,\n // For enabling tiling\n tile: true,\n // Type of layout animation. The option set is {'during', 'end', false}\n animate: 'end',\n // Duration for animate:end\n animationDuration: 500,\n // Represents the amount of the vertical space to put between the zero degree members during the tiling operation(can also be a function)\n tilingPaddingVertical: 10,\n // Represents the amount of the horizontal space to put between the zero degree members during the tiling operation(can also be a function)\n tilingPaddingHorizontal: 10,\n // Gravity range (constant) for compounds\n gravityRangeCompound: 1.5,\n // Gravity force (constant) for compounds\n gravityCompound: 1.0,\n // Gravity range (constant)\n gravityRange: 3.8,\n // Initial cooling factor for incremental layout\n initialEnergyOnIncremental: 0.5\n};\n\nfunction extend(defaults, options) {\n var obj = {};\n\n for (var i in defaults) {\n obj[i] = defaults[i];\n }\n\n for (var i in options) {\n obj[i] = options[i];\n }\n\n return obj;\n};\n\nfunction _CoSELayout(_options) {\n this.options = extend(defaults, _options);\n getUserOptions(this.options);\n}\n\nvar getUserOptions = function getUserOptions(options) {\n if (options.nodeRepulsion != null) CoSEConstants.DEFAULT_REPULSION_STRENGTH = FDLayoutConstants.DEFAULT_REPULSION_STRENGTH = options.nodeRepulsion;\n if (options.idealEdgeLength != null) CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = options.idealEdgeLength;\n if (options.edgeElasticity != null) CoSEConstants.DEFAULT_SPRING_STRENGTH = FDLayoutConstants.DEFAULT_SPRING_STRENGTH = options.edgeElasticity;\n if (options.nestingFactor != null) CoSEConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = FDLayoutConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = options.nestingFactor;\n if (options.gravity != null) CoSEConstants.DEFAULT_GRAVITY_STRENGTH = FDLayoutConstants.DEFAULT_GRAVITY_STRENGTH = options.gravity;\n if (options.numIter != null) CoSEConstants.MAX_ITERATIONS = FDLayoutConstants.MAX_ITERATIONS = options.numIter;\n if (options.gravityRange != null) CoSEConstants.DEFAULT_GRAVITY_RANGE_FACTOR = FDLayoutConstants.DEFAULT_GRAVITY_RANGE_FACTOR = options.gravityRange;\n if (options.gravityCompound != null) CoSEConstants.DEFAULT_COMPOUND_GRAVITY_STRENGTH = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_STRENGTH = options.gravityCompound;\n if (options.gravityRangeCompound != null) CoSEConstants.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR = options.gravityRangeCompound;\n if (options.initialEnergyOnIncremental != null) CoSEConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL = options.initialEnergyOnIncremental;\n\n if (options.quality == 'draft') LayoutConstants.QUALITY = 0;else if (options.quality == 'proof') LayoutConstants.QUALITY = 2;else LayoutConstants.QUALITY = 1;\n\n CoSEConstants.NODE_DIMENSIONS_INCLUDE_LABELS = FDLayoutConstants.NODE_DIMENSIONS_INCLUDE_LABELS = LayoutConstants.NODE_DIMENSIONS_INCLUDE_LABELS = options.nodeDimensionsIncludeLabels;\n CoSEConstants.DEFAULT_INCREMENTAL = FDLayoutConstants.DEFAULT_INCREMENTAL = LayoutConstants.DEFAULT_INCREMENTAL = !options.randomize;\n CoSEConstants.ANIMATE = FDLayoutConstants.ANIMATE = LayoutConstants.ANIMATE = options.animate;\n CoSEConstants.TILE = options.tile;\n CoSEConstants.TILING_PADDING_VERTICAL = typeof options.tilingPaddingVertical === 'function' ? options.tilingPaddingVertical.call() : options.tilingPaddingVertical;\n CoSEConstants.TILING_PADDING_HORIZONTAL = typeof options.tilingPaddingHorizontal === 'function' ? options.tilingPaddingHorizontal.call() : options.tilingPaddingHorizontal;\n};\n\n_CoSELayout.prototype.run = function () {\n var ready;\n var frameId;\n var options = this.options;\n var idToLNode = this.idToLNode = {};\n var layout = this.layout = new CoSELayout();\n var self = this;\n\n self.stopped = false;\n\n this.cy = this.options.cy;\n\n this.cy.trigger({ type: 'layoutstart', layout: this });\n\n var gm = layout.newGraphManager();\n this.gm = gm;\n\n var nodes = this.options.eles.nodes();\n var edges = this.options.eles.edges();\n\n this.root = gm.addRoot();\n this.processChildrenList(this.root, this.getTopMostNodes(nodes), layout);\n\n for (var i = 0; i < edges.length; i++) {\n var edge = edges[i];\n var sourceNode = this.idToLNode[edge.data(\"source\")];\n var targetNode = this.idToLNode[edge.data(\"target\")];\n if (sourceNode !== targetNode && sourceNode.getEdgesBetween(targetNode).length == 0) {\n var e1 = gm.add(layout.newEdge(), sourceNode, targetNode);\n e1.id = edge.id();\n }\n }\n\n var getPositions = function getPositions(ele, i) {\n if (typeof ele === \"number\") {\n ele = i;\n }\n var theId = ele.data('id');\n var lNode = self.idToLNode[theId];\n\n return {\n x: lNode.getRect().getCenterX(),\n y: lNode.getRect().getCenterY()\n };\n };\n\n /*\n * Reposition nodes in iterations animatedly\n */\n var iterateAnimated = function iterateAnimated() {\n // Thigs to perform after nodes are repositioned on screen\n var afterReposition = function afterReposition() {\n if (options.fit) {\n options.cy.fit(options.eles, options.padding);\n }\n\n if (!ready) {\n ready = true;\n self.cy.one('layoutready', options.ready);\n self.cy.trigger({ type: 'layoutready', layout: self });\n }\n };\n\n var ticksPerFrame = self.options.refresh;\n var isDone;\n\n for (var i = 0; i < ticksPerFrame && !isDone; i++) {\n isDone = self.stopped || self.layout.tick();\n }\n\n // If layout is done\n if (isDone) {\n // If the layout is not a sublayout and it is successful perform post layout.\n if (layout.checkLayoutSuccess() && !layout.isSubLayout) {\n layout.doPostLayout();\n }\n\n // If layout has a tilingPostLayout function property call it.\n if (layout.tilingPostLayout) {\n layout.tilingPostLayout();\n }\n\n layout.isLayoutFinished = true;\n\n self.options.eles.nodes().positions(getPositions);\n\n afterReposition();\n\n // trigger layoutstop when the layout stops (e.g. finishes)\n self.cy.one('layoutstop', self.options.stop);\n self.cy.trigger({ type: 'layoutstop', layout: self });\n\n if (frameId) {\n cancelAnimationFrame(frameId);\n }\n\n ready = false;\n return;\n }\n\n var animationData = self.layout.getPositionsData(); // Get positions of layout nodes note that all nodes may not be layout nodes because of tiling\n\n // Position nodes, for the nodes whose id does not included in data (because they are removed from their parents and included in dummy compounds)\n // use position of their ancestors or dummy ancestors\n options.eles.nodes().positions(function (ele, i) {\n if (typeof ele === \"number\") {\n ele = i;\n }\n // If ele is a compound node, then its position will be defined by its children\n if (!ele.isParent()) {\n var theId = ele.id();\n var pNode = animationData[theId];\n var temp = ele;\n // If pNode is undefined search until finding position data of its first ancestor (It may be dummy as well)\n while (pNode == null) {\n pNode = animationData[temp.data('parent')] || animationData['DummyCompound_' + temp.data('parent')];\n animationData[theId] = pNode;\n temp = temp.parent()[0];\n if (temp == undefined) {\n break;\n }\n }\n if (pNode != null) {\n return {\n x: pNode.x,\n y: pNode.y\n };\n } else {\n return {\n x: ele.position('x'),\n y: ele.position('y')\n };\n }\n }\n });\n\n afterReposition();\n\n frameId = requestAnimationFrame(iterateAnimated);\n };\n\n /*\n * Listen 'layoutstarted' event and start animated iteration if animate option is 'during'\n */\n layout.addListener('layoutstarted', function () {\n if (self.options.animate === 'during') {\n frameId = requestAnimationFrame(iterateAnimated);\n }\n });\n\n layout.runLayout(); // Run cose layout\n\n /*\n * If animate option is not 'during' ('end' or false) perform these here (If it is 'during' similar things are already performed)\n */\n if (this.options.animate !== \"during\") {\n self.options.eles.nodes().not(\":parent\").layoutPositions(self, self.options, getPositions); // Use layout positions to reposition the nodes it considers the options parameter\n ready = false;\n }\n\n return this; // chaining\n};\n\n//Get the top most ones of a list of nodes\n_CoSELayout.prototype.getTopMostNodes = function (nodes) {\n var nodesMap = {};\n for (var i = 0; i < nodes.length; i++) {\n nodesMap[nodes[i].id()] = true;\n }\n var roots = nodes.filter(function (ele, i) {\n if (typeof ele === \"number\") {\n ele = i;\n }\n var parent = ele.parent()[0];\n while (parent != null) {\n if (nodesMap[parent.id()]) {\n return false;\n }\n parent = parent.parent()[0];\n }\n return true;\n });\n\n return roots;\n};\n\n_CoSELayout.prototype.processChildrenList = function (parent, children, layout) {\n var size = children.length;\n for (var i = 0; i < size; i++) {\n var theChild = children[i];\n var children_of_children = theChild.children();\n var theNode;\n\n var dimensions = theChild.layoutDimensions({\n nodeDimensionsIncludeLabels: this.options.nodeDimensionsIncludeLabels\n });\n\n if (theChild.outerWidth() != null && theChild.outerHeight() != null) {\n theNode = parent.add(new CoSENode(layout.graphManager, new PointD(theChild.position('x') - dimensions.w / 2, theChild.position('y') - dimensions.h / 2), new DimensionD(parseFloat(dimensions.w), parseFloat(dimensions.h))));\n } else {\n theNode = parent.add(new CoSENode(this.graphManager));\n }\n // Attach id to the layout node\n theNode.id = theChild.data(\"id\");\n // Attach the paddings of cy node to layout node\n theNode.paddingLeft = parseInt(theChild.css('padding'));\n theNode.paddingTop = parseInt(theChild.css('padding'));\n theNode.paddingRight = parseInt(theChild.css('padding'));\n theNode.paddingBottom = parseInt(theChild.css('padding'));\n\n //Attach the label properties to compound if labels will be included in node dimensions \n if (this.options.nodeDimensionsIncludeLabels) {\n if (theChild.isParent()) {\n var labelWidth = theChild.boundingBox({ includeLabels: true, includeNodes: false }).w;\n var labelHeight = theChild.boundingBox({ includeLabels: true, includeNodes: false }).h;\n var labelPos = theChild.css(\"text-halign\");\n theNode.labelWidth = labelWidth;\n theNode.labelHeight = labelHeight;\n theNode.labelPos = labelPos;\n }\n }\n\n // Map the layout node\n this.idToLNode[theChild.data(\"id\")] = theNode;\n\n if (isNaN(theNode.rect.x)) {\n theNode.rect.x = 0;\n }\n\n if (isNaN(theNode.rect.y)) {\n theNode.rect.y = 0;\n }\n\n if (children_of_children != null && children_of_children.length > 0) {\n var theNewGraph;\n theNewGraph = layout.getGraphManager().add(layout.newGraph(), theNode);\n this.processChildrenList(theNewGraph, children_of_children, layout);\n }\n }\n};\n\n/**\n * @brief : called on continuous layouts to stop them before they finish\n */\n_CoSELayout.prototype.stop = function () {\n this.stopped = true;\n\n return this; // chaining\n};\n\nvar register = function register(cytoscape) {\n // var Layout = getLayout( cytoscape );\n\n cytoscape('layout', 'cose-bilkent', _CoSELayout);\n};\n\n// auto reg for globals\nif (typeof cytoscape !== 'undefined') {\n register(cytoscape);\n}\n\nmodule.exports = register;\n\n/***/ })\n/******/ ]);\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2N5dG9zY2FwZS1jb3NlLWJpbGtlbnQvY3l0b3NjYXBlLWNvc2UtYmlsa2VudC5qcy5qcyIsIm1hcHBpbmdzIjoiQUFBQTtBQUNBLElBQUksSUFBeUQ7QUFDN0QsMkJBQTJCLG1CQUFPLENBQUMsK0RBQVc7QUFDOUMsTUFBTSxFQUtxRDtBQUMzRCxDQUFDO0FBQ0QscUNBQXFDO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLDhCQUFtQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBFQUEwRSw4QkFBbUI7QUFDN0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLDhCQUFtQjtBQUM3QjtBQUNBO0FBQ0EsVUFBVSw4QkFBbUI7QUFDN0I7QUFDQTtBQUNBLFVBQVUsOEJBQW1CLHVCQUF1QjtBQUNwRDtBQUNBO0FBQ0EsVUFBVSw4QkFBbUI7QUFDN0IsZUFBZSw4QkFBbUI7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLDhCQUFtQjtBQUM3QjtBQUNBLG9DQUFvQyw0QkFBNEI7QUFDaEUsMENBQTBDO0FBQzFDLFdBQVcsOEJBQW1CO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSw4QkFBbUIsa0NBQWtDO0FBQy9EO0FBQ0E7QUFDQSxVQUFVLDhCQUFtQjtBQUM3QjtBQUNBO0FBQ0EsaUJBQWlCLDhCQUFtQixDQUFDLDhCQUFtQjtBQUN4RCxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsT0FBTztBQUNQO0FBQ0EsaUNBQWlDLCtCQUFtQjs7QUFFcEQ7OztBQUdBLHNCQUFzQiwrQkFBbUI7QUFDekMsd0JBQXdCLCtCQUFtQjtBQUMzQyxvQkFBb0IsK0JBQW1CO0FBQ3ZDLGlCQUFpQiwrQkFBbUI7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QSxlQUFlO0FBQ2Y7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLE9BQU87QUFDUDtBQUNBLENBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2N5dG9zY2FwZS1jb3NlLWJpbGtlbnQvY3l0b3NjYXBlLWNvc2UtYmlsa2VudC5qcz9lNWRiIl0sInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiB3ZWJwYWNrVW5pdmVyc2FsTW9kdWxlRGVmaW5pdGlvbihyb290LCBmYWN0b3J5KSB7XG5cdGlmKHR5cGVvZiBleHBvcnRzID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgbW9kdWxlID09PSAnb2JqZWN0Jylcblx0XHRtb2R1bGUuZXhwb3J0cyA9IGZhY3RvcnkocmVxdWlyZShcImNvc2UtYmFzZVwiKSk7XG5cdGVsc2UgaWYodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKVxuXHRcdGRlZmluZShbXCJjb3NlLWJhc2VcIl0sIGZhY3RvcnkpO1xuXHRlbHNlIGlmKHR5cGVvZiBleHBvcnRzID09PSAnb2JqZWN0Jylcblx0XHRleHBvcnRzW1wiY3l0b3NjYXBlQ29zZUJpbGtlbnRcIl0gPSBmYWN0b3J5KHJlcXVpcmUoXCJjb3NlLWJhc2VcIikpO1xuXHRlbHNlXG5cdFx0cm9vdFtcImN5dG9zY2FwZUNvc2VCaWxrZW50XCJdID0gZmFjdG9yeShyb290W1wiY29zZUJhc2VcIl0pO1xufSkodGhpcywgZnVuY3Rpb24oX19XRUJQQUNLX0VYVEVSTkFMX01PRFVMRV8wX18pIHtcbnJldHVybiAvKioqKioqLyAoZnVuY3Rpb24obW9kdWxlcykgeyAvLyB3ZWJwYWNrQm9vdHN0cmFwXG4vKioqKioqLyBcdC8vIFRoZSBtb2R1bGUgY2FjaGVcbi8qKioqKiovIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcbi8qKioqKiovXG4vKioqKioqLyBcdC8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG4vKioqKioqLyBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcbi8qKioqKiovXG4vKioqKioqLyBcdFx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG4vKioqKioqLyBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbi8qKioqKiovIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuLyoqKioqKi8gXHRcdH1cbi8qKioqKiovIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuLyoqKioqKi8gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbi8qKioqKiovIFx0XHRcdGk6IG1vZHVsZUlkLFxuLyoqKioqKi8gXHRcdFx0bDogZmFsc2UsXG4vKioqKioqLyBcdFx0XHRleHBvcnRzOiB7fVxuLyoqKioqKi8gXHRcdH07XG4vKioqKioqL1xuLyoqKioqKi8gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuLyoqKioqKi8gXHRcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuLyoqKioqKi9cbi8qKioqKiovIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4vKioqKioqLyBcdFx0bW9kdWxlLmwgPSB0cnVlO1xuLyoqKioqKi9cbi8qKioqKiovIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuLyoqKioqKi8gXHRcdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbi8qKioqKiovIFx0fVxuLyoqKioqKi9cbi8qKioqKiovXG4vKioqKioqLyBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4vKioqKioqLyBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG4vKioqKioqL1xuLyoqKioqKi8gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuLyoqKioqKi8gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuLyoqKioqKi9cbi8qKioqKiovIFx0Ly8gaWRlbnRpdHkgZnVuY3Rpb24gZm9yIGNhbGxpbmcgaGFybW9ueSBpbXBvcnRzIHdpdGggdGhlIGNvcnJlY3QgY29udGV4dFxuLyoqKioqKi8gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmkgPSBmdW5jdGlvbih2YWx1ZSkgeyByZXR1cm4gdmFsdWU7IH07XG4vKioqKioqL1xuLyoqKioqKi8gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbi8qKioqKiovIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kID0gZnVuY3Rpb24oZXhwb3J0cywgbmFtZSwgZ2V0dGVyKSB7XG4vKioqKioqLyBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuLyoqKioqKi8gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHtcbi8qKioqKiovIFx0XHRcdFx0Y29uZmlndXJhYmxlOiBmYWxzZSxcbi8qKioqKiovIFx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcbi8qKioqKiovIFx0XHRcdFx0Z2V0OiBnZXR0ZXJcbi8qKioqKiovIFx0XHRcdH0pO1xuLyoqKioqKi8gXHRcdH1cbi8qKioqKiovIFx0fTtcbi8qKioqKiovXG4vKioqKioqLyBcdC8vIGdldERlZmF1bHRFeHBvcnQgZnVuY3Rpb24gZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBub24taGFybW9ueSBtb2R1bGVzXG4vKioqKioqLyBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuLyoqKioqKi8gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuLyoqKioqKi8gXHRcdFx0ZnVuY3Rpb24gZ2V0RGVmYXVsdCgpIHsgcmV0dXJuIG1vZHVsZVsnZGVmYXVsdCddOyB9IDpcbi8qKioqKiovIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4vKioqKioqLyBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuLyoqKioqKi8gXHRcdHJldHVybiBnZXR0ZXI7XG4vKioqKioqLyBcdH07XG4vKioqKioqL1xuLyoqKioqKi8gXHQvLyBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGxcbi8qKioqKiovIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuLyoqKioqKi9cbi8qKioqKiovIFx0Ly8gX193ZWJwYWNrX3B1YmxpY19wYXRoX19cbi8qKioqKiovIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcbi8qKioqKiovXG4vKioqKioqLyBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuLyoqKioqKi8gXHRyZXR1cm4gX193ZWJwYWNrX3JlcXVpcmVfXyhfX3dlYnBhY2tfcmVxdWlyZV9fLnMgPSAxKTtcbi8qKioqKiovIH0pXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuLyoqKioqKi8gKFtcbi8qIDAgKi9cbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMpIHtcblxubW9kdWxlLmV4cG9ydHMgPSBfX1dFQlBBQ0tfRVhURVJOQUxfTU9EVUxFXzBfXztcblxuLyoqKi8gfSksXG4vKiAxICovXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG5cblwidXNlIHN0cmljdFwiO1xuXG5cbnZhciBMYXlvdXRDb25zdGFudHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApLmxheW91dEJhc2UuTGF5b3V0Q29uc3RhbnRzO1xudmFyIEZETGF5b3V0Q29uc3RhbnRzID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5sYXlvdXRCYXNlLkZETGF5b3V0Q29uc3RhbnRzO1xudmFyIENvU0VDb25zdGFudHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApLkNvU0VDb25zdGFudHM7XG52YXIgQ29TRUxheW91dCA9IF9fd2VicGFja19yZXF1aXJlX18oMCkuQ29TRUxheW91dDtcbnZhciBDb1NFTm9kZSA9IF9fd2VicGFja19yZXF1aXJlX18oMCkuQ29TRU5vZGU7XG52YXIgUG9pbnREID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5sYXlvdXRCYXNlLlBvaW50RDtcbnZhciBEaW1lbnNpb25EID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKS5sYXlvdXRCYXNlLkRpbWVuc2lvbkQ7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgLy8gQ2FsbGVkIG9uIGBsYXlvdXRyZWFkeWBcbiAgcmVhZHk6IGZ1bmN0aW9uIHJlYWR5KCkge30sXG4gIC8vIENhbGxlZCBvbiBgbGF5b3V0c3RvcGBcbiAgc3RvcDogZnVuY3Rpb24gc3RvcCgpIHt9LFxuICAvLyAnZHJhZnQnLCAnZGVmYXVsdCcgb3IgJ3Byb29mXCIgXG4gIC8vIC0gJ2RyYWZ0JyBmYXN0IGNvb2xpbmcgcmF0ZSBcbiAgLy8gLSAnZGVmYXVsdCcgbW9kZXJhdGUgY29vbGluZyByYXRlIFxuICAvLyAtIFwicHJvb2ZcIiBzbG93IGNvb2xpbmcgcmF0ZVxuICBxdWFsaXR5OiAnZGVmYXVsdCcsXG4gIC8vIGluY2x1ZGUgbGFiZWxzIGluIG5vZGUgZGltZW5zaW9uc1xuICBub2RlRGltZW5zaW9uc0luY2x1ZGVMYWJlbHM6IGZhbHNlLFxuICAvLyBudW1iZXIgb2YgdGlja3MgcGVyIGZyYW1lOyBoaWdoZXIgaXMgZmFzdGVyIGJ1dCBtb3JlIGplcmt5XG4gIHJlZnJlc2g6IDMwLFxuICAvLyBXaGV0aGVyIHRvIGZpdCB0aGUgbmV0d29yayB2aWV3IGFmdGVyIHdoZW4gZG9uZVxuICBmaXQ6IHRydWUsXG4gIC8vIFBhZGRpbmcgb24gZml0XG4gIHBhZGRpbmc6IDEwLFxuICAvLyBXaGV0aGVyIHRvIGVuYWJsZSBpbmNyZW1lbnRhbCBtb2RlXG4gIHJhbmRvbWl6ZTogdHJ1ZSxcbiAgLy8gTm9kZSByZXB1bHNpb24gKG5vbiBvdmVybGFwcGluZykgbXVsdGlwbGllclxuICBub2RlUmVwdWxzaW9uOiA0NTAwLFxuICAvLyBJZGVhbCBlZGdlIChub24gbmVzdGVkKSBsZW5ndGhcbiAgaWRlYWxFZGdlTGVuZ3RoOiA1MCxcbiAgLy8gRGl2aXNvciB0byBjb21wdXRlIGVkZ2UgZm9yY2VzXG4gIGVkZ2VFbGFzdGljaXR5OiAwLjQ1LFxuICAvLyBOZXN0aW5nIGZhY3RvciAobXVsdGlwbGllcikgdG8gY29tcHV0ZSBpZGVhbCBlZGdlIGxlbmd0aCBmb3IgbmVzdGVkIGVkZ2VzXG4gIG5lc3RpbmdGYWN0b3I6IDAuMSxcbiAgLy8gR3Jhdml0eSBmb3JjZSAoY29uc3RhbnQpXG4gIGdyYXZpdHk6IDAuMjUsXG4gIC8vIE1heGltdW0gbnVtYmVyIG9mIGl0ZXJhdGlvbnMgdG8gcGVyZm9ybVxuICBudW1JdGVyOiAyNTAwLFxuICAvLyBGb3IgZW5hYmxpbmcgdGlsaW5nXG4gIHRpbGU6IHRydWUsXG4gIC8vIFR5cGUgb2YgbGF5b3V0IGFuaW1hdGlvbi4gVGhlIG9wdGlvbiBzZXQgaXMgeydkdXJpbmcnLCAnZW5kJywgZmFsc2V9XG4gIGFuaW1hdGU6ICdlbmQnLFxuICAvLyBEdXJhdGlvbiBmb3IgYW5pbWF0ZTplbmRcbiAgYW5pbWF0aW9uRHVyYXRpb246IDUwMCxcbiAgLy8gUmVwcmVzZW50cyB0aGUgYW1vdW50IG9mIHRoZSB2ZXJ0aWNhbCBzcGFjZSB0byBwdXQgYmV0d2VlbiB0aGUgemVybyBkZWdyZWUgbWVtYmVycyBkdXJpbmcgdGhlIHRpbGluZyBvcGVyYXRpb24oY2FuIGFsc28gYmUgYSBmdW5jdGlvbilcbiAgdGlsaW5nUGFkZGluZ1ZlcnRpY2FsOiAxMCxcbiAgLy8gUmVwcmVzZW50cyB0aGUgYW1vdW50IG9mIHRoZSBob3Jpem9udGFsIHNwYWNlIHRvIHB1dCBiZXR3ZWVuIHRoZSB6ZXJvIGRlZ3JlZSBtZW1iZXJzIGR1cmluZyB0aGUgdGlsaW5nIG9wZXJhdGlvbihjYW4gYWxzbyBiZSBhIGZ1bmN0aW9uKVxuICB0aWxpbmdQYWRkaW5nSG9yaXpvbnRhbDogMTAsXG4gIC8vIEdyYXZpdHkgcmFuZ2UgKGNvbnN0YW50KSBmb3IgY29tcG91bmRzXG4gIGdyYXZpdHlSYW5nZUNvbXBvdW5kOiAxLjUsXG4gIC8vIEdyYXZpdHkgZm9yY2UgKGNvbnN0YW50KSBmb3IgY29tcG91bmRzXG4gIGdyYXZpdHlDb21wb3VuZDogMS4wLFxuICAvLyBHcmF2aXR5IHJhbmdlIChjb25zdGFudClcbiAgZ3Jhdml0eVJhbmdlOiAzLjgsXG4gIC8vIEluaXRpYWwgY29vbGluZyBmYWN0b3IgZm9yIGluY3JlbWVudGFsIGxheW91dFxuICBpbml0aWFsRW5lcmd5T25JbmNyZW1lbnRhbDogMC41XG59O1xuXG5mdW5jdGlvbiBleHRlbmQoZGVmYXVsdHMsIG9wdGlvbnMpIHtcbiAgdmFyIG9iaiA9IHt9O1xuXG4gIGZvciAodmFyIGkgaW4gZGVmYXVsdHMpIHtcbiAgICBvYmpbaV0gPSBkZWZhdWx0c1tpXTtcbiAgfVxuXG4gIGZvciAodmFyIGkgaW4gb3B0aW9ucykge1xuICAgIG9ialtpXSA9IG9wdGlvbnNbaV07XG4gIH1cblxuICByZXR1cm4gb2JqO1xufTtcblxuZnVuY3Rpb24gX0NvU0VMYXlvdXQoX29wdGlvbnMpIHtcbiAgdGhpcy5vcHRpb25zID0gZXh0ZW5kKGRlZmF1bHRzLCBfb3B0aW9ucyk7XG4gIGdldFVzZXJPcHRpb25zKHRoaXMub3B0aW9ucyk7XG59XG5cbnZhciBnZXRVc2VyT3B0aW9ucyA9IGZ1bmN0aW9uIGdldFVzZXJPcHRpb25zKG9wdGlvbnMpIHtcbiAgaWYgKG9wdGlvbnMubm9kZVJlcHVsc2lvbiAhPSBudWxsKSBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfUkVQVUxTSU9OX1NUUkVOR1RIID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9SRVBVTFNJT05fU1RSRU5HVEggPSBvcHRpb25zLm5vZGVSZXB1bHNpb247XG4gIGlmIChvcHRpb25zLmlkZWFsRWRnZUxlbmd0aCAhPSBudWxsKSBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0VER0VfTEVOR1RIID0gb3B0aW9ucy5pZGVhbEVkZ2VMZW5ndGg7XG4gIGlmIChvcHRpb25zLmVkZ2VFbGFzdGljaXR5ICE9IG51bGwpIENvU0VDb25zdGFudHMuREVGQVVMVF9TUFJJTkdfU1RSRU5HVEggPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX1NQUklOR19TVFJFTkdUSCA9IG9wdGlvbnMuZWRnZUVsYXN0aWNpdHk7XG4gIGlmIChvcHRpb25zLm5lc3RpbmdGYWN0b3IgIT0gbnVsbCkgQ29TRUNvbnN0YW50cy5QRVJfTEVWRUxfSURFQUxfRURHRV9MRU5HVEhfRkFDVE9SID0gRkRMYXlvdXRDb25zdGFudHMuUEVSX0xFVkVMX0lERUFMX0VER0VfTEVOR1RIX0ZBQ1RPUiA9IG9wdGlvbnMubmVzdGluZ0ZhY3RvcjtcbiAgaWYgKG9wdGlvbnMuZ3Jhdml0eSAhPSBudWxsKSBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfR1JBVklUWV9TVFJFTkdUSCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfR1JBVklUWV9TVFJFTkdUSCA9IG9wdGlvbnMuZ3Jhdml0eTtcbiAgaWYgKG9wdGlvbnMubnVtSXRlciAhPSBudWxsKSBDb1NFQ29uc3RhbnRzLk1BWF9JVEVSQVRJT05TID0gRkRMYXlvdXRDb25zdGFudHMuTUFYX0lURVJBVElPTlMgPSBvcHRpb25zLm51bUl0ZXI7XG4gIGlmIChvcHRpb25zLmdyYXZpdHlSYW5nZSAhPSBudWxsKSBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfR1JBVklUWV9SQU5HRV9GQUNUT1IgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0dSQVZJVFlfUkFOR0VfRkFDVE9SID0gb3B0aW9ucy5ncmF2aXR5UmFuZ2U7XG4gIGlmIChvcHRpb25zLmdyYXZpdHlDb21wb3VuZCAhPSBudWxsKSBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfQ09NUE9VTkRfR1JBVklUWV9TVFJFTkdUSCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09NUE9VTkRfR1JBVklUWV9TVFJFTkdUSCA9IG9wdGlvbnMuZ3Jhdml0eUNvbXBvdW5kO1xuICBpZiAob3B0aW9ucy5ncmF2aXR5UmFuZ2VDb21wb3VuZCAhPSBudWxsKSBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfQ09NUE9VTkRfR1JBVklUWV9SQU5HRV9GQUNUT1IgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0NPTVBPVU5EX0dSQVZJVFlfUkFOR0VfRkFDVE9SID0gb3B0aW9ucy5ncmF2aXR5UmFuZ2VDb21wb3VuZDtcbiAgaWYgKG9wdGlvbnMuaW5pdGlhbEVuZXJneU9uSW5jcmVtZW50YWwgIT0gbnVsbCkgQ29TRUNvbnN0YW50cy5ERUZBVUxUX0NPT0xJTkdfRkFDVE9SX0lOQ1JFTUVOVEFMID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9DT09MSU5HX0ZBQ1RPUl9JTkNSRU1FTlRBTCA9IG9wdGlvbnMuaW5pdGlhbEVuZXJneU9uSW5jcmVtZW50YWw7XG5cbiAgaWYgKG9wdGlvbnMucXVhbGl0eSA9PSAnZHJhZnQnKSBMYXlvdXRDb25zdGFudHMuUVVBTElUWSA9IDA7ZWxzZSBpZiAob3B0aW9ucy5xdWFsaXR5ID09ICdwcm9vZicpIExheW91dENvbnN0YW50cy5RVUFMSVRZID0gMjtlbHNlIExheW91dENvbnN0YW50cy5RVUFMSVRZID0gMTtcblxuICBDb1NFQ29uc3RhbnRzLk5PREVfRElNRU5TSU9OU19JTkNMVURFX0xBQkVMUyA9IEZETGF5b3V0Q29uc3RhbnRzLk5PREVfRElNRU5TSU9OU19JTkNMVURFX0xBQkVMUyA9IExheW91dENvbnN0YW50cy5OT0RFX0RJTUVOU0lPTlNfSU5DTFVERV9MQUJFTFMgPSBvcHRpb25zLm5vZGVEaW1lbnNpb25zSW5jbHVkZUxhYmVscztcbiAgQ29TRUNvbnN0YW50cy5ERUZBVUxUX0lOQ1JFTUVOVEFMID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9JTkNSRU1FTlRBTCA9IExheW91dENvbnN0YW50cy5ERUZBVUxUX0lOQ1JFTUVOVEFMID0gIW9wdGlvbnMucmFuZG9taXplO1xuICBDb1NFQ29uc3RhbnRzLkFOSU1BVEUgPSBGRExheW91dENvbnN0YW50cy5BTklNQVRFID0gTGF5b3V0Q29uc3RhbnRzLkFOSU1BVEUgPSBvcHRpb25zLmFuaW1hdGU7XG4gIENvU0VDb25zdGFudHMuVElMRSA9IG9wdGlvbnMudGlsZTtcbiAgQ29TRUNvbnN0YW50cy5USUxJTkdfUEFERElOR19WRVJUSUNBTCA9IHR5cGVvZiBvcHRpb25zLnRpbGluZ1BhZGRpbmdWZXJ0aWNhbCA9PT0gJ2Z1bmN0aW9uJyA/IG9wdGlvbnMudGlsaW5nUGFkZGluZ1ZlcnRpY2FsLmNhbGwoKSA6IG9wdGlvbnMudGlsaW5nUGFkZGluZ1ZlcnRpY2FsO1xuICBDb1NFQ29uc3RhbnRzLlRJTElOR19QQURESU5HX0hPUklaT05UQUwgPSB0eXBlb2Ygb3B0aW9ucy50aWxpbmdQYWRkaW5nSG9yaXpvbnRhbCA9PT0gJ2Z1bmN0aW9uJyA/IG9wdGlvbnMudGlsaW5nUGFkZGluZ0hvcml6b250YWwuY2FsbCgpIDogb3B0aW9ucy50aWxpbmdQYWRkaW5nSG9yaXpvbnRhbDtcbn07XG5cbl9Db1NFTGF5b3V0LnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbiAoKSB7XG4gIHZhciByZWFkeTtcbiAgdmFyIGZyYW1lSWQ7XG4gIHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuICB2YXIgaWRUb0xOb2RlID0gdGhpcy5pZFRvTE5vZGUgPSB7fTtcbiAgdmFyIGxheW91dCA9IHRoaXMubGF5b3V0ID0gbmV3IENvU0VMYXlvdXQoKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gIHNlbGYuc3RvcHBlZCA9IGZhbHNlO1xuXG4gIHRoaXMuY3kgPSB0aGlzLm9wdGlvbnMuY3k7XG5cbiAgdGhpcy5jeS50cmlnZ2VyKHsgdHlwZTogJ2xheW91dHN0YXJ0JywgbGF5b3V0OiB0aGlzIH0pO1xuXG4gIHZhciBnbSA9IGxheW91dC5uZXdHcmFwaE1hbmFnZXIoKTtcbiAgdGhpcy5nbSA9IGdtO1xuXG4gIHZhciBub2RlcyA9IHRoaXMub3B0aW9ucy5lbGVzLm5vZGVzKCk7XG4gIHZhciBlZGdlcyA9IHRoaXMub3B0aW9ucy5lbGVzLmVkZ2VzKCk7XG5cbiAgdGhpcy5yb290ID0gZ20uYWRkUm9vdCgpO1xuICB0aGlzLnByb2Nlc3NDaGlsZHJlbkxpc3QodGhpcy5yb290LCB0aGlzLmdldFRvcE1vc3ROb2Rlcyhub2RlcyksIGxheW91dCk7XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBlZGdlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBlZGdlID0gZWRnZXNbaV07XG4gICAgdmFyIHNvdXJjZU5vZGUgPSB0aGlzLmlkVG9MTm9kZVtlZGdlLmRhdGEoXCJzb3VyY2VcIildO1xuICAgIHZhciB0YXJnZXROb2RlID0gdGhpcy5pZFRvTE5vZGVbZWRnZS5kYXRhKFwidGFyZ2V0XCIpXTtcbiAgICBpZiAoc291cmNlTm9kZSAhPT0gdGFyZ2V0Tm9kZSAmJiBzb3VyY2VOb2RlLmdldEVkZ2VzQmV0d2Vlbih0YXJnZXROb2RlKS5sZW5ndGggPT0gMCkge1xuICAgICAgdmFyIGUxID0gZ20uYWRkKGxheW91dC5uZXdFZGdlKCksIHNvdXJjZU5vZGUsIHRhcmdldE5vZGUpO1xuICAgICAgZTEuaWQgPSBlZGdlLmlkKCk7XG4gICAgfVxuICB9XG5cbiAgdmFyIGdldFBvc2l0aW9ucyA9IGZ1bmN0aW9uIGdldFBvc2l0aW9ucyhlbGUsIGkpIHtcbiAgICBpZiAodHlwZW9mIGVsZSA9PT0gXCJudW1iZXJcIikge1xuICAgICAgZWxlID0gaTtcbiAgICB9XG4gICAgdmFyIHRoZUlkID0gZWxlLmRhdGEoJ2lkJyk7XG4gICAgdmFyIGxOb2RlID0gc2VsZi5pZFRvTE5vZGVbdGhlSWRdO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHg6IGxOb2RlLmdldFJlY3QoKS5nZXRDZW50ZXJYKCksXG4gICAgICB5OiBsTm9kZS5nZXRSZWN0KCkuZ2V0Q2VudGVyWSgpXG4gICAgfTtcbiAgfTtcblxuICAvKlxuICAgKiBSZXBvc2l0aW9uIG5vZGVzIGluIGl0ZXJhdGlvbnMgYW5pbWF0ZWRseVxuICAgKi9cbiAgdmFyIGl0ZXJhdGVBbmltYXRlZCA9IGZ1bmN0aW9uIGl0ZXJhdGVBbmltYXRlZCgpIHtcbiAgICAvLyBUaGlncyB0byBwZXJmb3JtIGFmdGVyIG5vZGVzIGFyZSByZXBvc2l0aW9uZWQgb24gc2NyZWVuXG4gICAgdmFyIGFmdGVyUmVwb3NpdGlvbiA9IGZ1bmN0aW9uIGFmdGVyUmVwb3NpdGlvbigpIHtcbiAgICAgIGlmIChvcHRpb25zLmZpdCkge1xuICAgICAgICBvcHRpb25zLmN5LmZpdChvcHRpb25zLmVsZXMsIG9wdGlvbnMucGFkZGluZyk7XG4gICAgICB9XG5cbiAgICAgIGlmICghcmVhZHkpIHtcbiAgICAgICAgcmVhZHkgPSB0cnVlO1xuICAgICAgICBzZWxmLmN5Lm9uZSgnbGF5b3V0cmVhZHknLCBvcHRpb25zLnJlYWR5KTtcbiAgICAgICAgc2VsZi5jeS50cmlnZ2VyKHsgdHlwZTogJ2xheW91dHJlYWR5JywgbGF5b3V0OiBzZWxmIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdGlja3NQZXJGcmFtZSA9IHNlbGYub3B0aW9ucy5yZWZyZXNoO1xuICAgIHZhciBpc0RvbmU7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRpY2tzUGVyRnJhbWUgJiYgIWlzRG9uZTsgaSsrKSB7XG4gICAgICBpc0RvbmUgPSBzZWxmLnN0b3BwZWQgfHwgc2VsZi5sYXlvdXQudGljaygpO1xuICAgIH1cblxuICAgIC8vIElmIGxheW91dCBpcyBkb25lXG4gICAgaWYgKGlzRG9uZSkge1xuICAgICAgLy8gSWYgdGhlIGxheW91dCBpcyBub3QgYSBzdWJsYXlvdXQgYW5kIGl0IGlzIHN1Y2Nlc3NmdWwgcGVyZm9ybSBwb3N0IGxheW91dC5cbiAgICAgIGlmIChsYXlvdXQuY2hlY2tMYXlvdXRTdWNjZXNzKCkgJiYgIWxheW91dC5pc1N1YkxheW91dCkge1xuICAgICAgICBsYXlvdXQuZG9Qb3N0TGF5b3V0KCk7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIGxheW91dCBoYXMgYSB0aWxpbmdQb3N0TGF5b3V0IGZ1bmN0aW9uIHByb3BlcnR5IGNhbGwgaXQuXG4gICAgICBpZiAobGF5b3V0LnRpbGluZ1Bvc3RMYXlvdXQpIHtcbiAgICAgICAgbGF5b3V0LnRpbGluZ1Bvc3RMYXlvdXQoKTtcbiAgICAgIH1cblxuICAgICAgbGF5b3V0LmlzTGF5b3V0RmluaXNoZWQgPSB0cnVlO1xuXG4gICAgICBzZWxmLm9wdGlvbnMuZWxlcy5ub2RlcygpLnBvc2l0aW9ucyhnZXRQb3NpdGlvbnMpO1xuXG4gICAgICBhZnRlclJlcG9zaXRpb24oKTtcblxuICAgICAgLy8gdHJpZ2dlciBsYXlvdXRzdG9wIHdoZW4gdGhlIGxheW91dCBzdG9wcyAoZS5nLiBmaW5pc2hlcylcbiAgICAgIHNlbGYuY3kub25lKCdsYXlvdXRzdG9wJywgc2VsZi5vcHRpb25zLnN0b3ApO1xuICAgICAgc2VsZi5jeS50cmlnZ2VyKHsgdHlwZTogJ2xheW91dHN0b3AnLCBsYXlvdXQ6IHNlbGYgfSk7XG5cbiAgICAgIGlmIChmcmFtZUlkKSB7XG4gICAgICAgIGNhbmNlbEFuaW1hdGlvbkZyYW1lKGZyYW1lSWQpO1xuICAgICAgfVxuXG4gICAgICByZWFkeSA9IGZhbHNlO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBhbmltYXRpb25EYXRhID0gc2VsZi5sYXlvdXQuZ2V0UG9zaXRpb25zRGF0YSgpOyAvLyBHZXQgcG9zaXRpb25zIG9mIGxheW91dCBub2RlcyBub3RlIHRoYXQgYWxsIG5vZGVzIG1heSBub3QgYmUgbGF5b3V0IG5vZGVzIGJlY2F1c2Ugb2YgdGlsaW5nXG5cbiAgICAvLyBQb3NpdGlvbiBub2RlcywgZm9yIHRoZSBub2RlcyB3aG9zZSBpZCBkb2VzIG5vdCBpbmNsdWRlZCBpbiBkYXRhIChiZWNhdXNlIHRoZXkgYXJlIHJlbW92ZWQgZnJvbSB0aGVpciBwYXJlbnRzIGFuZCBpbmNsdWRlZCBpbiBkdW1teSBjb21wb3VuZHMpXG4gICAgLy8gdXNlIHBvc2l0aW9uIG9mIHRoZWlyIGFuY2VzdG9ycyBvciBkdW1teSBhbmNlc3RvcnNcbiAgICBvcHRpb25zLmVsZXMubm9kZXMoKS5wb3NpdGlvbnMoZnVuY3Rpb24gKGVsZSwgaSkge1xuICAgICAgaWYgKHR5cGVvZiBlbGUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgZWxlID0gaTtcbiAgICAgIH1cbiAgICAgIC8vIElmIGVsZSBpcyBhIGNvbXBvdW5kIG5vZGUsIHRoZW4gaXRzIHBvc2l0aW9uIHdpbGwgYmUgZGVmaW5lZCBieSBpdHMgY2hpbGRyZW5cbiAgICAgIGlmICghZWxlLmlzUGFyZW50KCkpIHtcbiAgICAgICAgdmFyIHRoZUlkID0gZWxlLmlkKCk7XG4gICAgICAgIHZhciBwTm9kZSA9IGFuaW1hdGlvbkRhdGFbdGhlSWRdO1xuICAgICAgICB2YXIgdGVtcCA9IGVsZTtcbiAgICAgICAgLy8gSWYgcE5vZGUgaXMgdW5kZWZpbmVkIHNlYXJjaCB1bnRpbCBmaW5kaW5nIHBvc2l0aW9uIGRhdGEgb2YgaXRzIGZpcnN0IGFuY2VzdG9yIChJdCBtYXkgYmUgZHVtbXkgYXMgd2VsbClcbiAgICAgICAgd2hpbGUgKHBOb2RlID09IG51bGwpIHtcbiAgICAgICAgICBwTm9kZSA9IGFuaW1hdGlvbkRhdGFbdGVtcC5kYXRhKCdwYXJlbnQnKV0gfHwgYW5pbWF0aW9uRGF0YVsnRHVtbXlDb21wb3VuZF8nICsgdGVtcC5kYXRhKCdwYXJlbnQnKV07XG4gICAgICAgICAgYW5pbWF0aW9uRGF0YVt0aGVJZF0gPSBwTm9kZTtcbiAgICAgICAgICB0ZW1wID0gdGVtcC5wYXJlbnQoKVswXTtcbiAgICAgICAgICBpZiAodGVtcCA9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAocE5vZGUgIT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB4OiBwTm9kZS54LFxuICAgICAgICAgICAgeTogcE5vZGUueVxuICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHg6IGVsZS5wb3NpdGlvbigneCcpLFxuICAgICAgICAgICAgeTogZWxlLnBvc2l0aW9uKCd5JylcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBhZnRlclJlcG9zaXRpb24oKTtcblxuICAgIGZyYW1lSWQgPSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoaXRlcmF0ZUFuaW1hdGVkKTtcbiAgfTtcblxuICAvKlxuICAqIExpc3RlbiAnbGF5b3V0c3RhcnRlZCcgZXZlbnQgYW5kIHN0YXJ0IGFuaW1hdGVkIGl0ZXJhdGlvbiBpZiBhbmltYXRlIG9wdGlvbiBpcyAnZHVyaW5nJ1xuICAqL1xuICBsYXlvdXQuYWRkTGlzdGVuZXIoJ2xheW91dHN0YXJ0ZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHNlbGYub3B0aW9ucy5hbmltYXRlID09PSAnZHVyaW5nJykge1xuICAgICAgZnJhbWVJZCA9IHJlcXVlc3RBbmltYXRpb25GcmFtZShpdGVyYXRlQW5pbWF0ZWQpO1xuICAgIH1cbiAgfSk7XG5cbiAgbGF5b3V0LnJ1bkxheW91dCgpOyAvLyBSdW4gY29zZSBsYXlvdXRcblxuICAvKlxuICAgKiBJZiBhbmltYXRlIG9wdGlvbiBpcyBub3QgJ2R1cmluZycgKCdlbmQnIG9yIGZhbHNlKSBwZXJmb3JtIHRoZXNlIGhlcmUgKElmIGl0IGlzICdkdXJpbmcnIHNpbWlsYXIgdGhpbmdzIGFyZSBhbHJlYWR5IHBlcmZvcm1lZClcbiAgICovXG4gIGlmICh0aGlzLm9wdGlvbnMuYW5pbWF0ZSAhPT0gXCJkdXJpbmdcIikge1xuICAgIHNlbGYub3B0aW9ucy5lbGVzLm5vZGVzKCkubm90KFwiOnBhcmVudFwiKS5sYXlvdXRQb3NpdGlvbnMoc2VsZiwgc2VsZi5vcHRpb25zLCBnZXRQb3NpdGlvbnMpOyAvLyBVc2UgbGF5b3V0IHBvc2l0aW9ucyB0byByZXBvc2l0aW9uIHRoZSBub2RlcyBpdCBjb25zaWRlcnMgdGhlIG9wdGlvbnMgcGFyYW1ldGVyXG4gICAgcmVhZHkgPSBmYWxzZTtcbiAgfVxuXG4gIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xufTtcblxuLy9HZXQgdGhlIHRvcCBtb3N0IG9uZXMgb2YgYSBsaXN0IG9mIG5vZGVzXG5fQ29TRUxheW91dC5wcm90b3R5cGUuZ2V0VG9wTW9zdE5vZGVzID0gZnVuY3Rpb24gKG5vZGVzKSB7XG4gIHZhciBub2Rlc01hcCA9IHt9O1xuICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgbm9kZXNNYXBbbm9kZXNbaV0uaWQoKV0gPSB0cnVlO1xuICB9XG4gIHZhciByb290cyA9IG5vZGVzLmZpbHRlcihmdW5jdGlvbiAoZWxlLCBpKSB7XG4gICAgaWYgKHR5cGVvZiBlbGUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgIGVsZSA9IGk7XG4gICAgfVxuICAgIHZhciBwYXJlbnQgPSBlbGUucGFyZW50KClbMF07XG4gICAgd2hpbGUgKHBhcmVudCAhPSBudWxsKSB7XG4gICAgICBpZiAobm9kZXNNYXBbcGFyZW50LmlkKCldKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIHBhcmVudCA9IHBhcmVudC5wYXJlbnQoKVswXTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH0pO1xuXG4gIHJldHVybiByb290cztcbn07XG5cbl9Db1NFTGF5b3V0LnByb3RvdHlwZS5wcm9jZXNzQ2hpbGRyZW5MaXN0ID0gZnVuY3Rpb24gKHBhcmVudCwgY2hpbGRyZW4sIGxheW91dCkge1xuICB2YXIgc2l6ZSA9IGNoaWxkcmVuLmxlbmd0aDtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzaXplOyBpKyspIHtcbiAgICB2YXIgdGhlQ2hpbGQgPSBjaGlsZHJlbltpXTtcbiAgICB2YXIgY2hpbGRyZW5fb2ZfY2hpbGRyZW4gPSB0aGVDaGlsZC5jaGlsZHJlbigpO1xuICAgIHZhciB0aGVOb2RlO1xuXG4gICAgdmFyIGRpbWVuc2lvbnMgPSB0aGVDaGlsZC5sYXlvdXREaW1lbnNpb25zKHtcbiAgICAgIG5vZGVEaW1lbnNpb25zSW5jbHVkZUxhYmVsczogdGhpcy5vcHRpb25zLm5vZGVEaW1lbnNpb25zSW5jbHVkZUxhYmVsc1xuICAgIH0pO1xuXG4gICAgaWYgKHRoZUNoaWxkLm91dGVyV2lkdGgoKSAhPSBudWxsICYmIHRoZUNoaWxkLm91dGVySGVpZ2h0KCkgIT0gbnVsbCkge1xuICAgICAgdGhlTm9kZSA9IHBhcmVudC5hZGQobmV3IENvU0VOb2RlKGxheW91dC5ncmFwaE1hbmFnZXIsIG5ldyBQb2ludEQodGhlQ2hpbGQucG9zaXRpb24oJ3gnKSAtIGRpbWVuc2lvbnMudyAvIDIsIHRoZUNoaWxkLnBvc2l0aW9uKCd5JykgLSBkaW1lbnNpb25zLmggLyAyKSwgbmV3IERpbWVuc2lvbkQocGFyc2VGbG9hdChkaW1lbnNpb25zLncpLCBwYXJzZUZsb2F0KGRpbWVuc2lvbnMuaCkpKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoZU5vZGUgPSBwYXJlbnQuYWRkKG5ldyBDb1NFTm9kZSh0aGlzLmdyYXBoTWFuYWdlcikpO1xuICAgIH1cbiAgICAvLyBBdHRhY2ggaWQgdG8gdGhlIGxheW91dCBub2RlXG4gICAgdGhlTm9kZS5pZCA9IHRoZUNoaWxkLmRhdGEoXCJpZFwiKTtcbiAgICAvLyBBdHRhY2ggdGhlIHBhZGRpbmdzIG9mIGN5IG5vZGUgdG8gbGF5b3V0IG5vZGVcbiAgICB0aGVOb2RlLnBhZGRpbmdMZWZ0ID0gcGFyc2VJbnQodGhlQ2hpbGQuY3NzKCdwYWRkaW5nJykpO1xuICAgIHRoZU5vZGUucGFkZGluZ1RvcCA9IHBhcnNlSW50KHRoZUNoaWxkLmNzcygncGFkZGluZycpKTtcbiAgICB0aGVOb2RlLnBhZGRpbmdSaWdodCA9IHBhcnNlSW50KHRoZUNoaWxkLmNzcygncGFkZGluZycpKTtcbiAgICB0aGVOb2RlLnBhZGRpbmdCb3R0b20gPSBwYXJzZUludCh0aGVDaGlsZC5jc3MoJ3BhZGRpbmcnKSk7XG5cbiAgICAvL0F0dGFjaCB0aGUgbGFiZWwgcHJvcGVydGllcyB0byBjb21wb3VuZCBpZiBsYWJlbHMgd2lsbCBiZSBpbmNsdWRlZCBpbiBub2RlIGRpbWVuc2lvbnMgIFxuICAgIGlmICh0aGlzLm9wdGlvbnMubm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzKSB7XG4gICAgICBpZiAodGhlQ2hpbGQuaXNQYXJlbnQoKSkge1xuICAgICAgICB2YXIgbGFiZWxXaWR0aCA9IHRoZUNoaWxkLmJvdW5kaW5nQm94KHsgaW5jbHVkZUxhYmVsczogdHJ1ZSwgaW5jbHVkZU5vZGVzOiBmYWxzZSB9KS53O1xuICAgICAgICB2YXIgbGFiZWxIZWlnaHQgPSB0aGVDaGlsZC5ib3VuZGluZ0JveCh7IGluY2x1ZGVMYWJlbHM6IHRydWUsIGluY2x1ZGVOb2RlczogZmFsc2UgfSkuaDtcbiAgICAgICAgdmFyIGxhYmVsUG9zID0gdGhlQ2hpbGQuY3NzKFwidGV4dC1oYWxpZ25cIik7XG4gICAgICAgIHRoZU5vZGUubGFiZWxXaWR0aCA9IGxhYmVsV2lkdGg7XG4gICAgICAgIHRoZU5vZGUubGFiZWxIZWlnaHQgPSBsYWJlbEhlaWdodDtcbiAgICAgICAgdGhlTm9kZS5sYWJlbFBvcyA9IGxhYmVsUG9zO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIE1hcCB0aGUgbGF5b3V0IG5vZGVcbiAgICB0aGlzLmlkVG9MTm9kZVt0aGVDaGlsZC5kYXRhKFwiaWRcIildID0gdGhlTm9kZTtcblxuICAgIGlmIChpc05hTih0aGVOb2RlLnJlY3QueCkpIHtcbiAgICAgIHRoZU5vZGUucmVjdC54ID0gMDtcbiAgICB9XG5cbiAgICBpZiAoaXNOYU4odGhlTm9kZS5yZWN0LnkpKSB7XG4gICAgICB0aGVOb2RlLnJlY3QueSA9IDA7XG4gICAgfVxuXG4gICAgaWYgKGNoaWxkcmVuX29mX2NoaWxkcmVuICE9IG51bGwgJiYgY2hpbGRyZW5fb2ZfY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xuICAgICAgdmFyIHRoZU5ld0dyYXBoO1xuICAgICAgdGhlTmV3R3JhcGggPSBsYXlvdXQuZ2V0R3JhcGhNYW5hZ2VyKCkuYWRkKGxheW91dC5uZXdHcmFwaCgpLCB0aGVOb2RlKTtcbiAgICAgIHRoaXMucHJvY2Vzc0NoaWxkcmVuTGlzdCh0aGVOZXdHcmFwaCwgY2hpbGRyZW5fb2ZfY2hpbGRyZW4sIGxheW91dCk7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIEBicmllZiA6IGNhbGxlZCBvbiBjb250aW51b3VzIGxheW91dHMgdG8gc3RvcCB0aGVtIGJlZm9yZSB0aGV5IGZpbmlzaFxuICovXG5fQ29TRUxheW91dC5wcm90b3R5cGUuc3RvcCA9IGZ1bmN0aW9uICgpIHtcbiAgdGhpcy5zdG9wcGVkID0gdHJ1ZTtcblxuICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbn07XG5cbnZhciByZWdpc3RlciA9IGZ1bmN0aW9uIHJlZ2lzdGVyKGN5dG9zY2FwZSkge1xuICAvLyAgdmFyIExheW91dCA9IGdldExheW91dCggY3l0b3NjYXBlICk7XG5cbiAgY3l0b3NjYXBlKCdsYXlvdXQnLCAnY29zZS1iaWxrZW50JywgX0NvU0VMYXlvdXQpO1xufTtcblxuLy8gYXV0byByZWcgZm9yIGdsb2JhbHNcbmlmICh0eXBlb2YgY3l0b3NjYXBlICE9PSAndW5kZWZpbmVkJykge1xuICByZWdpc3RlcihjeXRvc2NhcGUpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHJlZ2lzdGVyO1xuXG4vKioqLyB9KVxuLyoqKioqKi8gXSk7XG59KTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../../node_modules/cytoscape-cose-bilkent/cytoscape-cose-bilkent.js\n");
+
+/***/ }),
+
+/***/ "../../../node_modules/cytoscape/dist/cytoscape.umd.js":
+/*!*************************************************************!*\
+ !*** ../../../node_modules/cytoscape/dist/cytoscape.umd.js ***!
+ \*************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+eval("/**\n * Copyright (c) 2016-2023, The Cytoscape Consortium.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of\n * this software and associated documentation files (the “Software”), to deal in\n * the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\n * of the Software, and to permit persons to whom the Software is furnished to do\n * so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n(function (global, factory) {\n true ? module.exports = factory() :\n 0;\n})(this, (function () { 'use strict';\n\n function _typeof(obj) {\n \"@babel/helpers - typeof\";\n\n return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) {\n return typeof obj;\n } : function (obj) {\n return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n }, _typeof(obj);\n }\n\n function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n }\n\n function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n function _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n Object.defineProperty(Constructor, \"prototype\", {\n writable: false\n });\n return Constructor;\n }\n\n function _defineProperty$1(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n\n return obj;\n }\n\n function _slicedToArray(arr, i) {\n return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();\n }\n\n function _arrayWithHoles(arr) {\n if (Array.isArray(arr)) return arr;\n }\n\n function _iterableToArrayLimit(arr, i) {\n var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"];\n\n if (_i == null) return;\n var _arr = [];\n var _n = true;\n var _d = false;\n\n var _s, _e;\n\n try {\n for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {\n _arr.push(_s.value);\n\n if (i && _arr.length === i) break;\n }\n } catch (err) {\n _d = true;\n _e = err;\n } finally {\n try {\n if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n } finally {\n if (_d) throw _e;\n }\n }\n\n return _arr;\n }\n\n function _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n }\n\n function _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n\n for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n\n return arr2;\n }\n\n function _nonIterableRest() {\n throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n }\n\n var _window = typeof window === 'undefined' ? null : window; // eslint-disable-line no-undef\n\n var navigator = _window ? _window.navigator : null;\n _window ? _window.document : null;\n\n var typeofstr = _typeof('');\n\n var typeofobj = _typeof({});\n\n var typeoffn = _typeof(function () {});\n\n var typeofhtmlele = typeof HTMLElement === \"undefined\" ? \"undefined\" : _typeof(HTMLElement);\n\n var instanceStr = function instanceStr(obj) {\n return obj && obj.instanceString && fn$6(obj.instanceString) ? obj.instanceString() : null;\n };\n\n var string = function string(obj) {\n return obj != null && _typeof(obj) == typeofstr;\n };\n var fn$6 = function fn(obj) {\n return obj != null && _typeof(obj) === typeoffn;\n };\n var array = function array(obj) {\n return !elementOrCollection(obj) && (Array.isArray ? Array.isArray(obj) : obj != null && obj instanceof Array);\n };\n var plainObject = function plainObject(obj) {\n return obj != null && _typeof(obj) === typeofobj && !array(obj) && obj.constructor === Object;\n };\n var object = function object(obj) {\n return obj != null && _typeof(obj) === typeofobj;\n };\n var number$1 = function number(obj) {\n return obj != null && _typeof(obj) === _typeof(1) && !isNaN(obj);\n };\n var integer = function integer(obj) {\n return number$1(obj) && Math.floor(obj) === obj;\n };\n var htmlElement = function htmlElement(obj) {\n if ('undefined' === typeofhtmlele) {\n return undefined;\n } else {\n return null != obj && obj instanceof HTMLElement;\n }\n };\n var elementOrCollection = function elementOrCollection(obj) {\n return element(obj) || collection(obj);\n };\n var element = function element(obj) {\n return instanceStr(obj) === 'collection' && obj._private.single;\n };\n var collection = function collection(obj) {\n return instanceStr(obj) === 'collection' && !obj._private.single;\n };\n var core = function core(obj) {\n return instanceStr(obj) === 'core';\n };\n var stylesheet = function stylesheet(obj) {\n return instanceStr(obj) === 'stylesheet';\n };\n var event = function event(obj) {\n return instanceStr(obj) === 'event';\n };\n var emptyString = function emptyString(obj) {\n if (obj === undefined || obj === null) {\n // null is empty\n return true;\n } else if (obj === '' || obj.match(/^\\s+$/)) {\n return true; // empty string is empty\n }\n\n return false; // otherwise, we don't know what we've got\n };\n var domElement = function domElement(obj) {\n if (typeof HTMLElement === 'undefined') {\n return false; // we're not in a browser so it doesn't matter\n } else {\n return obj instanceof HTMLElement;\n }\n };\n var boundingBox = function boundingBox(obj) {\n return plainObject(obj) && number$1(obj.x1) && number$1(obj.x2) && number$1(obj.y1) && number$1(obj.y2);\n };\n var promise = function promise(obj) {\n return object(obj) && fn$6(obj.then);\n };\n var ms = function ms() {\n return navigator && navigator.userAgent.match(/msie|trident|edge/i);\n }; // probably a better way to detect this...\n\n var memoize$1 = function memoize(fn, keyFn) {\n if (!keyFn) {\n keyFn = function keyFn() {\n if (arguments.length === 1) {\n return arguments[0];\n } else if (arguments.length === 0) {\n return 'undefined';\n }\n\n var args = [];\n\n for (var i = 0; i < arguments.length; i++) {\n args.push(arguments[i]);\n }\n\n return args.join('$');\n };\n }\n\n var memoizedFn = function memoizedFn() {\n var self = this;\n var args = arguments;\n var ret;\n var k = keyFn.apply(self, args);\n var cache = memoizedFn.cache;\n\n if (!(ret = cache[k])) {\n ret = cache[k] = fn.apply(self, args);\n }\n\n return ret;\n };\n\n memoizedFn.cache = {};\n return memoizedFn;\n };\n\n var camel2dash = memoize$1(function (str) {\n return str.replace(/([A-Z])/g, function (v) {\n return '-' + v.toLowerCase();\n });\n });\n var dash2camel = memoize$1(function (str) {\n return str.replace(/(-\\w)/g, function (v) {\n return v[1].toUpperCase();\n });\n });\n var prependCamel = memoize$1(function (prefix, str) {\n return prefix + str[0].toUpperCase() + str.substring(1);\n }, function (prefix, str) {\n return prefix + '$' + str;\n });\n var capitalize = function capitalize(str) {\n if (emptyString(str)) {\n return str;\n }\n\n return str.charAt(0).toUpperCase() + str.substring(1);\n };\n\n var number = '(?:[-+]?(?:(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:[Ee][+-]?\\\\d+)?))';\n var rgba = 'rgb[a]?\\\\((' + number + '[%]?)\\\\s*,\\\\s*(' + number + '[%]?)\\\\s*,\\\\s*(' + number + '[%]?)(?:\\\\s*,\\\\s*(' + number + '))?\\\\)';\n var rgbaNoBackRefs = 'rgb[a]?\\\\((?:' + number + '[%]?)\\\\s*,\\\\s*(?:' + number + '[%]?)\\\\s*,\\\\s*(?:' + number + '[%]?)(?:\\\\s*,\\\\s*(?:' + number + '))?\\\\)';\n var hsla = 'hsl[a]?\\\\((' + number + ')\\\\s*,\\\\s*(' + number + '[%])\\\\s*,\\\\s*(' + number + '[%])(?:\\\\s*,\\\\s*(' + number + '))?\\\\)';\n var hslaNoBackRefs = 'hsl[a]?\\\\((?:' + number + ')\\\\s*,\\\\s*(?:' + number + '[%])\\\\s*,\\\\s*(?:' + number + '[%])(?:\\\\s*,\\\\s*(?:' + number + '))?\\\\)';\n var hex3 = '\\\\#[0-9a-fA-F]{3}';\n var hex6 = '\\\\#[0-9a-fA-F]{6}';\n\n var ascending = function ascending(a, b) {\n if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n } else {\n return 0;\n }\n };\n var descending = function descending(a, b) {\n return -1 * ascending(a, b);\n };\n\n var extend = Object.assign != null ? Object.assign.bind(Object) : function (tgt) {\n var args = arguments;\n\n for (var i = 1; i < args.length; i++) {\n var obj = args[i];\n\n if (obj == null) {\n continue;\n }\n\n var keys = Object.keys(obj);\n\n for (var j = 0; j < keys.length; j++) {\n var k = keys[j];\n tgt[k] = obj[k];\n }\n }\n\n return tgt;\n };\n\n var hex2tuple = function hex2tuple(hex) {\n if (!(hex.length === 4 || hex.length === 7) || hex[0] !== '#') {\n return;\n }\n\n var shortHex = hex.length === 4;\n var r, g, b;\n var base = 16;\n\n if (shortHex) {\n r = parseInt(hex[1] + hex[1], base);\n g = parseInt(hex[2] + hex[2], base);\n b = parseInt(hex[3] + hex[3], base);\n } else {\n r = parseInt(hex[1] + hex[2], base);\n g = parseInt(hex[3] + hex[4], base);\n b = parseInt(hex[5] + hex[6], base);\n }\n\n return [r, g, b];\n }; // get [r, g, b, a] from hsl(0, 0, 0) or hsla(0, 0, 0, 0)\n\n var hsl2tuple = function hsl2tuple(hsl) {\n var ret;\n var h, s, l, a, r, g, b;\n\n function hue2rgb(p, q, t) {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n }\n\n var m = new RegExp('^' + hsla + '$').exec(hsl);\n\n if (m) {\n // get hue\n h = parseInt(m[1]);\n\n if (h < 0) {\n h = (360 - -1 * h % 360) % 360;\n } else if (h > 360) {\n h = h % 360;\n }\n\n h /= 360; // normalise on [0, 1]\n\n s = parseFloat(m[2]);\n\n if (s < 0 || s > 100) {\n return;\n } // saturation is [0, 100]\n\n\n s = s / 100; // normalise on [0, 1]\n\n l = parseFloat(m[3]);\n\n if (l < 0 || l > 100) {\n return;\n } // lightness is [0, 100]\n\n\n l = l / 100; // normalise on [0, 1]\n\n a = m[4];\n\n if (a !== undefined) {\n a = parseFloat(a);\n\n if (a < 0 || a > 1) {\n return;\n } // alpha is [0, 1]\n\n } // now, convert to rgb\n // code from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript\n\n\n if (s === 0) {\n r = g = b = Math.round(l * 255); // achromatic\n } else {\n var q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n var p = 2 * l - q;\n r = Math.round(255 * hue2rgb(p, q, h + 1 / 3));\n g = Math.round(255 * hue2rgb(p, q, h));\n b = Math.round(255 * hue2rgb(p, q, h - 1 / 3));\n }\n\n ret = [r, g, b, a];\n }\n\n return ret;\n }; // get [r, g, b, a] from rgb(0, 0, 0) or rgba(0, 0, 0, 0)\n\n var rgb2tuple = function rgb2tuple(rgb) {\n var ret;\n var m = new RegExp('^' + rgba + '$').exec(rgb);\n\n if (m) {\n ret = [];\n var isPct = [];\n\n for (var i = 1; i <= 3; i++) {\n var channel = m[i];\n\n if (channel[channel.length - 1] === '%') {\n isPct[i] = true;\n }\n\n channel = parseFloat(channel);\n\n if (isPct[i]) {\n channel = channel / 100 * 255; // normalise to [0, 255]\n }\n\n if (channel < 0 || channel > 255) {\n return;\n } // invalid channel value\n\n\n ret.push(Math.floor(channel));\n }\n\n var atLeastOneIsPct = isPct[1] || isPct[2] || isPct[3];\n var allArePct = isPct[1] && isPct[2] && isPct[3];\n\n if (atLeastOneIsPct && !allArePct) {\n return;\n } // must all be percent values if one is\n\n\n var alpha = m[4];\n\n if (alpha !== undefined) {\n alpha = parseFloat(alpha);\n\n if (alpha < 0 || alpha > 1) {\n return;\n } // invalid alpha value\n\n\n ret.push(alpha);\n }\n }\n\n return ret;\n };\n var colorname2tuple = function colorname2tuple(color) {\n return colors[color.toLowerCase()];\n };\n var color2tuple = function color2tuple(color) {\n return (array(color) ? color : null) || colorname2tuple(color) || hex2tuple(color) || rgb2tuple(color) || hsl2tuple(color);\n };\n var colors = {\n // special colour names\n transparent: [0, 0, 0, 0],\n // NB alpha === 0\n // regular colours\n aliceblue: [240, 248, 255],\n antiquewhite: [250, 235, 215],\n aqua: [0, 255, 255],\n aquamarine: [127, 255, 212],\n azure: [240, 255, 255],\n beige: [245, 245, 220],\n bisque: [255, 228, 196],\n black: [0, 0, 0],\n blanchedalmond: [255, 235, 205],\n blue: [0, 0, 255],\n blueviolet: [138, 43, 226],\n brown: [165, 42, 42],\n burlywood: [222, 184, 135],\n cadetblue: [95, 158, 160],\n chartreuse: [127, 255, 0],\n chocolate: [210, 105, 30],\n coral: [255, 127, 80],\n cornflowerblue: [100, 149, 237],\n cornsilk: [255, 248, 220],\n crimson: [220, 20, 60],\n cyan: [0, 255, 255],\n darkblue: [0, 0, 139],\n darkcyan: [0, 139, 139],\n darkgoldenrod: [184, 134, 11],\n darkgray: [169, 169, 169],\n darkgreen: [0, 100, 0],\n darkgrey: [169, 169, 169],\n darkkhaki: [189, 183, 107],\n darkmagenta: [139, 0, 139],\n darkolivegreen: [85, 107, 47],\n darkorange: [255, 140, 0],\n darkorchid: [153, 50, 204],\n darkred: [139, 0, 0],\n darksalmon: [233, 150, 122],\n darkseagreen: [143, 188, 143],\n darkslateblue: [72, 61, 139],\n darkslategray: [47, 79, 79],\n darkslategrey: [47, 79, 79],\n darkturquoise: [0, 206, 209],\n darkviolet: [148, 0, 211],\n deeppink: [255, 20, 147],\n deepskyblue: [0, 191, 255],\n dimgray: [105, 105, 105],\n dimgrey: [105, 105, 105],\n dodgerblue: [30, 144, 255],\n firebrick: [178, 34, 34],\n floralwhite: [255, 250, 240],\n forestgreen: [34, 139, 34],\n fuchsia: [255, 0, 255],\n gainsboro: [220, 220, 220],\n ghostwhite: [248, 248, 255],\n gold: [255, 215, 0],\n goldenrod: [218, 165, 32],\n gray: [128, 128, 128],\n grey: [128, 128, 128],\n green: [0, 128, 0],\n greenyellow: [173, 255, 47],\n honeydew: [240, 255, 240],\n hotpink: [255, 105, 180],\n indianred: [205, 92, 92],\n indigo: [75, 0, 130],\n ivory: [255, 255, 240],\n khaki: [240, 230, 140],\n lavender: [230, 230, 250],\n lavenderblush: [255, 240, 245],\n lawngreen: [124, 252, 0],\n lemonchiffon: [255, 250, 205],\n lightblue: [173, 216, 230],\n lightcoral: [240, 128, 128],\n lightcyan: [224, 255, 255],\n lightgoldenrodyellow: [250, 250, 210],\n lightgray: [211, 211, 211],\n lightgreen: [144, 238, 144],\n lightgrey: [211, 211, 211],\n lightpink: [255, 182, 193],\n lightsalmon: [255, 160, 122],\n lightseagreen: [32, 178, 170],\n lightskyblue: [135, 206, 250],\n lightslategray: [119, 136, 153],\n lightslategrey: [119, 136, 153],\n lightsteelblue: [176, 196, 222],\n lightyellow: [255, 255, 224],\n lime: [0, 255, 0],\n limegreen: [50, 205, 50],\n linen: [250, 240, 230],\n magenta: [255, 0, 255],\n maroon: [128, 0, 0],\n mediumaquamarine: [102, 205, 170],\n mediumblue: [0, 0, 205],\n mediumorchid: [186, 85, 211],\n mediumpurple: [147, 112, 219],\n mediumseagreen: [60, 179, 113],\n mediumslateblue: [123, 104, 238],\n mediumspringgreen: [0, 250, 154],\n mediumturquoise: [72, 209, 204],\n mediumvioletred: [199, 21, 133],\n midnightblue: [25, 25, 112],\n mintcream: [245, 255, 250],\n mistyrose: [255, 228, 225],\n moccasin: [255, 228, 181],\n navajowhite: [255, 222, 173],\n navy: [0, 0, 128],\n oldlace: [253, 245, 230],\n olive: [128, 128, 0],\n olivedrab: [107, 142, 35],\n orange: [255, 165, 0],\n orangered: [255, 69, 0],\n orchid: [218, 112, 214],\n palegoldenrod: [238, 232, 170],\n palegreen: [152, 251, 152],\n paleturquoise: [175, 238, 238],\n palevioletred: [219, 112, 147],\n papayawhip: [255, 239, 213],\n peachpuff: [255, 218, 185],\n peru: [205, 133, 63],\n pink: [255, 192, 203],\n plum: [221, 160, 221],\n powderblue: [176, 224, 230],\n purple: [128, 0, 128],\n red: [255, 0, 0],\n rosybrown: [188, 143, 143],\n royalblue: [65, 105, 225],\n saddlebrown: [139, 69, 19],\n salmon: [250, 128, 114],\n sandybrown: [244, 164, 96],\n seagreen: [46, 139, 87],\n seashell: [255, 245, 238],\n sienna: [160, 82, 45],\n silver: [192, 192, 192],\n skyblue: [135, 206, 235],\n slateblue: [106, 90, 205],\n slategray: [112, 128, 144],\n slategrey: [112, 128, 144],\n snow: [255, 250, 250],\n springgreen: [0, 255, 127],\n steelblue: [70, 130, 180],\n tan: [210, 180, 140],\n teal: [0, 128, 128],\n thistle: [216, 191, 216],\n tomato: [255, 99, 71],\n turquoise: [64, 224, 208],\n violet: [238, 130, 238],\n wheat: [245, 222, 179],\n white: [255, 255, 255],\n whitesmoke: [245, 245, 245],\n yellow: [255, 255, 0],\n yellowgreen: [154, 205, 50]\n };\n\n var setMap = function setMap(options) {\n var obj = options.map;\n var keys = options.keys;\n var l = keys.length;\n\n for (var i = 0; i < l; i++) {\n var key = keys[i];\n\n if (plainObject(key)) {\n throw Error('Tried to set map with object key');\n }\n\n if (i < keys.length - 1) {\n // extend the map if necessary\n if (obj[key] == null) {\n obj[key] = {};\n }\n\n obj = obj[key];\n } else {\n // set the value\n obj[key] = options.value;\n }\n }\n }; // gets the value in a map even if it's not built in places\n\n var getMap = function getMap(options) {\n var obj = options.map;\n var keys = options.keys;\n var l = keys.length;\n\n for (var i = 0; i < l; i++) {\n var key = keys[i];\n\n if (plainObject(key)) {\n throw Error('Tried to get map with object key');\n }\n\n obj = obj[key];\n\n if (obj == null) {\n return obj;\n }\n }\n\n return obj;\n }; // deletes the entry in the map\n\n /**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\n function isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n }\n\n var isObject_1 = isObject;\n\n var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof __webpack_require__.g !== 'undefined' ? __webpack_require__.g : typeof self !== 'undefined' ? self : {};\n\n function createCommonjsModule(fn, module) {\n \treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n }\n\n /** Detect free variable `global` from Node.js. */\n var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;\n\n var _freeGlobal = freeGlobal;\n\n /** Detect free variable `self`. */\n var freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n /** Used as a reference to the global object. */\n var root = _freeGlobal || freeSelf || Function('return this')();\n\n var _root = root;\n\n /**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\n var now = function() {\n return _root.Date.now();\n };\n\n var now_1 = now;\n\n /** Used to match a single whitespace character. */\n var reWhitespace = /\\s/;\n\n /**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace\n * character of `string`.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {number} Returns the index of the last non-whitespace character.\n */\n function trimmedEndIndex(string) {\n var index = string.length;\n\n while (index-- && reWhitespace.test(string.charAt(index))) {}\n return index;\n }\n\n var _trimmedEndIndex = trimmedEndIndex;\n\n /** Used to match leading whitespace. */\n var reTrimStart = /^\\s+/;\n\n /**\n * The base implementation of `_.trim`.\n *\n * @private\n * @param {string} string The string to trim.\n * @returns {string} Returns the trimmed string.\n */\n function baseTrim(string) {\n return string\n ? string.slice(0, _trimmedEndIndex(string) + 1).replace(reTrimStart, '')\n : string;\n }\n\n var _baseTrim = baseTrim;\n\n /** Built-in value references. */\n var Symbol$1 = _root.Symbol;\n\n var _Symbol = Symbol$1;\n\n /** Used for built-in method references. */\n var objectProto$5 = Object.prototype;\n\n /** Used to check objects for own properties. */\n var hasOwnProperty$4 = objectProto$5.hasOwnProperty;\n\n /**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\n var nativeObjectToString$1 = objectProto$5.toString;\n\n /** Built-in value references. */\n var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;\n\n /**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\n function getRawTag(value) {\n var isOwn = hasOwnProperty$4.call(value, symToStringTag$1),\n tag = value[symToStringTag$1];\n\n try {\n value[symToStringTag$1] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString$1.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag$1] = tag;\n } else {\n delete value[symToStringTag$1];\n }\n }\n return result;\n }\n\n var _getRawTag = getRawTag;\n\n /** Used for built-in method references. */\n var objectProto$4 = Object.prototype;\n\n /**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\n var nativeObjectToString = objectProto$4.toString;\n\n /**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\n function objectToString(value) {\n return nativeObjectToString.call(value);\n }\n\n var _objectToString = objectToString;\n\n /** `Object#toString` result references. */\n var nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n /** Built-in value references. */\n var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;\n\n /**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\n function baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? _getRawTag(value)\n : _objectToString(value);\n }\n\n var _baseGetTag = baseGetTag;\n\n /**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\n function isObjectLike(value) {\n return value != null && typeof value == 'object';\n }\n\n var isObjectLike_1 = isObjectLike;\n\n /** `Object#toString` result references. */\n var symbolTag = '[object Symbol]';\n\n /**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\n function isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike_1(value) && _baseGetTag(value) == symbolTag);\n }\n\n var isSymbol_1 = isSymbol;\n\n /** Used as references for various `Number` constants. */\n var NAN = 0 / 0;\n\n /** Used to detect bad signed hexadecimal string values. */\n var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n /** Used to detect binary string values. */\n var reIsBinary = /^0b[01]+$/i;\n\n /** Used to detect octal string values. */\n var reIsOctal = /^0o[0-7]+$/i;\n\n /** Built-in method references without a dependency on `root`. */\n var freeParseInt = parseInt;\n\n /**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\n function toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol_1(value)) {\n return NAN;\n }\n if (isObject_1(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject_1(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = _baseTrim(value);\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n }\n\n var toNumber_1 = toNumber;\n\n /** Error message constants. */\n var FUNC_ERROR_TEXT$1 = 'Expected a function';\n\n /* Built-in method references for those with the same name as other `lodash` methods. */\n var nativeMax = Math.max,\n nativeMin = Math.min;\n\n /**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\n function debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT$1);\n }\n wait = toNumber_1(wait) || 0;\n if (isObject_1(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber_1(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n timeWaiting = wait - timeSinceLastCall;\n\n return maxing\n ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)\n : timeWaiting;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now_1();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now_1());\n }\n\n function debounced() {\n var time = now_1(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n clearTimeout(timerId);\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n }\n\n var debounce_1 = debounce;\n\n var performance = _window ? _window.performance : null;\n var pnow = performance && performance.now ? function () {\n return performance.now();\n } : function () {\n return Date.now();\n };\n\n var raf = function () {\n if (_window) {\n if (_window.requestAnimationFrame) {\n return function (fn) {\n _window.requestAnimationFrame(fn);\n };\n } else if (_window.mozRequestAnimationFrame) {\n return function (fn) {\n _window.mozRequestAnimationFrame(fn);\n };\n } else if (_window.webkitRequestAnimationFrame) {\n return function (fn) {\n _window.webkitRequestAnimationFrame(fn);\n };\n } else if (_window.msRequestAnimationFrame) {\n return function (fn) {\n _window.msRequestAnimationFrame(fn);\n };\n }\n }\n\n return function (fn) {\n if (fn) {\n setTimeout(function () {\n fn(pnow());\n }, 1000 / 60);\n }\n };\n }();\n\n var requestAnimationFrame = function requestAnimationFrame(fn) {\n return raf(fn);\n };\n var performanceNow = pnow;\n\n var DEFAULT_HASH_SEED = 9261;\n var K = 65599; // 37 also works pretty well\n\n var DEFAULT_HASH_SEED_ALT = 5381;\n var hashIterableInts = function hashIterableInts(iterator) {\n var seed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_HASH_SEED;\n // sdbm/string-hash\n var hash = seed;\n var entry;\n\n for (;;) {\n entry = iterator.next();\n\n if (entry.done) {\n break;\n }\n\n hash = hash * K + entry.value | 0;\n }\n\n return hash;\n };\n var hashInt = function hashInt(num) {\n var seed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_HASH_SEED;\n // sdbm/string-hash\n return seed * K + num | 0;\n };\n var hashIntAlt = function hashIntAlt(num) {\n var seed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_HASH_SEED_ALT;\n // djb2/string-hash\n return (seed << 5) + seed + num | 0;\n };\n var combineHashes = function combineHashes(hash1, hash2) {\n return hash1 * 0x200000 + hash2;\n };\n var combineHashesArray = function combineHashesArray(hashes) {\n return hashes[0] * 0x200000 + hashes[1];\n };\n var hashArrays = function hashArrays(hashes1, hashes2) {\n return [hashInt(hashes1[0], hashes2[0]), hashIntAlt(hashes1[1], hashes2[1])];\n };\n var hashIntsArray = function hashIntsArray(ints, seed) {\n var entry = {\n value: 0,\n done: false\n };\n var i = 0;\n var length = ints.length;\n var iterator = {\n next: function next() {\n if (i < length) {\n entry.value = ints[i++];\n } else {\n entry.done = true;\n }\n\n return entry;\n }\n };\n return hashIterableInts(iterator, seed);\n };\n var hashString = function hashString(str, seed) {\n var entry = {\n value: 0,\n done: false\n };\n var i = 0;\n var length = str.length;\n var iterator = {\n next: function next() {\n if (i < length) {\n entry.value = str.charCodeAt(i++);\n } else {\n entry.done = true;\n }\n\n return entry;\n }\n };\n return hashIterableInts(iterator, seed);\n };\n var hashStrings = function hashStrings() {\n return hashStringsArray(arguments);\n };\n var hashStringsArray = function hashStringsArray(strs) {\n var hash;\n\n for (var i = 0; i < strs.length; i++) {\n var str = strs[i];\n\n if (i === 0) {\n hash = hashString(str);\n } else {\n hash = hashString(str, hash);\n }\n }\n\n return hash;\n };\n\n /*global console */\n var warningsEnabled = true;\n var warnSupported = console.warn != null; // eslint-disable-line no-console\n\n var traceSupported = console.trace != null; // eslint-disable-line no-console\n\n var MAX_INT$1 = Number.MAX_SAFE_INTEGER || 9007199254740991;\n var trueify = function trueify() {\n return true;\n };\n var falsify = function falsify() {\n return false;\n };\n var zeroify = function zeroify() {\n return 0;\n };\n var noop$1 = function noop() {};\n var error = function error(msg) {\n throw new Error(msg);\n };\n var warnings = function warnings(enabled) {\n if (enabled !== undefined) {\n warningsEnabled = !!enabled;\n } else {\n return warningsEnabled;\n }\n };\n var warn = function warn(msg) {\n /* eslint-disable no-console */\n if (!warnings()) {\n return;\n }\n\n if (warnSupported) {\n console.warn(msg);\n } else {\n console.log(msg);\n\n if (traceSupported) {\n console.trace();\n }\n }\n };\n /* eslint-enable */\n\n var clone = function clone(obj) {\n return extend({}, obj);\n }; // gets a shallow copy of the argument\n\n var copy = function copy(obj) {\n if (obj == null) {\n return obj;\n }\n\n if (array(obj)) {\n return obj.slice();\n } else if (plainObject(obj)) {\n return clone(obj);\n } else {\n return obj;\n }\n };\n var copyArray$1 = function copyArray(arr) {\n return arr.slice();\n };\n var uuid = function uuid(a, b\n /* placeholders */\n ) {\n for ( // loop :)\n b = a = ''; // b - result , a - numeric letiable\n a++ < 36; //\n b += a * 51 & 52 // if \"a\" is not 9 or 14 or 19 or 24\n ? // return a random number or 4\n (a ^ 15 // if \"a\" is not 15\n ? // generate a random number from 0 to 15\n 8 ^ Math.random() * (a ^ 20 ? 16 : 4) // unless \"a\" is 20, in which case a random number from 8 to 11\n : 4 // otherwise 4\n ).toString(16) : '-' // in other cases (if \"a\" is 9,14,19,24) insert \"-\"\n ) {\n }\n\n return b;\n };\n var _staticEmptyObject = {};\n var staticEmptyObject = function staticEmptyObject() {\n return _staticEmptyObject;\n };\n var defaults$g = function defaults(_defaults) {\n var keys = Object.keys(_defaults);\n return function (opts) {\n var filledOpts = {};\n\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i];\n var optVal = opts == null ? undefined : opts[key];\n filledOpts[key] = optVal === undefined ? _defaults[key] : optVal;\n }\n\n return filledOpts;\n };\n };\n var removeFromArray = function removeFromArray(arr, ele, oneCopy) {\n for (var i = arr.length - 1; i >= 0; i--) {\n if (arr[i] === ele) {\n arr.splice(i, 1);\n\n if (oneCopy) {\n break;\n }\n }\n }\n };\n var clearArray = function clearArray(arr) {\n arr.splice(0, arr.length);\n };\n var push = function push(arr, otherArr) {\n for (var i = 0; i < otherArr.length; i++) {\n var el = otherArr[i];\n arr.push(el);\n }\n };\n var getPrefixedProperty = function getPrefixedProperty(obj, propName, prefix) {\n if (prefix) {\n propName = prependCamel(prefix, propName); // e.g. (labelWidth, source) => sourceLabelWidth\n }\n\n return obj[propName];\n };\n var setPrefixedProperty = function setPrefixedProperty(obj, propName, prefix, value) {\n if (prefix) {\n propName = prependCamel(prefix, propName); // e.g. (labelWidth, source) => sourceLabelWidth\n }\n\n obj[propName] = value;\n };\n\n /* global Map */\n var ObjectMap = /*#__PURE__*/function () {\n function ObjectMap() {\n _classCallCheck(this, ObjectMap);\n\n this._obj = {};\n }\n\n _createClass(ObjectMap, [{\n key: \"set\",\n value: function set(key, val) {\n this._obj[key] = val;\n return this;\n }\n }, {\n key: \"delete\",\n value: function _delete(key) {\n this._obj[key] = undefined;\n return this;\n }\n }, {\n key: \"clear\",\n value: function clear() {\n this._obj = {};\n }\n }, {\n key: \"has\",\n value: function has(key) {\n return this._obj[key] !== undefined;\n }\n }, {\n key: \"get\",\n value: function get(key) {\n return this._obj[key];\n }\n }]);\n\n return ObjectMap;\n }();\n\n var Map$2 = typeof Map !== 'undefined' ? Map : ObjectMap;\n\n /* global Set */\n var undef = \"undefined\" ;\n\n var ObjectSet = /*#__PURE__*/function () {\n function ObjectSet(arrayOrObjectSet) {\n _classCallCheck(this, ObjectSet);\n\n this._obj = Object.create(null);\n this.size = 0;\n\n if (arrayOrObjectSet != null) {\n var arr;\n\n if (arrayOrObjectSet.instanceString != null && arrayOrObjectSet.instanceString() === this.instanceString()) {\n arr = arrayOrObjectSet.toArray();\n } else {\n arr = arrayOrObjectSet;\n }\n\n for (var i = 0; i < arr.length; i++) {\n this.add(arr[i]);\n }\n }\n }\n\n _createClass(ObjectSet, [{\n key: \"instanceString\",\n value: function instanceString() {\n return 'set';\n }\n }, {\n key: \"add\",\n value: function add(val) {\n var o = this._obj;\n\n if (o[val] !== 1) {\n o[val] = 1;\n this.size++;\n }\n }\n }, {\n key: \"delete\",\n value: function _delete(val) {\n var o = this._obj;\n\n if (o[val] === 1) {\n o[val] = 0;\n this.size--;\n }\n }\n }, {\n key: \"clear\",\n value: function clear() {\n this._obj = Object.create(null);\n }\n }, {\n key: \"has\",\n value: function has(val) {\n return this._obj[val] === 1;\n }\n }, {\n key: \"toArray\",\n value: function toArray() {\n var _this = this;\n\n return Object.keys(this._obj).filter(function (key) {\n return _this.has(key);\n });\n }\n }, {\n key: \"forEach\",\n value: function forEach(callback, thisArg) {\n return this.toArray().forEach(callback, thisArg);\n }\n }]);\n\n return ObjectSet;\n }();\n\n var Set$1 = (typeof Set === \"undefined\" ? \"undefined\" : _typeof(Set)) !== undef ? Set : ObjectSet;\n\n var Element = function Element(cy, params) {\n var restore = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n if (cy === undefined || params === undefined || !core(cy)) {\n error('An element must have a core reference and parameters set');\n return;\n }\n\n var group = params.group; // try to automatically infer the group if unspecified\n\n if (group == null) {\n if (params.data && params.data.source != null && params.data.target != null) {\n group = 'edges';\n } else {\n group = 'nodes';\n }\n } // validate group\n\n\n if (group !== 'nodes' && group !== 'edges') {\n error('An element must be of type `nodes` or `edges`; you specified `' + group + '`');\n return;\n } // make the element array-like, just like a collection\n\n\n this.length = 1;\n this[0] = this; // NOTE: when something is added here, add also to ele.json()\n\n var _p = this._private = {\n cy: cy,\n single: true,\n // indicates this is an element\n data: params.data || {},\n // data object\n position: params.position || {\n x: 0,\n y: 0\n },\n // (x, y) position pair\n autoWidth: undefined,\n // width and height of nodes calculated by the renderer when set to special 'auto' value\n autoHeight: undefined,\n autoPadding: undefined,\n compoundBoundsClean: false,\n // whether the compound dimensions need to be recalculated the next time dimensions are read\n listeners: [],\n // array of bound listeners\n group: group,\n // string; 'nodes' or 'edges'\n style: {},\n // properties as set by the style\n rstyle: {},\n // properties for style sent from the renderer to the core\n styleCxts: [],\n // applied style contexts from the styler\n styleKeys: {},\n // per-group keys of style property values\n removed: true,\n // whether it's inside the vis; true if removed (set true here since we call restore)\n selected: params.selected ? true : false,\n // whether it's selected\n selectable: params.selectable === undefined ? true : params.selectable ? true : false,\n // whether it's selectable\n locked: params.locked ? true : false,\n // whether the element is locked (cannot be moved)\n grabbed: false,\n // whether the element is grabbed by the mouse; renderer sets this privately\n grabbable: params.grabbable === undefined ? true : params.grabbable ? true : false,\n // whether the element can be grabbed\n pannable: params.pannable === undefined ? group === 'edges' ? true : false : params.pannable ? true : false,\n // whether the element has passthrough panning enabled\n active: false,\n // whether the element is active from user interaction\n classes: new Set$1(),\n // map ( className => true )\n animation: {\n // object for currently-running animations\n current: [],\n queue: []\n },\n rscratch: {},\n // object in which the renderer can store information\n scratch: params.scratch || {},\n // scratch objects\n edges: [],\n // array of connected edges\n children: [],\n // array of children\n parent: params.parent && params.parent.isNode() ? params.parent : null,\n // parent ref\n traversalCache: {},\n // cache of output of traversal functions\n backgrounding: false,\n // whether background images are loading\n bbCache: null,\n // cache of the current bounding box\n bbCacheShift: {\n x: 0,\n y: 0\n },\n // shift applied to cached bb to be applied on next get\n bodyBounds: null,\n // bounds cache of element body, w/o overlay\n overlayBounds: null,\n // bounds cache of element body, including overlay\n labelBounds: {\n // bounds cache of labels\n all: null,\n source: null,\n target: null,\n main: null\n },\n arrowBounds: {\n // bounds cache of edge arrows\n source: null,\n target: null,\n 'mid-source': null,\n 'mid-target': null\n }\n };\n\n if (_p.position.x == null) {\n _p.position.x = 0;\n }\n\n if (_p.position.y == null) {\n _p.position.y = 0;\n } // renderedPosition overrides if specified\n\n\n if (params.renderedPosition) {\n var rpos = params.renderedPosition;\n var pan = cy.pan();\n var zoom = cy.zoom();\n _p.position = {\n x: (rpos.x - pan.x) / zoom,\n y: (rpos.y - pan.y) / zoom\n };\n }\n\n var classes = [];\n\n if (array(params.classes)) {\n classes = params.classes;\n } else if (string(params.classes)) {\n classes = params.classes.split(/\\s+/);\n }\n\n for (var i = 0, l = classes.length; i < l; i++) {\n var cls = classes[i];\n\n if (!cls || cls === '') {\n continue;\n }\n\n _p.classes.add(cls);\n }\n\n this.createEmitter();\n var bypass = params.style || params.css;\n\n if (bypass) {\n warn('Setting a `style` bypass at element creation should be done only when absolutely necessary. Try to use the stylesheet instead.');\n this.style(bypass);\n }\n\n if (restore === undefined || restore) {\n this.restore();\n }\n };\n\n var defineSearch = function defineSearch(params) {\n params = {\n bfs: params.bfs || !params.dfs,\n dfs: params.dfs || !params.bfs\n }; // from pseudocode on wikipedia\n\n return function searchFn(roots, fn, directed) {\n var options;\n\n if (plainObject(roots) && !elementOrCollection(roots)) {\n options = roots;\n roots = options.roots || options.root;\n fn = options.visit;\n directed = options.directed;\n }\n\n directed = arguments.length === 2 && !fn$6(fn) ? fn : directed;\n fn = fn$6(fn) ? fn : function () {};\n var cy = this._private.cy;\n var v = roots = string(roots) ? this.filter(roots) : roots;\n var Q = [];\n var connectedNodes = [];\n var connectedBy = {};\n var id2depth = {};\n var V = {};\n var j = 0;\n var found;\n\n var _this$byGroup = this.byGroup(),\n nodes = _this$byGroup.nodes,\n edges = _this$byGroup.edges; // enqueue v\n\n\n for (var i = 0; i < v.length; i++) {\n var vi = v[i];\n var viId = vi.id();\n\n if (vi.isNode()) {\n Q.unshift(vi);\n\n if (params.bfs) {\n V[viId] = true;\n connectedNodes.push(vi);\n }\n\n id2depth[viId] = 0;\n }\n }\n\n var _loop = function _loop() {\n var v = params.bfs ? Q.shift() : Q.pop();\n var vId = v.id();\n\n if (params.dfs) {\n if (V[vId]) {\n return \"continue\";\n }\n\n V[vId] = true;\n connectedNodes.push(v);\n }\n\n var depth = id2depth[vId];\n var prevEdge = connectedBy[vId];\n var src = prevEdge != null ? prevEdge.source() : null;\n var tgt = prevEdge != null ? prevEdge.target() : null;\n var prevNode = prevEdge == null ? undefined : v.same(src) ? tgt[0] : src[0];\n var ret = void 0;\n ret = fn(v, prevEdge, prevNode, j++, depth);\n\n if (ret === true) {\n found = v;\n return \"break\";\n }\n\n if (ret === false) {\n return \"break\";\n }\n\n var vwEdges = v.connectedEdges().filter(function (e) {\n return (!directed || e.source().same(v)) && edges.has(e);\n });\n\n for (var _i2 = 0; _i2 < vwEdges.length; _i2++) {\n var e = vwEdges[_i2];\n var w = e.connectedNodes().filter(function (n) {\n return !n.same(v) && nodes.has(n);\n });\n var wId = w.id();\n\n if (w.length !== 0 && !V[wId]) {\n w = w[0];\n Q.push(w);\n\n if (params.bfs) {\n V[wId] = true;\n connectedNodes.push(w);\n }\n\n connectedBy[wId] = e;\n id2depth[wId] = id2depth[vId] + 1;\n }\n }\n };\n\n while (Q.length !== 0) {\n var _ret = _loop();\n\n if (_ret === \"continue\") continue;\n if (_ret === \"break\") break;\n }\n\n var connectedEles = cy.collection();\n\n for (var _i = 0; _i < connectedNodes.length; _i++) {\n var node = connectedNodes[_i];\n var edge = connectedBy[node.id()];\n\n if (edge != null) {\n connectedEles.push(edge);\n }\n\n connectedEles.push(node);\n }\n\n return {\n path: cy.collection(connectedEles),\n found: cy.collection(found)\n };\n };\n }; // search, spanning trees, etc\n\n\n var elesfn$v = {\n breadthFirstSearch: defineSearch({\n bfs: true\n }),\n depthFirstSearch: defineSearch({\n dfs: true\n })\n }; // nice, short mathematical alias\n\n elesfn$v.bfs = elesfn$v.breadthFirstSearch;\n elesfn$v.dfs = elesfn$v.depthFirstSearch;\n\n var heap$1 = createCommonjsModule(function (module, exports) {\n // Generated by CoffeeScript 1.8.0\n (function() {\n var Heap, defaultCmp, floor, heapify, heappop, heappush, heappushpop, heapreplace, insort, min, nlargest, nsmallest, updateItem, _siftdown, _siftup;\n\n floor = Math.floor, min = Math.min;\n\n\n /*\n Default comparison function to be used\n */\n\n defaultCmp = function(x, y) {\n if (x < y) {\n return -1;\n }\n if (x > y) {\n return 1;\n }\n return 0;\n };\n\n\n /*\n Insert item x in list a, and keep it sorted assuming a is sorted.\n \n If x is already in a, insert it to the right of the rightmost x.\n \n Optional args lo (default 0) and hi (default a.length) bound the slice\n of a to be searched.\n */\n\n insort = function(a, x, lo, hi, cmp) {\n var mid;\n if (lo == null) {\n lo = 0;\n }\n if (cmp == null) {\n cmp = defaultCmp;\n }\n if (lo < 0) {\n throw new Error('lo must be non-negative');\n }\n if (hi == null) {\n hi = a.length;\n }\n while (lo < hi) {\n mid = floor((lo + hi) / 2);\n if (cmp(x, a[mid]) < 0) {\n hi = mid;\n } else {\n lo = mid + 1;\n }\n }\n return ([].splice.apply(a, [lo, lo - lo].concat(x)), x);\n };\n\n\n /*\n Push item onto heap, maintaining the heap invariant.\n */\n\n heappush = function(array, item, cmp) {\n if (cmp == null) {\n cmp = defaultCmp;\n }\n array.push(item);\n return _siftdown(array, 0, array.length - 1, cmp);\n };\n\n\n /*\n Pop the smallest item off the heap, maintaining the heap invariant.\n */\n\n heappop = function(array, cmp) {\n var lastelt, returnitem;\n if (cmp == null) {\n cmp = defaultCmp;\n }\n lastelt = array.pop();\n if (array.length) {\n returnitem = array[0];\n array[0] = lastelt;\n _siftup(array, 0, cmp);\n } else {\n returnitem = lastelt;\n }\n return returnitem;\n };\n\n\n /*\n Pop and return the current smallest value, and add the new item.\n \n This is more efficient than heappop() followed by heappush(), and can be\n more appropriate when using a fixed size heap. Note that the value\n returned may be larger than item! That constrains reasonable use of\n this routine unless written as part of a conditional replacement:\n if item > array[0]\n item = heapreplace(array, item)\n */\n\n heapreplace = function(array, item, cmp) {\n var returnitem;\n if (cmp == null) {\n cmp = defaultCmp;\n }\n returnitem = array[0];\n array[0] = item;\n _siftup(array, 0, cmp);\n return returnitem;\n };\n\n\n /*\n Fast version of a heappush followed by a heappop.\n */\n\n heappushpop = function(array, item, cmp) {\n var _ref;\n if (cmp == null) {\n cmp = defaultCmp;\n }\n if (array.length && cmp(array[0], item) < 0) {\n _ref = [array[0], item], item = _ref[0], array[0] = _ref[1];\n _siftup(array, 0, cmp);\n }\n return item;\n };\n\n\n /*\n Transform list into a heap, in-place, in O(array.length) time.\n */\n\n heapify = function(array, cmp) {\n var i, _i, _len, _ref1, _results, _results1;\n if (cmp == null) {\n cmp = defaultCmp;\n }\n _ref1 = (function() {\n _results1 = [];\n for (var _j = 0, _ref = floor(array.length / 2); 0 <= _ref ? _j < _ref : _j > _ref; 0 <= _ref ? _j++ : _j--){ _results1.push(_j); }\n return _results1;\n }).apply(this).reverse();\n _results = [];\n for (_i = 0, _len = _ref1.length; _i < _len; _i++) {\n i = _ref1[_i];\n _results.push(_siftup(array, i, cmp));\n }\n return _results;\n };\n\n\n /*\n Update the position of the given item in the heap.\n This function should be called every time the item is being modified.\n */\n\n updateItem = function(array, item, cmp) {\n var pos;\n if (cmp == null) {\n cmp = defaultCmp;\n }\n pos = array.indexOf(item);\n if (pos === -1) {\n return;\n }\n _siftdown(array, 0, pos, cmp);\n return _siftup(array, pos, cmp);\n };\n\n\n /*\n Find the n largest elements in a dataset.\n */\n\n nlargest = function(array, n, cmp) {\n var elem, result, _i, _len, _ref;\n if (cmp == null) {\n cmp = defaultCmp;\n }\n result = array.slice(0, n);\n if (!result.length) {\n return result;\n }\n heapify(result, cmp);\n _ref = array.slice(n);\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n elem = _ref[_i];\n heappushpop(result, elem, cmp);\n }\n return result.sort(cmp).reverse();\n };\n\n\n /*\n Find the n smallest elements in a dataset.\n */\n\n nsmallest = function(array, n, cmp) {\n var elem, los, result, _i, _j, _len, _ref, _ref1, _results;\n if (cmp == null) {\n cmp = defaultCmp;\n }\n if (n * 10 <= array.length) {\n result = array.slice(0, n).sort(cmp);\n if (!result.length) {\n return result;\n }\n los = result[result.length - 1];\n _ref = array.slice(n);\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n elem = _ref[_i];\n if (cmp(elem, los) < 0) {\n insort(result, elem, 0, null, cmp);\n result.pop();\n los = result[result.length - 1];\n }\n }\n return result;\n }\n heapify(array, cmp);\n _results = [];\n for (_j = 0, _ref1 = min(n, array.length); 0 <= _ref1 ? _j < _ref1 : _j > _ref1; 0 <= _ref1 ? ++_j : --_j) {\n _results.push(heappop(array, cmp));\n }\n return _results;\n };\n\n _siftdown = function(array, startpos, pos, cmp) {\n var newitem, parent, parentpos;\n if (cmp == null) {\n cmp = defaultCmp;\n }\n newitem = array[pos];\n while (pos > startpos) {\n parentpos = (pos - 1) >> 1;\n parent = array[parentpos];\n if (cmp(newitem, parent) < 0) {\n array[pos] = parent;\n pos = parentpos;\n continue;\n }\n break;\n }\n return array[pos] = newitem;\n };\n\n _siftup = function(array, pos, cmp) {\n var childpos, endpos, newitem, rightpos, startpos;\n if (cmp == null) {\n cmp = defaultCmp;\n }\n endpos = array.length;\n startpos = pos;\n newitem = array[pos];\n childpos = 2 * pos + 1;\n while (childpos < endpos) {\n rightpos = childpos + 1;\n if (rightpos < endpos && !(cmp(array[childpos], array[rightpos]) < 0)) {\n childpos = rightpos;\n }\n array[pos] = array[childpos];\n pos = childpos;\n childpos = 2 * pos + 1;\n }\n array[pos] = newitem;\n return _siftdown(array, startpos, pos, cmp);\n };\n\n Heap = (function() {\n Heap.push = heappush;\n\n Heap.pop = heappop;\n\n Heap.replace = heapreplace;\n\n Heap.pushpop = heappushpop;\n\n Heap.heapify = heapify;\n\n Heap.updateItem = updateItem;\n\n Heap.nlargest = nlargest;\n\n Heap.nsmallest = nsmallest;\n\n function Heap(cmp) {\n this.cmp = cmp != null ? cmp : defaultCmp;\n this.nodes = [];\n }\n\n Heap.prototype.push = function(x) {\n return heappush(this.nodes, x, this.cmp);\n };\n\n Heap.prototype.pop = function() {\n return heappop(this.nodes, this.cmp);\n };\n\n Heap.prototype.peek = function() {\n return this.nodes[0];\n };\n\n Heap.prototype.contains = function(x) {\n return this.nodes.indexOf(x) !== -1;\n };\n\n Heap.prototype.replace = function(x) {\n return heapreplace(this.nodes, x, this.cmp);\n };\n\n Heap.prototype.pushpop = function(x) {\n return heappushpop(this.nodes, x, this.cmp);\n };\n\n Heap.prototype.heapify = function() {\n return heapify(this.nodes, this.cmp);\n };\n\n Heap.prototype.updateItem = function(x) {\n return updateItem(this.nodes, x, this.cmp);\n };\n\n Heap.prototype.clear = function() {\n return this.nodes = [];\n };\n\n Heap.prototype.empty = function() {\n return this.nodes.length === 0;\n };\n\n Heap.prototype.size = function() {\n return this.nodes.length;\n };\n\n Heap.prototype.clone = function() {\n var heap;\n heap = new Heap();\n heap.nodes = this.nodes.slice(0);\n return heap;\n };\n\n Heap.prototype.toArray = function() {\n return this.nodes.slice(0);\n };\n\n Heap.prototype.insert = Heap.prototype.push;\n\n Heap.prototype.top = Heap.prototype.peek;\n\n Heap.prototype.front = Heap.prototype.peek;\n\n Heap.prototype.has = Heap.prototype.contains;\n\n Heap.prototype.copy = Heap.prototype.clone;\n\n return Heap;\n\n })();\n\n (function(root, factory) {\n {\n return module.exports = factory();\n }\n })(this, function() {\n return Heap;\n });\n\n }).call(commonjsGlobal);\n });\n\n var heap = heap$1;\n\n var dijkstraDefaults = defaults$g({\n root: null,\n weight: function weight(edge) {\n return 1;\n },\n directed: false\n });\n var elesfn$u = {\n dijkstra: function dijkstra(options) {\n if (!plainObject(options)) {\n var args = arguments;\n options = {\n root: args[0],\n weight: args[1],\n directed: args[2]\n };\n }\n\n var _dijkstraDefaults = dijkstraDefaults(options),\n root = _dijkstraDefaults.root,\n weight = _dijkstraDefaults.weight,\n directed = _dijkstraDefaults.directed;\n\n var eles = this;\n var weightFn = weight;\n var source = string(root) ? this.filter(root)[0] : root[0];\n var dist = {};\n var prev = {};\n var knownDist = {};\n\n var _this$byGroup = this.byGroup(),\n nodes = _this$byGroup.nodes,\n edges = _this$byGroup.edges;\n\n edges.unmergeBy(function (ele) {\n return ele.isLoop();\n });\n\n var getDist = function getDist(node) {\n return dist[node.id()];\n };\n\n var setDist = function setDist(node, d) {\n dist[node.id()] = d;\n Q.updateItem(node);\n };\n\n var Q = new heap(function (a, b) {\n return getDist(a) - getDist(b);\n });\n\n for (var i = 0; i < nodes.length; i++) {\n var node = nodes[i];\n dist[node.id()] = node.same(source) ? 0 : Infinity;\n Q.push(node);\n }\n\n var distBetween = function distBetween(u, v) {\n var uvs = (directed ? u.edgesTo(v) : u.edgesWith(v)).intersect(edges);\n var smallestDistance = Infinity;\n var smallestEdge;\n\n for (var _i = 0; _i < uvs.length; _i++) {\n var edge = uvs[_i];\n\n var _weight = weightFn(edge);\n\n if (_weight < smallestDistance || !smallestEdge) {\n smallestDistance = _weight;\n smallestEdge = edge;\n }\n }\n\n return {\n edge: smallestEdge,\n dist: smallestDistance\n };\n };\n\n while (Q.size() > 0) {\n var u = Q.pop();\n var smalletsDist = getDist(u);\n var uid = u.id();\n knownDist[uid] = smalletsDist;\n\n if (smalletsDist === Infinity) {\n continue;\n }\n\n var neighbors = u.neighborhood().intersect(nodes);\n\n for (var _i2 = 0; _i2 < neighbors.length; _i2++) {\n var v = neighbors[_i2];\n var vid = v.id();\n var vDist = distBetween(u, v);\n var alt = smalletsDist + vDist.dist;\n\n if (alt < getDist(v)) {\n setDist(v, alt);\n prev[vid] = {\n node: u,\n edge: vDist.edge\n };\n }\n } // for\n\n } // while\n\n\n return {\n distanceTo: function distanceTo(node) {\n var target = string(node) ? nodes.filter(node)[0] : node[0];\n return knownDist[target.id()];\n },\n pathTo: function pathTo(node) {\n var target = string(node) ? nodes.filter(node)[0] : node[0];\n var S = [];\n var u = target;\n var uid = u.id();\n\n if (target.length > 0) {\n S.unshift(target);\n\n while (prev[uid]) {\n var p = prev[uid];\n S.unshift(p.edge);\n S.unshift(p.node);\n u = p.node;\n uid = u.id();\n }\n }\n\n return eles.spawn(S);\n }\n };\n }\n };\n\n var elesfn$t = {\n // kruskal's algorithm (finds min spanning tree, assuming undirected graph)\n // implemented from pseudocode from wikipedia\n kruskal: function kruskal(weightFn) {\n weightFn = weightFn || function (edge) {\n return 1;\n };\n\n var _this$byGroup = this.byGroup(),\n nodes = _this$byGroup.nodes,\n edges = _this$byGroup.edges;\n\n var numNodes = nodes.length;\n var forest = new Array(numNodes);\n var A = nodes; // assumes byGroup() creates new collections that can be safely mutated\n\n var findSetIndex = function findSetIndex(ele) {\n for (var i = 0; i < forest.length; i++) {\n var eles = forest[i];\n\n if (eles.has(ele)) {\n return i;\n }\n }\n }; // start with one forest per node\n\n\n for (var i = 0; i < numNodes; i++) {\n forest[i] = this.spawn(nodes[i]);\n }\n\n var S = edges.sort(function (a, b) {\n return weightFn(a) - weightFn(b);\n });\n\n for (var _i = 0; _i < S.length; _i++) {\n var edge = S[_i];\n var u = edge.source()[0];\n var v = edge.target()[0];\n var setUIndex = findSetIndex(u);\n var setVIndex = findSetIndex(v);\n var setU = forest[setUIndex];\n var setV = forest[setVIndex];\n\n if (setUIndex !== setVIndex) {\n A.merge(edge); // combine forests for u and v\n\n setU.merge(setV);\n forest.splice(setVIndex, 1);\n }\n }\n\n return A;\n }\n };\n\n var aStarDefaults = defaults$g({\n root: null,\n goal: null,\n weight: function weight(edge) {\n return 1;\n },\n heuristic: function heuristic(edge) {\n return 0;\n },\n directed: false\n });\n var elesfn$s = {\n // Implemented from pseudocode from wikipedia\n aStar: function aStar(options) {\n var cy = this.cy();\n\n var _aStarDefaults = aStarDefaults(options),\n root = _aStarDefaults.root,\n goal = _aStarDefaults.goal,\n heuristic = _aStarDefaults.heuristic,\n directed = _aStarDefaults.directed,\n weight = _aStarDefaults.weight;\n\n root = cy.collection(root)[0];\n goal = cy.collection(goal)[0];\n var sid = root.id();\n var tid = goal.id();\n var gScore = {};\n var fScore = {};\n var closedSetIds = {};\n var openSet = new heap(function (a, b) {\n return fScore[a.id()] - fScore[b.id()];\n });\n var openSetIds = new Set$1();\n var cameFrom = {};\n var cameFromEdge = {};\n\n var addToOpenSet = function addToOpenSet(ele, id) {\n openSet.push(ele);\n openSetIds.add(id);\n };\n\n var cMin, cMinId;\n\n var popFromOpenSet = function popFromOpenSet() {\n cMin = openSet.pop();\n cMinId = cMin.id();\n openSetIds[\"delete\"](cMinId);\n };\n\n var isInOpenSet = function isInOpenSet(id) {\n return openSetIds.has(id);\n };\n\n addToOpenSet(root, sid);\n gScore[sid] = 0;\n fScore[sid] = heuristic(root); // Counter\n\n var steps = 0; // Main loop\n\n while (openSet.size() > 0) {\n popFromOpenSet();\n steps++; // If we've found our goal, then we are done\n\n if (cMinId === tid) {\n var path = [];\n var pathNode = goal;\n var pathNodeId = tid;\n var pathEdge = cameFromEdge[pathNodeId];\n\n for (;;) {\n path.unshift(pathNode);\n\n if (pathEdge != null) {\n path.unshift(pathEdge);\n }\n\n pathNode = cameFrom[pathNodeId];\n\n if (pathNode == null) {\n break;\n }\n\n pathNodeId = pathNode.id();\n pathEdge = cameFromEdge[pathNodeId];\n }\n\n return {\n found: true,\n distance: gScore[cMinId],\n path: this.spawn(path),\n steps: steps\n };\n } // Add cMin to processed nodes\n\n\n closedSetIds[cMinId] = true; // Update scores for neighbors of cMin\n // Take into account if graph is directed or not\n\n var vwEdges = cMin._private.edges;\n\n for (var i = 0; i < vwEdges.length; i++) {\n var e = vwEdges[i]; // edge must be in set of calling eles\n\n if (!this.hasElementWithId(e.id())) {\n continue;\n } // cMin must be the source of edge if directed\n\n\n if (directed && e.data('source') !== cMinId) {\n continue;\n }\n\n var wSrc = e.source();\n var wTgt = e.target();\n var w = wSrc.id() !== cMinId ? wSrc : wTgt;\n var wid = w.id(); // node must be in set of calling eles\n\n if (!this.hasElementWithId(wid)) {\n continue;\n } // if node is in closedSet, ignore it\n\n\n if (closedSetIds[wid]) {\n continue;\n } // New tentative score for node w\n\n\n var tempScore = gScore[cMinId] + weight(e); // Update gScore for node w if:\n // w not present in openSet\n // OR\n // tentative gScore is less than previous value\n // w not in openSet\n\n if (!isInOpenSet(wid)) {\n gScore[wid] = tempScore;\n fScore[wid] = tempScore + heuristic(w);\n addToOpenSet(w, wid);\n cameFrom[wid] = cMin;\n cameFromEdge[wid] = e;\n continue;\n } // w already in openSet, but with greater gScore\n\n\n if (tempScore < gScore[wid]) {\n gScore[wid] = tempScore;\n fScore[wid] = tempScore + heuristic(w);\n cameFrom[wid] = cMin;\n cameFromEdge[wid] = e;\n }\n } // End of neighbors update\n\n } // End of main loop\n // If we've reached here, then we've not reached our goal\n\n\n return {\n found: false,\n distance: undefined,\n path: undefined,\n steps: steps\n };\n }\n }; // elesfn\n\n var floydWarshallDefaults = defaults$g({\n weight: function weight(edge) {\n return 1;\n },\n directed: false\n });\n var elesfn$r = {\n // Implemented from pseudocode from wikipedia\n floydWarshall: function floydWarshall(options) {\n var cy = this.cy();\n\n var _floydWarshallDefault = floydWarshallDefaults(options),\n weight = _floydWarshallDefault.weight,\n directed = _floydWarshallDefault.directed;\n\n var weightFn = weight;\n\n var _this$byGroup = this.byGroup(),\n nodes = _this$byGroup.nodes,\n edges = _this$byGroup.edges;\n\n var N = nodes.length;\n var Nsq = N * N;\n\n var indexOf = function indexOf(node) {\n return nodes.indexOf(node);\n };\n\n var atIndex = function atIndex(i) {\n return nodes[i];\n }; // Initialize distance matrix\n\n\n var dist = new Array(Nsq);\n\n for (var n = 0; n < Nsq; n++) {\n var j = n % N;\n var i = (n - j) / N;\n\n if (i === j) {\n dist[n] = 0;\n } else {\n dist[n] = Infinity;\n }\n } // Initialize matrix used for path reconstruction\n // Initialize distance matrix\n\n\n var next = new Array(Nsq);\n var edgeNext = new Array(Nsq); // Process edges\n\n for (var _i = 0; _i < edges.length; _i++) {\n var edge = edges[_i];\n var src = edge.source()[0];\n var tgt = edge.target()[0];\n\n if (src === tgt) {\n continue;\n } // exclude loops\n\n\n var s = indexOf(src);\n var t = indexOf(tgt);\n var st = s * N + t; // source to target index\n\n var _weight = weightFn(edge); // Check if already process another edge between same 2 nodes\n\n\n if (dist[st] > _weight) {\n dist[st] = _weight;\n next[st] = t;\n edgeNext[st] = edge;\n } // If undirected graph, process 'reversed' edge\n\n\n if (!directed) {\n var ts = t * N + s; // target to source index\n\n if (!directed && dist[ts] > _weight) {\n dist[ts] = _weight;\n next[ts] = s;\n edgeNext[ts] = edge;\n }\n }\n } // Main loop\n\n\n for (var k = 0; k < N; k++) {\n for (var _i2 = 0; _i2 < N; _i2++) {\n var ik = _i2 * N + k;\n\n for (var _j = 0; _j < N; _j++) {\n var ij = _i2 * N + _j;\n var kj = k * N + _j;\n\n if (dist[ik] + dist[kj] < dist[ij]) {\n dist[ij] = dist[ik] + dist[kj];\n next[ij] = next[ik];\n }\n }\n }\n }\n\n var getArgEle = function getArgEle(ele) {\n return (string(ele) ? cy.filter(ele) : ele)[0];\n };\n\n var indexOfArgEle = function indexOfArgEle(ele) {\n return indexOf(getArgEle(ele));\n };\n\n var res = {\n distance: function distance(from, to) {\n var i = indexOfArgEle(from);\n var j = indexOfArgEle(to);\n return dist[i * N + j];\n },\n path: function path(from, to) {\n var i = indexOfArgEle(from);\n var j = indexOfArgEle(to);\n var fromNode = atIndex(i);\n\n if (i === j) {\n return fromNode.collection();\n }\n\n if (next[i * N + j] == null) {\n return cy.collection();\n }\n\n var path = cy.collection();\n var prev = i;\n var edge;\n path.merge(fromNode);\n\n while (i !== j) {\n prev = i;\n i = next[i * N + j];\n edge = edgeNext[prev * N + i];\n path.merge(edge);\n path.merge(atIndex(i));\n }\n\n return path;\n }\n };\n return res;\n } // floydWarshall\n\n }; // elesfn\n\n var bellmanFordDefaults = defaults$g({\n weight: function weight(edge) {\n return 1;\n },\n directed: false,\n root: null\n });\n var elesfn$q = {\n // Implemented from pseudocode from wikipedia\n bellmanFord: function bellmanFord(options) {\n var _this = this;\n\n var _bellmanFordDefaults = bellmanFordDefaults(options),\n weight = _bellmanFordDefaults.weight,\n directed = _bellmanFordDefaults.directed,\n root = _bellmanFordDefaults.root;\n\n var weightFn = weight;\n var eles = this;\n var cy = this.cy();\n\n var _this$byGroup = this.byGroup(),\n edges = _this$byGroup.edges,\n nodes = _this$byGroup.nodes;\n\n var numNodes = nodes.length;\n var infoMap = new Map$2();\n var hasNegativeWeightCycle = false;\n var negativeWeightCycles = [];\n root = cy.collection(root)[0]; // in case selector passed\n\n edges.unmergeBy(function (edge) {\n return edge.isLoop();\n });\n var numEdges = edges.length;\n\n var getInfo = function getInfo(node) {\n var obj = infoMap.get(node.id());\n\n if (!obj) {\n obj = {};\n infoMap.set(node.id(), obj);\n }\n\n return obj;\n };\n\n var getNodeFromTo = function getNodeFromTo(to) {\n return (string(to) ? cy.$(to) : to)[0];\n };\n\n var distanceTo = function distanceTo(to) {\n return getInfo(getNodeFromTo(to)).dist;\n };\n\n var pathTo = function pathTo(to) {\n var thisStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : root;\n var end = getNodeFromTo(to);\n var path = [];\n var node = end;\n\n for (;;) {\n if (node == null) {\n return _this.spawn();\n }\n\n var _getInfo = getInfo(node),\n edge = _getInfo.edge,\n pred = _getInfo.pred;\n\n path.unshift(node[0]);\n\n if (node.same(thisStart) && path.length > 0) {\n break;\n }\n\n if (edge != null) {\n path.unshift(edge);\n }\n\n node = pred;\n }\n\n return eles.spawn(path);\n }; // Initializations { dist, pred, edge }\n\n\n for (var i = 0; i < numNodes; i++) {\n var node = nodes[i];\n var info = getInfo(node);\n\n if (node.same(root)) {\n info.dist = 0;\n } else {\n info.dist = Infinity;\n }\n\n info.pred = null;\n info.edge = null;\n } // Edges relaxation\n\n\n var replacedEdge = false;\n\n var checkForEdgeReplacement = function checkForEdgeReplacement(node1, node2, edge, info1, info2, weight) {\n var dist = info1.dist + weight;\n\n if (dist < info2.dist && !edge.same(info1.edge)) {\n info2.dist = dist;\n info2.pred = node1;\n info2.edge = edge;\n replacedEdge = true;\n }\n };\n\n for (var _i = 1; _i < numNodes; _i++) {\n replacedEdge = false;\n\n for (var e = 0; e < numEdges; e++) {\n var edge = edges[e];\n var src = edge.source();\n var tgt = edge.target();\n\n var _weight = weightFn(edge);\n\n var srcInfo = getInfo(src);\n var tgtInfo = getInfo(tgt);\n checkForEdgeReplacement(src, tgt, edge, srcInfo, tgtInfo, _weight); // If undirected graph, we need to take into account the 'reverse' edge\n\n if (!directed) {\n checkForEdgeReplacement(tgt, src, edge, tgtInfo, srcInfo, _weight);\n }\n }\n\n if (!replacedEdge) {\n break;\n }\n }\n\n if (replacedEdge) {\n // Check for negative weight cycles\n var negativeWeightCycleIds = [];\n\n for (var _e = 0; _e < numEdges; _e++) {\n var _edge = edges[_e];\n\n var _src = _edge.source();\n\n var _tgt = _edge.target();\n\n var _weight2 = weightFn(_edge);\n\n var srcDist = getInfo(_src).dist;\n var tgtDist = getInfo(_tgt).dist;\n\n if (srcDist + _weight2 < tgtDist || !directed && tgtDist + _weight2 < srcDist) {\n if (!hasNegativeWeightCycle) {\n warn('Graph contains a negative weight cycle for Bellman-Ford');\n hasNegativeWeightCycle = true;\n }\n\n if (options.findNegativeWeightCycles !== false) {\n var negativeNodes = [];\n\n if (srcDist + _weight2 < tgtDist) {\n negativeNodes.push(_src);\n }\n\n if (!directed && tgtDist + _weight2 < srcDist) {\n negativeNodes.push(_tgt);\n }\n\n var numNegativeNodes = negativeNodes.length;\n\n for (var n = 0; n < numNegativeNodes; n++) {\n var start = negativeNodes[n];\n var cycle = [start];\n cycle.push(getInfo(start).edge);\n var _node = getInfo(start).pred;\n\n while (cycle.indexOf(_node) === -1) {\n cycle.push(_node);\n cycle.push(getInfo(_node).edge);\n _node = getInfo(_node).pred;\n }\n\n cycle = cycle.slice(cycle.indexOf(_node));\n var smallestId = cycle[0].id();\n var smallestIndex = 0;\n\n for (var c = 2; c < cycle.length; c += 2) {\n if (cycle[c].id() < smallestId) {\n smallestId = cycle[c].id();\n smallestIndex = c;\n }\n }\n\n cycle = cycle.slice(smallestIndex).concat(cycle.slice(0, smallestIndex));\n cycle.push(cycle[0]);\n var cycleId = cycle.map(function (el) {\n return el.id();\n }).join(\",\");\n\n if (negativeWeightCycleIds.indexOf(cycleId) === -1) {\n negativeWeightCycles.push(eles.spawn(cycle));\n negativeWeightCycleIds.push(cycleId);\n }\n }\n } else {\n break;\n }\n }\n }\n }\n\n return {\n distanceTo: distanceTo,\n pathTo: pathTo,\n hasNegativeWeightCycle: hasNegativeWeightCycle,\n negativeWeightCycles: negativeWeightCycles\n };\n } // bellmanFord\n\n }; // elesfn\n\n var sqrt2 = Math.sqrt(2); // Function which colapses 2 (meta) nodes into one\n // Updates the remaining edge lists\n // Receives as a paramater the edge which causes the collapse\n\n var collapse = function collapse(edgeIndex, nodeMap, remainingEdges) {\n if (remainingEdges.length === 0) {\n error(\"Karger-Stein must be run on a connected (sub)graph\");\n }\n\n var edgeInfo = remainingEdges[edgeIndex];\n var sourceIn = edgeInfo[1];\n var targetIn = edgeInfo[2];\n var partition1 = nodeMap[sourceIn];\n var partition2 = nodeMap[targetIn];\n var newEdges = remainingEdges; // re-use array\n // Delete all edges between partition1 and partition2\n\n for (var i = newEdges.length - 1; i >= 0; i--) {\n var edge = newEdges[i];\n var src = edge[1];\n var tgt = edge[2];\n\n if (nodeMap[src] === partition1 && nodeMap[tgt] === partition2 || nodeMap[src] === partition2 && nodeMap[tgt] === partition1) {\n newEdges.splice(i, 1);\n }\n } // All edges pointing to partition2 should now point to partition1\n\n\n for (var _i = 0; _i < newEdges.length; _i++) {\n var _edge = newEdges[_i];\n\n if (_edge[1] === partition2) {\n // Check source\n newEdges[_i] = _edge.slice(); // copy\n\n newEdges[_i][1] = partition1;\n } else if (_edge[2] === partition2) {\n // Check target\n newEdges[_i] = _edge.slice(); // copy\n\n newEdges[_i][2] = partition1;\n }\n } // Move all nodes from partition2 to partition1\n\n\n for (var _i2 = 0; _i2 < nodeMap.length; _i2++) {\n if (nodeMap[_i2] === partition2) {\n nodeMap[_i2] = partition1;\n }\n }\n\n return newEdges;\n }; // Contracts a graph until we reach a certain number of meta nodes\n\n\n var contractUntil = function contractUntil(metaNodeMap, remainingEdges, size, sizeLimit) {\n while (size > sizeLimit) {\n // Choose an edge randomly\n var edgeIndex = Math.floor(Math.random() * remainingEdges.length); // Collapse graph based on edge\n\n remainingEdges = collapse(edgeIndex, metaNodeMap, remainingEdges);\n size--;\n }\n\n return remainingEdges;\n };\n\n var elesfn$p = {\n // Computes the minimum cut of an undirected graph\n // Returns the correct answer with high probability\n kargerStein: function kargerStein() {\n var _this = this;\n\n var _this$byGroup = this.byGroup(),\n nodes = _this$byGroup.nodes,\n edges = _this$byGroup.edges;\n\n edges.unmergeBy(function (edge) {\n return edge.isLoop();\n });\n var numNodes = nodes.length;\n var numEdges = edges.length;\n var numIter = Math.ceil(Math.pow(Math.log(numNodes) / Math.LN2, 2));\n var stopSize = Math.floor(numNodes / sqrt2);\n\n if (numNodes < 2) {\n error('At least 2 nodes are required for Karger-Stein algorithm');\n return undefined;\n } // Now store edge destination as indexes\n // Format for each edge (edge index, source node index, target node index)\n\n\n var edgeIndexes = [];\n\n for (var i = 0; i < numEdges; i++) {\n var e = edges[i];\n edgeIndexes.push([i, nodes.indexOf(e.source()), nodes.indexOf(e.target())]);\n } // We will store the best cut found here\n\n\n var minCutSize = Infinity;\n var minCutEdgeIndexes = [];\n var minCutNodeMap = new Array(numNodes); // Initial meta node partition\n\n var metaNodeMap = new Array(numNodes);\n var metaNodeMap2 = new Array(numNodes);\n\n var copyNodesMap = function copyNodesMap(from, to) {\n for (var _i3 = 0; _i3 < numNodes; _i3++) {\n to[_i3] = from[_i3];\n }\n }; // Main loop\n\n\n for (var iter = 0; iter <= numIter; iter++) {\n // Reset meta node partition\n for (var _i4 = 0; _i4 < numNodes; _i4++) {\n metaNodeMap[_i4] = _i4;\n } // Contract until stop point (stopSize nodes)\n\n\n var edgesState = contractUntil(metaNodeMap, edgeIndexes.slice(), numNodes, stopSize);\n var edgesState2 = edgesState.slice(); // copy\n // Create a copy of the colapsed nodes state\n\n copyNodesMap(metaNodeMap, metaNodeMap2); // Run 2 iterations starting in the stop state\n\n var res1 = contractUntil(metaNodeMap, edgesState, stopSize, 2);\n var res2 = contractUntil(metaNodeMap2, edgesState2, stopSize, 2); // Is any of the 2 results the best cut so far?\n\n if (res1.length <= res2.length && res1.length < minCutSize) {\n minCutSize = res1.length;\n minCutEdgeIndexes = res1;\n copyNodesMap(metaNodeMap, minCutNodeMap);\n } else if (res2.length <= res1.length && res2.length < minCutSize) {\n minCutSize = res2.length;\n minCutEdgeIndexes = res2;\n copyNodesMap(metaNodeMap2, minCutNodeMap);\n }\n } // end of main loop\n // Construct result\n\n\n var cut = this.spawn(minCutEdgeIndexes.map(function (e) {\n return edges[e[0]];\n }));\n var partition1 = this.spawn();\n var partition2 = this.spawn(); // traverse metaNodeMap for best cut\n\n var witnessNodePartition = minCutNodeMap[0];\n\n for (var _i5 = 0; _i5 < minCutNodeMap.length; _i5++) {\n var partitionId = minCutNodeMap[_i5];\n var node = nodes[_i5];\n\n if (partitionId === witnessNodePartition) {\n partition1.merge(node);\n } else {\n partition2.merge(node);\n }\n } // construct components corresponding to each disjoint subset of nodes\n\n\n var constructComponent = function constructComponent(subset) {\n var component = _this.spawn();\n\n subset.forEach(function (node) {\n component.merge(node);\n node.connectedEdges().forEach(function (edge) {\n // ensure edge is within calling collection and edge is not in cut\n if (_this.contains(edge) && !cut.contains(edge)) {\n component.merge(edge);\n }\n });\n });\n return component;\n };\n\n var components = [constructComponent(partition1), constructComponent(partition2)];\n var ret = {\n cut: cut,\n components: components,\n // n.b. partitions are included to be compatible with the old api spec\n // (could be removed in a future major version)\n partition1: partition1,\n partition2: partition2\n };\n return ret;\n }\n }; // elesfn\n\n var copyPosition = function copyPosition(p) {\n return {\n x: p.x,\n y: p.y\n };\n };\n var modelToRenderedPosition = function modelToRenderedPosition(p, zoom, pan) {\n return {\n x: p.x * zoom + pan.x,\n y: p.y * zoom + pan.y\n };\n };\n var renderedToModelPosition = function renderedToModelPosition(p, zoom, pan) {\n return {\n x: (p.x - pan.x) / zoom,\n y: (p.y - pan.y) / zoom\n };\n };\n var array2point = function array2point(arr) {\n return {\n x: arr[0],\n y: arr[1]\n };\n };\n var min = function min(arr) {\n var begin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : arr.length;\n var min = Infinity;\n\n for (var i = begin; i < end; i++) {\n var val = arr[i];\n\n if (isFinite(val)) {\n min = Math.min(val, min);\n }\n }\n\n return min;\n };\n var max = function max(arr) {\n var begin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : arr.length;\n var max = -Infinity;\n\n for (var i = begin; i < end; i++) {\n var val = arr[i];\n\n if (isFinite(val)) {\n max = Math.max(val, max);\n }\n }\n\n return max;\n };\n var mean = function mean(arr) {\n var begin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : arr.length;\n var total = 0;\n var n = 0;\n\n for (var i = begin; i < end; i++) {\n var val = arr[i];\n\n if (isFinite(val)) {\n total += val;\n n++;\n }\n }\n\n return total / n;\n };\n var median = function median(arr) {\n var begin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : arr.length;\n var copy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;\n var sort = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;\n var includeHoles = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true;\n\n if (copy) {\n arr = arr.slice(begin, end);\n } else {\n if (end < arr.length) {\n arr.splice(end, arr.length - end);\n }\n\n if (begin > 0) {\n arr.splice(0, begin);\n }\n } // all non finite (e.g. Infinity, NaN) elements must be -Infinity so they go to the start\n\n\n var off = 0; // offset from non-finite values\n\n for (var i = arr.length - 1; i >= 0; i--) {\n var v = arr[i];\n\n if (includeHoles) {\n if (!isFinite(v)) {\n arr[i] = -Infinity;\n off++;\n }\n } else {\n // just remove it if we don't want to consider holes\n arr.splice(i, 1);\n }\n }\n\n if (sort) {\n arr.sort(function (a, b) {\n return a - b;\n }); // requires copy = true if you don't want to change the orig\n }\n\n var len = arr.length;\n var mid = Math.floor(len / 2);\n\n if (len % 2 !== 0) {\n return arr[mid + 1 + off];\n } else {\n return (arr[mid - 1 + off] + arr[mid + off]) / 2;\n }\n };\n var deg2rad = function deg2rad(deg) {\n return Math.PI * deg / 180;\n };\n var getAngleFromDisp = function getAngleFromDisp(dispX, dispY) {\n return Math.atan2(dispY, dispX) - Math.PI / 2;\n };\n var log2 = Math.log2 || function (n) {\n return Math.log(n) / Math.log(2);\n };\n var signum = function signum(x) {\n if (x > 0) {\n return 1;\n } else if (x < 0) {\n return -1;\n } else {\n return 0;\n }\n };\n var dist = function dist(p1, p2) {\n return Math.sqrt(sqdist(p1, p2));\n };\n var sqdist = function sqdist(p1, p2) {\n var dx = p2.x - p1.x;\n var dy = p2.y - p1.y;\n return dx * dx + dy * dy;\n };\n var inPlaceSumNormalize = function inPlaceSumNormalize(v) {\n var length = v.length; // First, get sum of all elements\n\n var total = 0;\n\n for (var i = 0; i < length; i++) {\n total += v[i];\n } // Now, divide each by the sum of all elements\n\n\n for (var _i = 0; _i < length; _i++) {\n v[_i] = v[_i] / total;\n }\n\n return v;\n };\n\n var qbezierAt = function qbezierAt(p0, p1, p2, t) {\n return (1 - t) * (1 - t) * p0 + 2 * (1 - t) * t * p1 + t * t * p2;\n };\n var qbezierPtAt = function qbezierPtAt(p0, p1, p2, t) {\n return {\n x: qbezierAt(p0.x, p1.x, p2.x, t),\n y: qbezierAt(p0.y, p1.y, p2.y, t)\n };\n };\n var lineAt = function lineAt(p0, p1, t, d) {\n var vec = {\n x: p1.x - p0.x,\n y: p1.y - p0.y\n };\n var vecDist = dist(p0, p1);\n var normVec = {\n x: vec.x / vecDist,\n y: vec.y / vecDist\n };\n t = t == null ? 0 : t;\n d = d != null ? d : t * vecDist;\n return {\n x: p0.x + normVec.x * d,\n y: p0.y + normVec.y * d\n };\n };\n var bound = function bound(min, val, max) {\n return Math.max(min, Math.min(max, val));\n }; // makes a full bb (x1, y1, x2, y2, w, h) from implicit params\n\n var makeBoundingBox = function makeBoundingBox(bb) {\n if (bb == null) {\n return {\n x1: Infinity,\n y1: Infinity,\n x2: -Infinity,\n y2: -Infinity,\n w: 0,\n h: 0\n };\n } else if (bb.x1 != null && bb.y1 != null) {\n if (bb.x2 != null && bb.y2 != null && bb.x2 >= bb.x1 && bb.y2 >= bb.y1) {\n return {\n x1: bb.x1,\n y1: bb.y1,\n x2: bb.x2,\n y2: bb.y2,\n w: bb.x2 - bb.x1,\n h: bb.y2 - bb.y1\n };\n } else if (bb.w != null && bb.h != null && bb.w >= 0 && bb.h >= 0) {\n return {\n x1: bb.x1,\n y1: bb.y1,\n x2: bb.x1 + bb.w,\n y2: bb.y1 + bb.h,\n w: bb.w,\n h: bb.h\n };\n }\n }\n };\n var copyBoundingBox = function copyBoundingBox(bb) {\n return {\n x1: bb.x1,\n x2: bb.x2,\n w: bb.w,\n y1: bb.y1,\n y2: bb.y2,\n h: bb.h\n };\n };\n var clearBoundingBox = function clearBoundingBox(bb) {\n bb.x1 = Infinity;\n bb.y1 = Infinity;\n bb.x2 = -Infinity;\n bb.y2 = -Infinity;\n bb.w = 0;\n bb.h = 0;\n };\n var updateBoundingBox = function updateBoundingBox(bb1, bb2) {\n // update bb1 with bb2 bounds\n bb1.x1 = Math.min(bb1.x1, bb2.x1);\n bb1.x2 = Math.max(bb1.x2, bb2.x2);\n bb1.w = bb1.x2 - bb1.x1;\n bb1.y1 = Math.min(bb1.y1, bb2.y1);\n bb1.y2 = Math.max(bb1.y2, bb2.y2);\n bb1.h = bb1.y2 - bb1.y1;\n };\n var expandBoundingBoxByPoint = function expandBoundingBoxByPoint(bb, x, y) {\n bb.x1 = Math.min(bb.x1, x);\n bb.x2 = Math.max(bb.x2, x);\n bb.w = bb.x2 - bb.x1;\n bb.y1 = Math.min(bb.y1, y);\n bb.y2 = Math.max(bb.y2, y);\n bb.h = bb.y2 - bb.y1;\n };\n var expandBoundingBox = function expandBoundingBox(bb) {\n var padding = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n bb.x1 -= padding;\n bb.x2 += padding;\n bb.y1 -= padding;\n bb.y2 += padding;\n bb.w = bb.x2 - bb.x1;\n bb.h = bb.y2 - bb.y1;\n return bb;\n };\n var expandBoundingBoxSides = function expandBoundingBoxSides(bb) {\n var padding = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [0];\n var top, right, bottom, left;\n\n if (padding.length === 1) {\n top = right = bottom = left = padding[0];\n } else if (padding.length === 2) {\n top = bottom = padding[0];\n left = right = padding[1];\n } else if (padding.length === 4) {\n var _padding = _slicedToArray(padding, 4);\n\n top = _padding[0];\n right = _padding[1];\n bottom = _padding[2];\n left = _padding[3];\n }\n\n bb.x1 -= left;\n bb.x2 += right;\n bb.y1 -= top;\n bb.y2 += bottom;\n bb.w = bb.x2 - bb.x1;\n bb.h = bb.y2 - bb.y1;\n return bb;\n };\n\n var assignBoundingBox = function assignBoundingBox(bb1, bb2) {\n bb1.x1 = bb2.x1;\n bb1.y1 = bb2.y1;\n bb1.x2 = bb2.x2;\n bb1.y2 = bb2.y2;\n bb1.w = bb1.x2 - bb1.x1;\n bb1.h = bb1.y2 - bb1.y1;\n };\n var boundingBoxesIntersect = function boundingBoxesIntersect(bb1, bb2) {\n // case: one bb to right of other\n if (bb1.x1 > bb2.x2) {\n return false;\n }\n\n if (bb2.x1 > bb1.x2) {\n return false;\n } // case: one bb to left of other\n\n\n if (bb1.x2 < bb2.x1) {\n return false;\n }\n\n if (bb2.x2 < bb1.x1) {\n return false;\n } // case: one bb above other\n\n\n if (bb1.y2 < bb2.y1) {\n return false;\n }\n\n if (bb2.y2 < bb1.y1) {\n return false;\n } // case: one bb below other\n\n\n if (bb1.y1 > bb2.y2) {\n return false;\n }\n\n if (bb2.y1 > bb1.y2) {\n return false;\n } // otherwise, must have some overlap\n\n\n return true;\n };\n var inBoundingBox = function inBoundingBox(bb, x, y) {\n return bb.x1 <= x && x <= bb.x2 && bb.y1 <= y && y <= bb.y2;\n };\n var pointInBoundingBox = function pointInBoundingBox(bb, pt) {\n return inBoundingBox(bb, pt.x, pt.y);\n };\n var boundingBoxInBoundingBox = function boundingBoxInBoundingBox(bb1, bb2) {\n return inBoundingBox(bb1, bb2.x1, bb2.y1) && inBoundingBox(bb1, bb2.x2, bb2.y2);\n };\n var roundRectangleIntersectLine = function roundRectangleIntersectLine(x, y, nodeX, nodeY, width, height, padding) {\n var cornerRadius = getRoundRectangleRadius(width, height);\n var halfWidth = width / 2;\n var halfHeight = height / 2; // Check intersections with straight line segments\n\n var straightLineIntersections; // Top segment, left to right\n\n {\n var topStartX = nodeX - halfWidth + cornerRadius - padding;\n var topStartY = nodeY - halfHeight - padding;\n var topEndX = nodeX + halfWidth - cornerRadius + padding;\n var topEndY = topStartY;\n straightLineIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, topStartX, topStartY, topEndX, topEndY, false);\n\n if (straightLineIntersections.length > 0) {\n return straightLineIntersections;\n }\n } // Right segment, top to bottom\n\n {\n var rightStartX = nodeX + halfWidth + padding;\n var rightStartY = nodeY - halfHeight + cornerRadius - padding;\n var rightEndX = rightStartX;\n var rightEndY = nodeY + halfHeight - cornerRadius + padding;\n straightLineIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, rightStartX, rightStartY, rightEndX, rightEndY, false);\n\n if (straightLineIntersections.length > 0) {\n return straightLineIntersections;\n }\n } // Bottom segment, left to right\n\n {\n var bottomStartX = nodeX - halfWidth + cornerRadius - padding;\n var bottomStartY = nodeY + halfHeight + padding;\n var bottomEndX = nodeX + halfWidth - cornerRadius + padding;\n var bottomEndY = bottomStartY;\n straightLineIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, bottomStartX, bottomStartY, bottomEndX, bottomEndY, false);\n\n if (straightLineIntersections.length > 0) {\n return straightLineIntersections;\n }\n } // Left segment, top to bottom\n\n {\n var leftStartX = nodeX - halfWidth - padding;\n var leftStartY = nodeY - halfHeight + cornerRadius - padding;\n var leftEndX = leftStartX;\n var leftEndY = nodeY + halfHeight - cornerRadius + padding;\n straightLineIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, leftStartX, leftStartY, leftEndX, leftEndY, false);\n\n if (straightLineIntersections.length > 0) {\n return straightLineIntersections;\n }\n } // Check intersections with arc segments\n\n var arcIntersections; // Top Left\n\n {\n var topLeftCenterX = nodeX - halfWidth + cornerRadius;\n var topLeftCenterY = nodeY - halfHeight + cornerRadius;\n arcIntersections = intersectLineCircle(x, y, nodeX, nodeY, topLeftCenterX, topLeftCenterY, cornerRadius + padding); // Ensure the intersection is on the desired quarter of the circle\n\n if (arcIntersections.length > 0 && arcIntersections[0] <= topLeftCenterX && arcIntersections[1] <= topLeftCenterY) {\n return [arcIntersections[0], arcIntersections[1]];\n }\n } // Top Right\n\n {\n var topRightCenterX = nodeX + halfWidth - cornerRadius;\n var topRightCenterY = nodeY - halfHeight + cornerRadius;\n arcIntersections = intersectLineCircle(x, y, nodeX, nodeY, topRightCenterX, topRightCenterY, cornerRadius + padding); // Ensure the intersection is on the desired quarter of the circle\n\n if (arcIntersections.length > 0 && arcIntersections[0] >= topRightCenterX && arcIntersections[1] <= topRightCenterY) {\n return [arcIntersections[0], arcIntersections[1]];\n }\n } // Bottom Right\n\n {\n var bottomRightCenterX = nodeX + halfWidth - cornerRadius;\n var bottomRightCenterY = nodeY + halfHeight - cornerRadius;\n arcIntersections = intersectLineCircle(x, y, nodeX, nodeY, bottomRightCenterX, bottomRightCenterY, cornerRadius + padding); // Ensure the intersection is on the desired quarter of the circle\n\n if (arcIntersections.length > 0 && arcIntersections[0] >= bottomRightCenterX && arcIntersections[1] >= bottomRightCenterY) {\n return [arcIntersections[0], arcIntersections[1]];\n }\n } // Bottom Left\n\n {\n var bottomLeftCenterX = nodeX - halfWidth + cornerRadius;\n var bottomLeftCenterY = nodeY + halfHeight - cornerRadius;\n arcIntersections = intersectLineCircle(x, y, nodeX, nodeY, bottomLeftCenterX, bottomLeftCenterY, cornerRadius + padding); // Ensure the intersection is on the desired quarter of the circle\n\n if (arcIntersections.length > 0 && arcIntersections[0] <= bottomLeftCenterX && arcIntersections[1] >= bottomLeftCenterY) {\n return [arcIntersections[0], arcIntersections[1]];\n }\n }\n return []; // if nothing\n };\n var inLineVicinity = function inLineVicinity(x, y, lx1, ly1, lx2, ly2, tolerance) {\n var t = tolerance;\n var x1 = Math.min(lx1, lx2);\n var x2 = Math.max(lx1, lx2);\n var y1 = Math.min(ly1, ly2);\n var y2 = Math.max(ly1, ly2);\n return x1 - t <= x && x <= x2 + t && y1 - t <= y && y <= y2 + t;\n };\n var inBezierVicinity = function inBezierVicinity(x, y, x1, y1, x2, y2, x3, y3, tolerance) {\n var bb = {\n x1: Math.min(x1, x3, x2) - tolerance,\n x2: Math.max(x1, x3, x2) + tolerance,\n y1: Math.min(y1, y3, y2) - tolerance,\n y2: Math.max(y1, y3, y2) + tolerance\n }; // if outside the rough bounding box for the bezier, then it can't be a hit\n\n if (x < bb.x1 || x > bb.x2 || y < bb.y1 || y > bb.y2) {\n // console.log('bezier out of rough bb')\n return false;\n } else {\n // console.log('do more expensive check');\n return true;\n }\n };\n var solveQuadratic = function solveQuadratic(a, b, c, val) {\n c -= val;\n var r = b * b - 4 * a * c;\n\n if (r < 0) {\n return [];\n }\n\n var sqrtR = Math.sqrt(r);\n var denom = 2 * a;\n var root1 = (-b + sqrtR) / denom;\n var root2 = (-b - sqrtR) / denom;\n return [root1, root2];\n };\n var solveCubic = function solveCubic(a, b, c, d, result) {\n // Solves a cubic function, returns root in form [r1, i1, r2, i2, r3, i3], where\n // r is the real component, i is the imaginary component\n // An implementation of the Cardano method from the year 1545\n // http://en.wikipedia.org/wiki/Cubic_function#The_nature_of_the_roots\n var epsilon = 0.00001; // avoid division by zero while keeping the overall expression close in value\n\n if (a === 0) {\n a = epsilon;\n }\n\n b /= a;\n c /= a;\n d /= a;\n var discriminant, q, r, dum1, s, t, term1, r13;\n q = (3.0 * c - b * b) / 9.0;\n r = -(27.0 * d) + b * (9.0 * c - 2.0 * (b * b));\n r /= 54.0;\n discriminant = q * q * q + r * r;\n result[1] = 0;\n term1 = b / 3.0;\n\n if (discriminant > 0) {\n s = r + Math.sqrt(discriminant);\n s = s < 0 ? -Math.pow(-s, 1.0 / 3.0) : Math.pow(s, 1.0 / 3.0);\n t = r - Math.sqrt(discriminant);\n t = t < 0 ? -Math.pow(-t, 1.0 / 3.0) : Math.pow(t, 1.0 / 3.0);\n result[0] = -term1 + s + t;\n term1 += (s + t) / 2.0;\n result[4] = result[2] = -term1;\n term1 = Math.sqrt(3.0) * (-t + s) / 2;\n result[3] = term1;\n result[5] = -term1;\n return;\n }\n\n result[5] = result[3] = 0;\n\n if (discriminant === 0) {\n r13 = r < 0 ? -Math.pow(-r, 1.0 / 3.0) : Math.pow(r, 1.0 / 3.0);\n result[0] = -term1 + 2.0 * r13;\n result[4] = result[2] = -(r13 + term1);\n return;\n }\n\n q = -q;\n dum1 = q * q * q;\n dum1 = Math.acos(r / Math.sqrt(dum1));\n r13 = 2.0 * Math.sqrt(q);\n result[0] = -term1 + r13 * Math.cos(dum1 / 3.0);\n result[2] = -term1 + r13 * Math.cos((dum1 + 2.0 * Math.PI) / 3.0);\n result[4] = -term1 + r13 * Math.cos((dum1 + 4.0 * Math.PI) / 3.0);\n return;\n };\n var sqdistToQuadraticBezier = function sqdistToQuadraticBezier(x, y, x1, y1, x2, y2, x3, y3) {\n // Find minimum distance by using the minimum of the distance\n // function between the given point and the curve\n // This gives the coefficients of the resulting cubic equation\n // whose roots tell us where a possible minimum is\n // (Coefficients are divided by 4)\n var a = 1.0 * x1 * x1 - 4 * x1 * x2 + 2 * x1 * x3 + 4 * x2 * x2 - 4 * x2 * x3 + x3 * x3 + y1 * y1 - 4 * y1 * y2 + 2 * y1 * y3 + 4 * y2 * y2 - 4 * y2 * y3 + y3 * y3;\n var b = 1.0 * 9 * x1 * x2 - 3 * x1 * x1 - 3 * x1 * x3 - 6 * x2 * x2 + 3 * x2 * x3 + 9 * y1 * y2 - 3 * y1 * y1 - 3 * y1 * y3 - 6 * y2 * y2 + 3 * y2 * y3;\n var c = 1.0 * 3 * x1 * x1 - 6 * x1 * x2 + x1 * x3 - x1 * x + 2 * x2 * x2 + 2 * x2 * x - x3 * x + 3 * y1 * y1 - 6 * y1 * y2 + y1 * y3 - y1 * y + 2 * y2 * y2 + 2 * y2 * y - y3 * y;\n var d = 1.0 * x1 * x2 - x1 * x1 + x1 * x - x2 * x + y1 * y2 - y1 * y1 + y1 * y - y2 * y; // debug(\"coefficients: \" + a / a + \", \" + b / a + \", \" + c / a + \", \" + d / a);\n\n var roots = []; // Use the cubic solving algorithm\n\n solveCubic(a, b, c, d, roots);\n var zeroThreshold = 0.0000001;\n var params = [];\n\n for (var index = 0; index < 6; index += 2) {\n if (Math.abs(roots[index + 1]) < zeroThreshold && roots[index] >= 0 && roots[index] <= 1.0) {\n params.push(roots[index]);\n }\n }\n\n params.push(1.0);\n params.push(0.0);\n var minDistanceSquared = -1;\n var curX, curY, distSquared;\n\n for (var i = 0; i < params.length; i++) {\n curX = Math.pow(1.0 - params[i], 2.0) * x1 + 2.0 * (1 - params[i]) * params[i] * x2 + params[i] * params[i] * x3;\n curY = Math.pow(1 - params[i], 2.0) * y1 + 2 * (1.0 - params[i]) * params[i] * y2 + params[i] * params[i] * y3;\n distSquared = Math.pow(curX - x, 2) + Math.pow(curY - y, 2); // debug('distance for param ' + params[i] + \": \" + Math.sqrt(distSquared));\n\n if (minDistanceSquared >= 0) {\n if (distSquared < minDistanceSquared) {\n minDistanceSquared = distSquared;\n }\n } else {\n minDistanceSquared = distSquared;\n }\n }\n\n return minDistanceSquared;\n };\n var sqdistToFiniteLine = function sqdistToFiniteLine(x, y, x1, y1, x2, y2) {\n var offset = [x - x1, y - y1];\n var line = [x2 - x1, y2 - y1];\n var lineSq = line[0] * line[0] + line[1] * line[1];\n var hypSq = offset[0] * offset[0] + offset[1] * offset[1];\n var dotProduct = offset[0] * line[0] + offset[1] * line[1];\n var adjSq = dotProduct * dotProduct / lineSq;\n\n if (dotProduct < 0) {\n return hypSq;\n }\n\n if (adjSq > lineSq) {\n return (x - x2) * (x - x2) + (y - y2) * (y - y2);\n }\n\n return hypSq - adjSq;\n };\n var pointInsidePolygonPoints = function pointInsidePolygonPoints(x, y, points) {\n var x1, y1, x2, y2;\n var y3; // Intersect with vertical line through (x, y)\n\n var up = 0; // let down = 0;\n\n for (var i = 0; i < points.length / 2; i++) {\n x1 = points[i * 2];\n y1 = points[i * 2 + 1];\n\n if (i + 1 < points.length / 2) {\n x2 = points[(i + 1) * 2];\n y2 = points[(i + 1) * 2 + 1];\n } else {\n x2 = points[(i + 1 - points.length / 2) * 2];\n y2 = points[(i + 1 - points.length / 2) * 2 + 1];\n }\n\n if (x1 == x && x2 == x) ; else if (x1 >= x && x >= x2 || x1 <= x && x <= x2) {\n y3 = (x - x1) / (x2 - x1) * (y2 - y1) + y1;\n\n if (y3 > y) {\n up++;\n } // if( y3 < y ){\n // down++;\n // }\n\n } else {\n continue;\n }\n }\n\n if (up % 2 === 0) {\n return false;\n } else {\n return true;\n }\n };\n var pointInsidePolygon = function pointInsidePolygon(x, y, basePoints, centerX, centerY, width, height, direction, padding) {\n var transformedPoints = new Array(basePoints.length); // Gives negative angle\n\n var angle;\n\n if (direction[0] != null) {\n angle = Math.atan(direction[1] / direction[0]);\n\n if (direction[0] < 0) {\n angle = angle + Math.PI / 2;\n } else {\n angle = -angle - Math.PI / 2;\n }\n } else {\n angle = direction;\n }\n\n var cos = Math.cos(-angle);\n var sin = Math.sin(-angle); // console.log(\"base: \" + basePoints);\n\n for (var i = 0; i < transformedPoints.length / 2; i++) {\n transformedPoints[i * 2] = width / 2 * (basePoints[i * 2] * cos - basePoints[i * 2 + 1] * sin);\n transformedPoints[i * 2 + 1] = height / 2 * (basePoints[i * 2 + 1] * cos + basePoints[i * 2] * sin);\n transformedPoints[i * 2] += centerX;\n transformedPoints[i * 2 + 1] += centerY;\n }\n\n var points;\n\n if (padding > 0) {\n var expandedLineSet = expandPolygon(transformedPoints, -padding);\n points = joinLines(expandedLineSet);\n } else {\n points = transformedPoints;\n }\n\n return pointInsidePolygonPoints(x, y, points);\n };\n var pointInsideRoundPolygon = function pointInsideRoundPolygon(x, y, basePoints, centerX, centerY, width, height) {\n var cutPolygonPoints = new Array(basePoints.length);\n var halfW = width / 2;\n var halfH = height / 2;\n var cornerRadius = getRoundPolygonRadius(width, height);\n var squaredCornerRadius = cornerRadius * cornerRadius;\n\n for (var i = 0; i < basePoints.length / 4; i++) {\n var sourceUv = void 0,\n destUv = void 0;\n\n if (i === 0) {\n sourceUv = basePoints.length - 2;\n } else {\n sourceUv = i * 4 - 2;\n }\n\n destUv = i * 4 + 2;\n var px = centerX + halfW * basePoints[i * 4];\n var py = centerY + halfH * basePoints[i * 4 + 1];\n var cosTheta = -basePoints[sourceUv] * basePoints[destUv] - basePoints[sourceUv + 1] * basePoints[destUv + 1];\n var offset = cornerRadius / Math.tan(Math.acos(cosTheta) / 2);\n var cp0x = px - offset * basePoints[sourceUv];\n var cp0y = py - offset * basePoints[sourceUv + 1];\n var cp1x = px + offset * basePoints[destUv];\n var cp1y = py + offset * basePoints[destUv + 1];\n cutPolygonPoints[i * 4] = cp0x;\n cutPolygonPoints[i * 4 + 1] = cp0y;\n cutPolygonPoints[i * 4 + 2] = cp1x;\n cutPolygonPoints[i * 4 + 3] = cp1y;\n var orthx = basePoints[sourceUv + 1];\n var orthy = -basePoints[sourceUv];\n var cosAlpha = orthx * basePoints[destUv] + orthy * basePoints[destUv + 1];\n\n if (cosAlpha < 0) {\n orthx *= -1;\n orthy *= -1;\n }\n\n var cx = cp0x + orthx * cornerRadius;\n var cy = cp0y + orthy * cornerRadius;\n var squaredDistance = Math.pow(cx - x, 2) + Math.pow(cy - y, 2);\n\n if (squaredDistance <= squaredCornerRadius) {\n return true;\n }\n }\n\n return pointInsidePolygonPoints(x, y, cutPolygonPoints);\n };\n var joinLines = function joinLines(lineSet) {\n var vertices = new Array(lineSet.length / 2);\n var currentLineStartX, currentLineStartY, currentLineEndX, currentLineEndY;\n var nextLineStartX, nextLineStartY, nextLineEndX, nextLineEndY;\n\n for (var i = 0; i < lineSet.length / 4; i++) {\n currentLineStartX = lineSet[i * 4];\n currentLineStartY = lineSet[i * 4 + 1];\n currentLineEndX = lineSet[i * 4 + 2];\n currentLineEndY = lineSet[i * 4 + 3];\n\n if (i < lineSet.length / 4 - 1) {\n nextLineStartX = lineSet[(i + 1) * 4];\n nextLineStartY = lineSet[(i + 1) * 4 + 1];\n nextLineEndX = lineSet[(i + 1) * 4 + 2];\n nextLineEndY = lineSet[(i + 1) * 4 + 3];\n } else {\n nextLineStartX = lineSet[0];\n nextLineStartY = lineSet[1];\n nextLineEndX = lineSet[2];\n nextLineEndY = lineSet[3];\n }\n\n var intersection = finiteLinesIntersect(currentLineStartX, currentLineStartY, currentLineEndX, currentLineEndY, nextLineStartX, nextLineStartY, nextLineEndX, nextLineEndY, true);\n vertices[i * 2] = intersection[0];\n vertices[i * 2 + 1] = intersection[1];\n }\n\n return vertices;\n };\n var expandPolygon = function expandPolygon(points, pad) {\n var expandedLineSet = new Array(points.length * 2);\n var currentPointX, currentPointY, nextPointX, nextPointY;\n\n for (var i = 0; i < points.length / 2; i++) {\n currentPointX = points[i * 2];\n currentPointY = points[i * 2 + 1];\n\n if (i < points.length / 2 - 1) {\n nextPointX = points[(i + 1) * 2];\n nextPointY = points[(i + 1) * 2 + 1];\n } else {\n nextPointX = points[0];\n nextPointY = points[1];\n } // Current line: [currentPointX, currentPointY] to [nextPointX, nextPointY]\n // Assume CCW polygon winding\n\n\n var offsetX = nextPointY - currentPointY;\n var offsetY = -(nextPointX - currentPointX); // Normalize\n\n var offsetLength = Math.sqrt(offsetX * offsetX + offsetY * offsetY);\n var normalizedOffsetX = offsetX / offsetLength;\n var normalizedOffsetY = offsetY / offsetLength;\n expandedLineSet[i * 4] = currentPointX + normalizedOffsetX * pad;\n expandedLineSet[i * 4 + 1] = currentPointY + normalizedOffsetY * pad;\n expandedLineSet[i * 4 + 2] = nextPointX + normalizedOffsetX * pad;\n expandedLineSet[i * 4 + 3] = nextPointY + normalizedOffsetY * pad;\n }\n\n return expandedLineSet;\n };\n var intersectLineEllipse = function intersectLineEllipse(x, y, centerX, centerY, ellipseWradius, ellipseHradius) {\n var dispX = centerX - x;\n var dispY = centerY - y;\n dispX /= ellipseWradius;\n dispY /= ellipseHradius;\n var len = Math.sqrt(dispX * dispX + dispY * dispY);\n var newLength = len - 1;\n\n if (newLength < 0) {\n return [];\n }\n\n var lenProportion = newLength / len;\n return [(centerX - x) * lenProportion + x, (centerY - y) * lenProportion + y];\n };\n var checkInEllipse = function checkInEllipse(x, y, width, height, centerX, centerY, padding) {\n x -= centerX;\n y -= centerY;\n x /= width / 2 + padding;\n y /= height / 2 + padding;\n return x * x + y * y <= 1;\n }; // Returns intersections of increasing distance from line's start point\n\n var intersectLineCircle = function intersectLineCircle(x1, y1, x2, y2, centerX, centerY, radius) {\n // Calculate d, direction vector of line\n var d = [x2 - x1, y2 - y1]; // Direction vector of line\n\n var f = [x1 - centerX, y1 - centerY];\n var a = d[0] * d[0] + d[1] * d[1];\n var b = 2 * (f[0] * d[0] + f[1] * d[1]);\n var c = f[0] * f[0] + f[1] * f[1] - radius * radius;\n var discriminant = b * b - 4 * a * c;\n\n if (discriminant < 0) {\n return [];\n }\n\n var t1 = (-b + Math.sqrt(discriminant)) / (2 * a);\n var t2 = (-b - Math.sqrt(discriminant)) / (2 * a);\n var tMin = Math.min(t1, t2);\n var tMax = Math.max(t1, t2);\n var inRangeParams = [];\n\n if (tMin >= 0 && tMin <= 1) {\n inRangeParams.push(tMin);\n }\n\n if (tMax >= 0 && tMax <= 1) {\n inRangeParams.push(tMax);\n }\n\n if (inRangeParams.length === 0) {\n return [];\n }\n\n var nearIntersectionX = inRangeParams[0] * d[0] + x1;\n var nearIntersectionY = inRangeParams[0] * d[1] + y1;\n\n if (inRangeParams.length > 1) {\n if (inRangeParams[0] == inRangeParams[1]) {\n return [nearIntersectionX, nearIntersectionY];\n } else {\n var farIntersectionX = inRangeParams[1] * d[0] + x1;\n var farIntersectionY = inRangeParams[1] * d[1] + y1;\n return [nearIntersectionX, nearIntersectionY, farIntersectionX, farIntersectionY];\n }\n } else {\n return [nearIntersectionX, nearIntersectionY];\n }\n };\n var midOfThree = function midOfThree(a, b, c) {\n if (b <= a && a <= c || c <= a && a <= b) {\n return a;\n } else if (a <= b && b <= c || c <= b && b <= a) {\n return b;\n } else {\n return c;\n }\n }; // (x1,y1)=>(x2,y2) intersect with (x3,y3)=>(x4,y4)\n\n var finiteLinesIntersect = function finiteLinesIntersect(x1, y1, x2, y2, x3, y3, x4, y4, infiniteLines) {\n var dx13 = x1 - x3;\n var dx21 = x2 - x1;\n var dx43 = x4 - x3;\n var dy13 = y1 - y3;\n var dy21 = y2 - y1;\n var dy43 = y4 - y3;\n var ua_t = dx43 * dy13 - dy43 * dx13;\n var ub_t = dx21 * dy13 - dy21 * dx13;\n var u_b = dy43 * dx21 - dx43 * dy21;\n\n if (u_b !== 0) {\n var ua = ua_t / u_b;\n var ub = ub_t / u_b;\n var flptThreshold = 0.001;\n\n var _min = 0 - flptThreshold;\n\n var _max = 1 + flptThreshold;\n\n if (_min <= ua && ua <= _max && _min <= ub && ub <= _max) {\n return [x1 + ua * dx21, y1 + ua * dy21];\n } else {\n if (!infiniteLines) {\n return [];\n } else {\n return [x1 + ua * dx21, y1 + ua * dy21];\n }\n }\n } else {\n if (ua_t === 0 || ub_t === 0) {\n // Parallel, coincident lines. Check if overlap\n // Check endpoint of second line\n if (midOfThree(x1, x2, x4) === x4) {\n return [x4, y4];\n } // Check start point of second line\n\n\n if (midOfThree(x1, x2, x3) === x3) {\n return [x3, y3];\n } // Endpoint of first line\n\n\n if (midOfThree(x3, x4, x2) === x2) {\n return [x2, y2];\n }\n\n return [];\n } else {\n // Parallel, non-coincident\n return [];\n }\n }\n }; // math.polygonIntersectLine( x, y, basePoints, centerX, centerY, width, height, padding )\n // intersect a node polygon (pts transformed)\n //\n // math.polygonIntersectLine( x, y, basePoints, centerX, centerY )\n // intersect the points (no transform)\n\n var polygonIntersectLine = function polygonIntersectLine(x, y, basePoints, centerX, centerY, width, height, padding) {\n var intersections = [];\n var intersection;\n var transformedPoints = new Array(basePoints.length);\n var doTransform = true;\n\n if (width == null) {\n doTransform = false;\n }\n\n var points;\n\n if (doTransform) {\n for (var i = 0; i < transformedPoints.length / 2; i++) {\n transformedPoints[i * 2] = basePoints[i * 2] * width + centerX;\n transformedPoints[i * 2 + 1] = basePoints[i * 2 + 1] * height + centerY;\n }\n\n if (padding > 0) {\n var expandedLineSet = expandPolygon(transformedPoints, -padding);\n points = joinLines(expandedLineSet);\n } else {\n points = transformedPoints;\n }\n } else {\n points = basePoints;\n }\n\n var currentX, currentY, nextX, nextY;\n\n for (var _i2 = 0; _i2 < points.length / 2; _i2++) {\n currentX = points[_i2 * 2];\n currentY = points[_i2 * 2 + 1];\n\n if (_i2 < points.length / 2 - 1) {\n nextX = points[(_i2 + 1) * 2];\n nextY = points[(_i2 + 1) * 2 + 1];\n } else {\n nextX = points[0];\n nextY = points[1];\n }\n\n intersection = finiteLinesIntersect(x, y, centerX, centerY, currentX, currentY, nextX, nextY);\n\n if (intersection.length !== 0) {\n intersections.push(intersection[0], intersection[1]);\n }\n }\n\n return intersections;\n };\n var roundPolygonIntersectLine = function roundPolygonIntersectLine(x, y, basePoints, centerX, centerY, width, height, padding) {\n var intersections = [];\n var intersection;\n var lines = new Array(basePoints.length);\n var halfW = width / 2;\n var halfH = height / 2;\n var cornerRadius = getRoundPolygonRadius(width, height);\n\n for (var i = 0; i < basePoints.length / 4; i++) {\n var sourceUv = void 0,\n destUv = void 0;\n\n if (i === 0) {\n sourceUv = basePoints.length - 2;\n } else {\n sourceUv = i * 4 - 2;\n }\n\n destUv = i * 4 + 2;\n var px = centerX + halfW * basePoints[i * 4];\n var py = centerY + halfH * basePoints[i * 4 + 1];\n var cosTheta = -basePoints[sourceUv] * basePoints[destUv] - basePoints[sourceUv + 1] * basePoints[destUv + 1];\n var offset = cornerRadius / Math.tan(Math.acos(cosTheta) / 2);\n var cp0x = px - offset * basePoints[sourceUv];\n var cp0y = py - offset * basePoints[sourceUv + 1];\n var cp1x = px + offset * basePoints[destUv];\n var cp1y = py + offset * basePoints[destUv + 1];\n\n if (i === 0) {\n lines[basePoints.length - 2] = cp0x;\n lines[basePoints.length - 1] = cp0y;\n } else {\n lines[i * 4 - 2] = cp0x;\n lines[i * 4 - 1] = cp0y;\n }\n\n lines[i * 4] = cp1x;\n lines[i * 4 + 1] = cp1y;\n var orthx = basePoints[sourceUv + 1];\n var orthy = -basePoints[sourceUv];\n var cosAlpha = orthx * basePoints[destUv] + orthy * basePoints[destUv + 1];\n\n if (cosAlpha < 0) {\n orthx *= -1;\n orthy *= -1;\n }\n\n var cx = cp0x + orthx * cornerRadius;\n var cy = cp0y + orthy * cornerRadius;\n intersection = intersectLineCircle(x, y, centerX, centerY, cx, cy, cornerRadius);\n\n if (intersection.length !== 0) {\n intersections.push(intersection[0], intersection[1]);\n }\n }\n\n for (var _i3 = 0; _i3 < lines.length / 4; _i3++) {\n intersection = finiteLinesIntersect(x, y, centerX, centerY, lines[_i3 * 4], lines[_i3 * 4 + 1], lines[_i3 * 4 + 2], lines[_i3 * 4 + 3], false);\n\n if (intersection.length !== 0) {\n intersections.push(intersection[0], intersection[1]);\n }\n }\n\n if (intersections.length > 2) {\n var lowestIntersection = [intersections[0], intersections[1]];\n var lowestSquaredDistance = Math.pow(lowestIntersection[0] - x, 2) + Math.pow(lowestIntersection[1] - y, 2);\n\n for (var _i4 = 1; _i4 < intersections.length / 2; _i4++) {\n var squaredDistance = Math.pow(intersections[_i4 * 2] - x, 2) + Math.pow(intersections[_i4 * 2 + 1] - y, 2);\n\n if (squaredDistance <= lowestSquaredDistance) {\n lowestIntersection[0] = intersections[_i4 * 2];\n lowestIntersection[1] = intersections[_i4 * 2 + 1];\n lowestSquaredDistance = squaredDistance;\n }\n }\n\n return lowestIntersection;\n }\n\n return intersections;\n };\n var shortenIntersection = function shortenIntersection(intersection, offset, amount) {\n var disp = [intersection[0] - offset[0], intersection[1] - offset[1]];\n var length = Math.sqrt(disp[0] * disp[0] + disp[1] * disp[1]);\n var lenRatio = (length - amount) / length;\n\n if (lenRatio < 0) {\n lenRatio = 0.00001;\n }\n\n return [offset[0] + lenRatio * disp[0], offset[1] + lenRatio * disp[1]];\n };\n var generateUnitNgonPointsFitToSquare = function generateUnitNgonPointsFitToSquare(sides, rotationRadians) {\n var points = generateUnitNgonPoints(sides, rotationRadians);\n points = fitPolygonToSquare(points);\n return points;\n };\n var fitPolygonToSquare = function fitPolygonToSquare(points) {\n var x, y;\n var sides = points.length / 2;\n var minX = Infinity,\n minY = Infinity,\n maxX = -Infinity,\n maxY = -Infinity;\n\n for (var i = 0; i < sides; i++) {\n x = points[2 * i];\n y = points[2 * i + 1];\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n } // stretch factors\n\n\n var sx = 2 / (maxX - minX);\n var sy = 2 / (maxY - minY);\n\n for (var _i5 = 0; _i5 < sides; _i5++) {\n x = points[2 * _i5] = points[2 * _i5] * sx;\n y = points[2 * _i5 + 1] = points[2 * _i5 + 1] * sy;\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n }\n\n if (minY < -1) {\n for (var _i6 = 0; _i6 < sides; _i6++) {\n y = points[2 * _i6 + 1] = points[2 * _i6 + 1] + (-1 - minY);\n }\n }\n\n return points;\n };\n var generateUnitNgonPoints = function generateUnitNgonPoints(sides, rotationRadians) {\n var increment = 1.0 / sides * 2 * Math.PI;\n var startAngle = sides % 2 === 0 ? Math.PI / 2.0 + increment / 2.0 : Math.PI / 2.0;\n startAngle += rotationRadians;\n var points = new Array(sides * 2);\n var currentAngle;\n\n for (var i = 0; i < sides; i++) {\n currentAngle = i * increment + startAngle;\n points[2 * i] = Math.cos(currentAngle); // x\n\n points[2 * i + 1] = Math.sin(-currentAngle); // y\n }\n\n return points;\n }; // Set the default radius, unless half of width or height is smaller than default\n\n var getRoundRectangleRadius = function getRoundRectangleRadius(width, height) {\n return Math.min(width / 4, height / 4, 8);\n }; // Set the default radius\n\n var getRoundPolygonRadius = function getRoundPolygonRadius(width, height) {\n return Math.min(width / 10, height / 10, 8);\n };\n var getCutRectangleCornerLength = function getCutRectangleCornerLength() {\n return 8;\n };\n var bezierPtsToQuadCoeff = function bezierPtsToQuadCoeff(p0, p1, p2) {\n return [p0 - 2 * p1 + p2, 2 * (p1 - p0), p0];\n }; // get curve width, height, and control point position offsets as a percentage of node height / width\n\n var getBarrelCurveConstants = function getBarrelCurveConstants(width, height) {\n return {\n heightOffset: Math.min(15, 0.05 * height),\n widthOffset: Math.min(100, 0.25 * width),\n ctrlPtOffsetPct: 0.05\n };\n };\n\n var pageRankDefaults = defaults$g({\n dampingFactor: 0.8,\n precision: 0.000001,\n iterations: 200,\n weight: function weight(edge) {\n return 1;\n }\n });\n var elesfn$o = {\n pageRank: function pageRank(options) {\n var _pageRankDefaults = pageRankDefaults(options),\n dampingFactor = _pageRankDefaults.dampingFactor,\n precision = _pageRankDefaults.precision,\n iterations = _pageRankDefaults.iterations,\n weight = _pageRankDefaults.weight;\n\n var cy = this._private.cy;\n\n var _this$byGroup = this.byGroup(),\n nodes = _this$byGroup.nodes,\n edges = _this$byGroup.edges;\n\n var numNodes = nodes.length;\n var numNodesSqd = numNodes * numNodes;\n var numEdges = edges.length; // Construct transposed adjacency matrix\n // First lets have a zeroed matrix of the right size\n // We'll also keep track of the sum of each column\n\n var matrix = new Array(numNodesSqd);\n var columnSum = new Array(numNodes);\n var additionalProb = (1 - dampingFactor) / numNodes; // Create null matrix\n\n for (var i = 0; i < numNodes; i++) {\n for (var j = 0; j < numNodes; j++) {\n var n = i * numNodes + j;\n matrix[n] = 0;\n }\n\n columnSum[i] = 0;\n } // Now, process edges\n\n\n for (var _i = 0; _i < numEdges; _i++) {\n var edge = edges[_i];\n var srcId = edge.data('source');\n var tgtId = edge.data('target'); // Don't include loops in the matrix\n\n if (srcId === tgtId) {\n continue;\n }\n\n var s = nodes.indexOfId(srcId);\n var t = nodes.indexOfId(tgtId);\n var w = weight(edge);\n\n var _n = t * numNodes + s; // Update matrix\n\n\n matrix[_n] += w; // Update column sum\n\n columnSum[s] += w;\n } // Add additional probability based on damping factor\n // Also, take into account columns that have sum = 0\n\n\n var p = 1.0 / numNodes + additionalProb; // Shorthand\n // Traverse matrix, column by column\n\n for (var _j = 0; _j < numNodes; _j++) {\n if (columnSum[_j] === 0) {\n // No 'links' out from node jth, assume equal probability for each possible node\n for (var _i2 = 0; _i2 < numNodes; _i2++) {\n var _n2 = _i2 * numNodes + _j;\n\n matrix[_n2] = p;\n }\n } else {\n // Node jth has outgoing link, compute normalized probabilities\n for (var _i3 = 0; _i3 < numNodes; _i3++) {\n var _n3 = _i3 * numNodes + _j;\n\n matrix[_n3] = matrix[_n3] / columnSum[_j] + additionalProb;\n }\n }\n } // Compute dominant eigenvector using power method\n\n\n var eigenvector = new Array(numNodes);\n var temp = new Array(numNodes);\n var previous; // Start with a vector of all 1's\n // Also, initialize a null vector which will be used as shorthand\n\n for (var _i4 = 0; _i4 < numNodes; _i4++) {\n eigenvector[_i4] = 1;\n }\n\n for (var iter = 0; iter < iterations; iter++) {\n // Temp array with all 0's\n for (var _i5 = 0; _i5 < numNodes; _i5++) {\n temp[_i5] = 0;\n } // Multiply matrix with previous result\n\n\n for (var _i6 = 0; _i6 < numNodes; _i6++) {\n for (var _j2 = 0; _j2 < numNodes; _j2++) {\n var _n4 = _i6 * numNodes + _j2;\n\n temp[_i6] += matrix[_n4] * eigenvector[_j2];\n }\n }\n\n inPlaceSumNormalize(temp);\n previous = eigenvector;\n eigenvector = temp;\n temp = previous;\n var diff = 0; // Compute difference (squared module) of both vectors\n\n for (var _i7 = 0; _i7 < numNodes; _i7++) {\n var delta = previous[_i7] - eigenvector[_i7];\n diff += delta * delta;\n } // If difference is less than the desired threshold, stop iterating\n\n\n if (diff < precision) {\n break;\n }\n } // Construct result\n\n\n var res = {\n rank: function rank(node) {\n node = cy.collection(node)[0];\n return eigenvector[nodes.indexOf(node)];\n }\n };\n return res;\n } // pageRank\n\n }; // elesfn\n\n var defaults$f = defaults$g({\n root: null,\n weight: function weight(edge) {\n return 1;\n },\n directed: false,\n alpha: 0\n });\n var elesfn$n = {\n degreeCentralityNormalized: function degreeCentralityNormalized(options) {\n options = defaults$f(options);\n var cy = this.cy();\n var nodes = this.nodes();\n var numNodes = nodes.length;\n\n if (!options.directed) {\n var degrees = {};\n var maxDegree = 0;\n\n for (var i = 0; i < numNodes; i++) {\n var node = nodes[i]; // add current node to the current options object and call degreeCentrality\n\n options.root = node;\n var currDegree = this.degreeCentrality(options);\n\n if (maxDegree < currDegree.degree) {\n maxDegree = currDegree.degree;\n }\n\n degrees[node.id()] = currDegree.degree;\n }\n\n return {\n degree: function degree(node) {\n if (maxDegree === 0) {\n return 0;\n }\n\n if (string(node)) {\n // from is a selector string\n node = cy.filter(node);\n }\n\n return degrees[node.id()] / maxDegree;\n }\n };\n } else {\n var indegrees = {};\n var outdegrees = {};\n var maxIndegree = 0;\n var maxOutdegree = 0;\n\n for (var _i = 0; _i < numNodes; _i++) {\n var _node = nodes[_i];\n\n var id = _node.id(); // add current node to the current options object and call degreeCentrality\n\n\n options.root = _node;\n\n var _currDegree = this.degreeCentrality(options);\n\n if (maxIndegree < _currDegree.indegree) maxIndegree = _currDegree.indegree;\n if (maxOutdegree < _currDegree.outdegree) maxOutdegree = _currDegree.outdegree;\n indegrees[id] = _currDegree.indegree;\n outdegrees[id] = _currDegree.outdegree;\n }\n\n return {\n indegree: function indegree(node) {\n if (maxIndegree == 0) {\n return 0;\n }\n\n if (string(node)) {\n // from is a selector string\n node = cy.filter(node);\n }\n\n return indegrees[node.id()] / maxIndegree;\n },\n outdegree: function outdegree(node) {\n if (maxOutdegree === 0) {\n return 0;\n }\n\n if (string(node)) {\n // from is a selector string\n node = cy.filter(node);\n }\n\n return outdegrees[node.id()] / maxOutdegree;\n }\n };\n }\n },\n // degreeCentralityNormalized\n // Implemented from the algorithm in Opsahl's paper\n // \"Node centrality in weighted networks: Generalizing degree and shortest paths\"\n // check the heading 2 \"Degree\"\n degreeCentrality: function degreeCentrality(options) {\n options = defaults$f(options);\n var cy = this.cy();\n var callingEles = this;\n var _options = options,\n root = _options.root,\n weight = _options.weight,\n directed = _options.directed,\n alpha = _options.alpha;\n root = cy.collection(root)[0];\n\n if (!directed) {\n var connEdges = root.connectedEdges().intersection(callingEles);\n var k = connEdges.length;\n var s = 0; // Now, sum edge weights\n\n for (var i = 0; i < connEdges.length; i++) {\n s += weight(connEdges[i]);\n }\n\n return {\n degree: Math.pow(k, 1 - alpha) * Math.pow(s, alpha)\n };\n } else {\n var edges = root.connectedEdges();\n var incoming = edges.filter(function (edge) {\n return edge.target().same(root) && callingEles.has(edge);\n });\n var outgoing = edges.filter(function (edge) {\n return edge.source().same(root) && callingEles.has(edge);\n });\n var k_in = incoming.length;\n var k_out = outgoing.length;\n var s_in = 0;\n var s_out = 0; // Now, sum incoming edge weights\n\n for (var _i2 = 0; _i2 < incoming.length; _i2++) {\n s_in += weight(incoming[_i2]);\n } // Now, sum outgoing edge weights\n\n\n for (var _i3 = 0; _i3 < outgoing.length; _i3++) {\n s_out += weight(outgoing[_i3]);\n }\n\n return {\n indegree: Math.pow(k_in, 1 - alpha) * Math.pow(s_in, alpha),\n outdegree: Math.pow(k_out, 1 - alpha) * Math.pow(s_out, alpha)\n };\n }\n } // degreeCentrality\n\n }; // elesfn\n // nice, short mathematical alias\n\n elesfn$n.dc = elesfn$n.degreeCentrality;\n elesfn$n.dcn = elesfn$n.degreeCentralityNormalised = elesfn$n.degreeCentralityNormalized;\n\n var defaults$e = defaults$g({\n harmonic: true,\n weight: function weight() {\n return 1;\n },\n directed: false,\n root: null\n });\n var elesfn$m = {\n closenessCentralityNormalized: function closenessCentralityNormalized(options) {\n var _defaults = defaults$e(options),\n harmonic = _defaults.harmonic,\n weight = _defaults.weight,\n directed = _defaults.directed;\n\n var cy = this.cy();\n var closenesses = {};\n var maxCloseness = 0;\n var nodes = this.nodes();\n var fw = this.floydWarshall({\n weight: weight,\n directed: directed\n }); // Compute closeness for every node and find the maximum closeness\n\n for (var i = 0; i < nodes.length; i++) {\n var currCloseness = 0;\n var node_i = nodes[i];\n\n for (var j = 0; j < nodes.length; j++) {\n if (i !== j) {\n var d = fw.distance(node_i, nodes[j]);\n\n if (harmonic) {\n currCloseness += 1 / d;\n } else {\n currCloseness += d;\n }\n }\n }\n\n if (!harmonic) {\n currCloseness = 1 / currCloseness;\n }\n\n if (maxCloseness < currCloseness) {\n maxCloseness = currCloseness;\n }\n\n closenesses[node_i.id()] = currCloseness;\n }\n\n return {\n closeness: function closeness(node) {\n if (maxCloseness == 0) {\n return 0;\n }\n\n if (string(node)) {\n // from is a selector string\n node = cy.filter(node)[0].id();\n } else {\n // from is a node\n node = node.id();\n }\n\n return closenesses[node] / maxCloseness;\n }\n };\n },\n // Implemented from pseudocode from wikipedia\n closenessCentrality: function closenessCentrality(options) {\n var _defaults2 = defaults$e(options),\n root = _defaults2.root,\n weight = _defaults2.weight,\n directed = _defaults2.directed,\n harmonic = _defaults2.harmonic;\n\n root = this.filter(root)[0]; // we need distance from this node to every other node\n\n var dijkstra = this.dijkstra({\n root: root,\n weight: weight,\n directed: directed\n });\n var totalDistance = 0;\n var nodes = this.nodes();\n\n for (var i = 0; i < nodes.length; i++) {\n var n = nodes[i];\n\n if (!n.same(root)) {\n var d = dijkstra.distanceTo(n);\n\n if (harmonic) {\n totalDistance += 1 / d;\n } else {\n totalDistance += d;\n }\n }\n }\n\n return harmonic ? totalDistance : 1 / totalDistance;\n } // closenessCentrality\n\n }; // elesfn\n // nice, short mathematical alias\n\n elesfn$m.cc = elesfn$m.closenessCentrality;\n elesfn$m.ccn = elesfn$m.closenessCentralityNormalised = elesfn$m.closenessCentralityNormalized;\n\n var defaults$d = defaults$g({\n weight: null,\n directed: false\n });\n var elesfn$l = {\n // Implemented from the algorithm in the paper \"On Variants of Shortest-Path Betweenness Centrality and their Generic Computation\" by Ulrik Brandes\n betweennessCentrality: function betweennessCentrality(options) {\n var _defaults = defaults$d(options),\n directed = _defaults.directed,\n weight = _defaults.weight;\n\n var weighted = weight != null;\n var cy = this.cy(); // starting\n\n var V = this.nodes();\n var A = {};\n var _C = {};\n var max = 0;\n var C = {\n set: function set(key, val) {\n _C[key] = val;\n\n if (val > max) {\n max = val;\n }\n },\n get: function get(key) {\n return _C[key];\n }\n }; // A contains the neighborhoods of every node\n\n for (var i = 0; i < V.length; i++) {\n var v = V[i];\n var vid = v.id();\n\n if (directed) {\n A[vid] = v.outgoers().nodes(); // get outgoers of every node\n } else {\n A[vid] = v.openNeighborhood().nodes(); // get neighbors of every node\n }\n\n C.set(vid, 0);\n }\n\n var _loop = function _loop(s) {\n var sid = V[s].id();\n var S = []; // stack\n\n var P = {};\n var g = {};\n var d = {};\n var Q = new heap(function (a, b) {\n return d[a] - d[b];\n }); // queue\n // init dictionaries\n\n for (var _i = 0; _i < V.length; _i++) {\n var _vid = V[_i].id();\n\n P[_vid] = [];\n g[_vid] = 0;\n d[_vid] = Infinity;\n }\n\n g[sid] = 1; // sigma\n\n d[sid] = 0; // distance to s\n\n Q.push(sid);\n\n while (!Q.empty()) {\n var _v = Q.pop();\n\n S.push(_v);\n\n if (weighted) {\n for (var j = 0; j < A[_v].length; j++) {\n var w = A[_v][j];\n var vEle = cy.getElementById(_v);\n var edge = void 0;\n\n if (vEle.edgesTo(w).length > 0) {\n edge = vEle.edgesTo(w)[0];\n } else {\n edge = w.edgesTo(vEle)[0];\n }\n\n var edgeWeight = weight(edge);\n w = w.id();\n\n if (d[w] > d[_v] + edgeWeight) {\n d[w] = d[_v] + edgeWeight;\n\n if (Q.nodes.indexOf(w) < 0) {\n //if w is not in Q\n Q.push(w);\n } else {\n // update position if w is in Q\n Q.updateItem(w);\n }\n\n g[w] = 0;\n P[w] = [];\n }\n\n if (d[w] == d[_v] + edgeWeight) {\n g[w] = g[w] + g[_v];\n P[w].push(_v);\n }\n }\n } else {\n for (var _j = 0; _j < A[_v].length; _j++) {\n var _w = A[_v][_j].id();\n\n if (d[_w] == Infinity) {\n Q.push(_w);\n d[_w] = d[_v] + 1;\n }\n\n if (d[_w] == d[_v] + 1) {\n g[_w] = g[_w] + g[_v];\n\n P[_w].push(_v);\n }\n }\n }\n }\n\n var e = {};\n\n for (var _i2 = 0; _i2 < V.length; _i2++) {\n e[V[_i2].id()] = 0;\n }\n\n while (S.length > 0) {\n var _w2 = S.pop();\n\n for (var _j2 = 0; _j2 < P[_w2].length; _j2++) {\n var _v2 = P[_w2][_j2];\n e[_v2] = e[_v2] + g[_v2] / g[_w2] * (1 + e[_w2]);\n }\n\n if (_w2 != V[s].id()) {\n C.set(_w2, C.get(_w2) + e[_w2]);\n }\n }\n };\n\n for (var s = 0; s < V.length; s++) {\n _loop(s);\n }\n\n var ret = {\n betweenness: function betweenness(node) {\n var id = cy.collection(node).id();\n return C.get(id);\n },\n betweennessNormalized: function betweennessNormalized(node) {\n if (max == 0) {\n return 0;\n }\n\n var id = cy.collection(node).id();\n return C.get(id) / max;\n }\n }; // alias\n\n ret.betweennessNormalised = ret.betweennessNormalized;\n return ret;\n } // betweennessCentrality\n\n }; // elesfn\n // nice, short mathematical alias\n\n elesfn$l.bc = elesfn$l.betweennessCentrality;\n\n // Implemented by Zoe Xi @zoexi for GSOC 2016\n /* eslint-disable no-unused-vars */\n\n var defaults$c = defaults$g({\n expandFactor: 2,\n // affects time of computation and cluster granularity to some extent: M * M\n inflateFactor: 2,\n // affects cluster granularity (the greater the value, the more clusters): M(i,j) / E(j)\n multFactor: 1,\n // optional self loops for each node. Use a neutral value to improve cluster computations.\n maxIterations: 20,\n // maximum number of iterations of the MCL algorithm in a single run\n attributes: [// attributes/features used to group nodes, ie. similarity values between nodes\n function (edge) {\n return 1;\n }]\n });\n /* eslint-enable */\n\n var setOptions$3 = function setOptions(options) {\n return defaults$c(options);\n };\n /* eslint-enable */\n\n\n var getSimilarity$1 = function getSimilarity(edge, attributes) {\n var total = 0;\n\n for (var i = 0; i < attributes.length; i++) {\n total += attributes[i](edge);\n }\n\n return total;\n };\n\n var addLoops = function addLoops(M, n, val) {\n for (var i = 0; i < n; i++) {\n M[i * n + i] = val;\n }\n };\n\n var normalize = function normalize(M, n) {\n var sum;\n\n for (var col = 0; col < n; col++) {\n sum = 0;\n\n for (var row = 0; row < n; row++) {\n sum += M[row * n + col];\n }\n\n for (var _row = 0; _row < n; _row++) {\n M[_row * n + col] = M[_row * n + col] / sum;\n }\n }\n }; // TODO: blocked matrix multiplication?\n\n\n var mmult = function mmult(A, B, n) {\n var C = new Array(n * n);\n\n for (var i = 0; i < n; i++) {\n for (var j = 0; j < n; j++) {\n C[i * n + j] = 0;\n }\n\n for (var k = 0; k < n; k++) {\n for (var _j = 0; _j < n; _j++) {\n C[i * n + _j] += A[i * n + k] * B[k * n + _j];\n }\n }\n }\n\n return C;\n };\n\n var expand = function expand(M, n, expandFactor\n /** power **/\n ) {\n var _M = M.slice(0);\n\n for (var p = 1; p < expandFactor; p++) {\n M = mmult(M, _M, n);\n }\n\n return M;\n };\n\n var inflate = function inflate(M, n, inflateFactor\n /** r **/\n ) {\n var _M = new Array(n * n); // M(i,j) ^ inflatePower\n\n\n for (var i = 0; i < n * n; i++) {\n _M[i] = Math.pow(M[i], inflateFactor);\n }\n\n normalize(_M, n);\n return _M;\n };\n\n var hasConverged = function hasConverged(M, _M, n2, roundFactor) {\n // Check that both matrices have the same elements (i,j)\n for (var i = 0; i < n2; i++) {\n var v1 = Math.round(M[i] * Math.pow(10, roundFactor)) / Math.pow(10, roundFactor); // truncate to 'roundFactor' decimal places\n\n var v2 = Math.round(_M[i] * Math.pow(10, roundFactor)) / Math.pow(10, roundFactor);\n\n if (v1 !== v2) {\n return false;\n }\n }\n\n return true;\n };\n\n var assign$2 = function assign(M, n, nodes, cy) {\n var clusters = [];\n\n for (var i = 0; i < n; i++) {\n var cluster = [];\n\n for (var j = 0; j < n; j++) {\n // Row-wise attractors and elements that they attract belong in same cluster\n if (Math.round(M[i * n + j] * 1000) / 1000 > 0) {\n cluster.push(nodes[j]);\n }\n }\n\n if (cluster.length !== 0) {\n clusters.push(cy.collection(cluster));\n }\n }\n\n return clusters;\n };\n\n var isDuplicate = function isDuplicate(c1, c2) {\n for (var i = 0; i < c1.length; i++) {\n if (!c2[i] || c1[i].id() !== c2[i].id()) {\n return false;\n }\n }\n\n return true;\n };\n\n var removeDuplicates = function removeDuplicates(clusters) {\n for (var i = 0; i < clusters.length; i++) {\n for (var j = 0; j < clusters.length; j++) {\n if (i != j && isDuplicate(clusters[i], clusters[j])) {\n clusters.splice(j, 1);\n }\n }\n }\n\n return clusters;\n };\n\n var markovClustering = function markovClustering(options) {\n var nodes = this.nodes();\n var edges = this.edges();\n var cy = this.cy(); // Set parameters of algorithm:\n\n var opts = setOptions$3(options); // Map each node to its position in node array\n\n var id2position = {};\n\n for (var i = 0; i < nodes.length; i++) {\n id2position[nodes[i].id()] = i;\n } // Generate stochastic matrix M from input graph G (should be symmetric/undirected)\n\n\n var n = nodes.length,\n n2 = n * n;\n\n var M = new Array(n2),\n _M;\n\n for (var _i = 0; _i < n2; _i++) {\n M[_i] = 0;\n }\n\n for (var e = 0; e < edges.length; e++) {\n var edge = edges[e];\n var _i2 = id2position[edge.source().id()];\n var j = id2position[edge.target().id()];\n var sim = getSimilarity$1(edge, opts.attributes);\n M[_i2 * n + j] += sim; // G should be symmetric and undirected\n\n M[j * n + _i2] += sim;\n } // Begin Markov cluster algorithm\n // Step 1: Add self loops to each node, ie. add multFactor to matrix diagonal\n\n\n addLoops(M, n, opts.multFactor); // Step 2: M = normalize( M );\n\n normalize(M, n);\n var isStillMoving = true;\n var iterations = 0;\n\n while (isStillMoving && iterations < opts.maxIterations) {\n isStillMoving = false; // Step 3:\n\n _M = expand(M, n, opts.expandFactor); // Step 4:\n\n M = inflate(_M, n, opts.inflateFactor); // Step 5: check to see if ~steady state has been reached\n\n if (!hasConverged(M, _M, n2, 4)) {\n isStillMoving = true;\n }\n\n iterations++;\n } // Build clusters from matrix\n\n\n var clusters = assign$2(M, n, nodes, cy); // Remove duplicate clusters due to symmetry of graph and M matrix\n\n clusters = removeDuplicates(clusters);\n return clusters;\n };\n\n var markovClustering$1 = {\n markovClustering: markovClustering,\n mcl: markovClustering\n };\n\n // Common distance metrics for clustering algorithms\n\n var identity = function identity(x) {\n return x;\n };\n\n var absDiff = function absDiff(p, q) {\n return Math.abs(q - p);\n };\n\n var addAbsDiff = function addAbsDiff(total, p, q) {\n return total + absDiff(p, q);\n };\n\n var addSquaredDiff = function addSquaredDiff(total, p, q) {\n return total + Math.pow(q - p, 2);\n };\n\n var sqrt = function sqrt(x) {\n return Math.sqrt(x);\n };\n\n var maxAbsDiff = function maxAbsDiff(currentMax, p, q) {\n return Math.max(currentMax, absDiff(p, q));\n };\n\n var getDistance = function getDistance(length, getP, getQ, init, visit) {\n var post = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : identity;\n var ret = init;\n var p, q;\n\n for (var dim = 0; dim < length; dim++) {\n p = getP(dim);\n q = getQ(dim);\n ret = visit(ret, p, q);\n }\n\n return post(ret);\n };\n\n var distances = {\n euclidean: function euclidean(length, getP, getQ) {\n if (length >= 2) {\n return getDistance(length, getP, getQ, 0, addSquaredDiff, sqrt);\n } else {\n // for single attr case, more efficient to avoid sqrt\n return getDistance(length, getP, getQ, 0, addAbsDiff);\n }\n },\n squaredEuclidean: function squaredEuclidean(length, getP, getQ) {\n return getDistance(length, getP, getQ, 0, addSquaredDiff);\n },\n manhattan: function manhattan(length, getP, getQ) {\n return getDistance(length, getP, getQ, 0, addAbsDiff);\n },\n max: function max(length, getP, getQ) {\n return getDistance(length, getP, getQ, -Infinity, maxAbsDiff);\n }\n }; // in case the user accidentally doesn't use camel case\n\n distances['squared-euclidean'] = distances['squaredEuclidean'];\n distances['squaredeuclidean'] = distances['squaredEuclidean'];\n function clusteringDistance (method, length, getP, getQ, nodeP, nodeQ) {\n var impl;\n\n if (fn$6(method)) {\n impl = method;\n } else {\n impl = distances[method] || distances.euclidean;\n }\n\n if (length === 0 && fn$6(method)) {\n return impl(nodeP, nodeQ);\n } else {\n return impl(length, getP, getQ, nodeP, nodeQ);\n }\n }\n\n var defaults$b = defaults$g({\n k: 2,\n m: 2,\n sensitivityThreshold: 0.0001,\n distance: 'euclidean',\n maxIterations: 10,\n attributes: [],\n testMode: false,\n testCentroids: null\n });\n\n var setOptions$2 = function setOptions(options) {\n return defaults$b(options);\n };\n /* eslint-enable */\n\n\n var getDist = function getDist(type, node, centroid, attributes, mode) {\n var noNodeP = mode !== 'kMedoids';\n var getP = noNodeP ? function (i) {\n return centroid[i];\n } : function (i) {\n return attributes[i](centroid);\n };\n\n var getQ = function getQ(i) {\n return attributes[i](node);\n };\n\n var nodeP = centroid;\n var nodeQ = node;\n return clusteringDistance(type, attributes.length, getP, getQ, nodeP, nodeQ);\n };\n\n var randomCentroids = function randomCentroids(nodes, k, attributes) {\n var ndim = attributes.length;\n var min = new Array(ndim);\n var max = new Array(ndim);\n var centroids = new Array(k);\n var centroid = null; // Find min, max values for each attribute dimension\n\n for (var i = 0; i < ndim; i++) {\n min[i] = nodes.min(attributes[i]).value;\n max[i] = nodes.max(attributes[i]).value;\n } // Build k centroids, each represented as an n-dim feature vector\n\n\n for (var c = 0; c < k; c++) {\n centroid = [];\n\n for (var _i = 0; _i < ndim; _i++) {\n centroid[_i] = Math.random() * (max[_i] - min[_i]) + min[_i]; // random initial value\n }\n\n centroids[c] = centroid;\n }\n\n return centroids;\n };\n\n var classify = function classify(node, centroids, distance, attributes, type) {\n var min = Infinity;\n var index = 0;\n\n for (var i = 0; i < centroids.length; i++) {\n var dist = getDist(distance, node, centroids[i], attributes, type);\n\n if (dist < min) {\n min = dist;\n index = i;\n }\n }\n\n return index;\n };\n\n var buildCluster = function buildCluster(centroid, nodes, assignment) {\n var cluster = [];\n var node = null;\n\n for (var n = 0; n < nodes.length; n++) {\n node = nodes[n];\n\n if (assignment[node.id()] === centroid) {\n //console.log(\"Node \" + node.id() + \" is associated with medoid #: \" + m);\n cluster.push(node);\n }\n }\n\n return cluster;\n };\n\n var haveValuesConverged = function haveValuesConverged(v1, v2, sensitivityThreshold) {\n return Math.abs(v2 - v1) <= sensitivityThreshold;\n };\n\n var haveMatricesConverged = function haveMatricesConverged(v1, v2, sensitivityThreshold) {\n for (var i = 0; i < v1.length; i++) {\n for (var j = 0; j < v1[i].length; j++) {\n var diff = Math.abs(v1[i][j] - v2[i][j]);\n\n if (diff > sensitivityThreshold) {\n return false;\n }\n }\n }\n\n return true;\n };\n\n var seenBefore = function seenBefore(node, medoids, n) {\n for (var i = 0; i < n; i++) {\n if (node === medoids[i]) return true;\n }\n\n return false;\n };\n\n var randomMedoids = function randomMedoids(nodes, k) {\n var medoids = new Array(k); // For small data sets, the probability of medoid conflict is greater,\n // so we need to check to see if we've already seen or chose this node before.\n\n if (nodes.length < 50) {\n // Randomly select k medoids from the n nodes\n for (var i = 0; i < k; i++) {\n var node = nodes[Math.floor(Math.random() * nodes.length)]; // If we've already chosen this node to be a medoid, don't choose it again (for small data sets).\n // Instead choose a different random node.\n\n while (seenBefore(node, medoids, i)) {\n node = nodes[Math.floor(Math.random() * nodes.length)];\n }\n\n medoids[i] = node;\n }\n } else {\n // Relatively large data set, so pretty safe to not check and just select random nodes\n for (var _i2 = 0; _i2 < k; _i2++) {\n medoids[_i2] = nodes[Math.floor(Math.random() * nodes.length)];\n }\n }\n\n return medoids;\n };\n\n var findCost = function findCost(potentialNewMedoid, cluster, attributes) {\n var cost = 0;\n\n for (var n = 0; n < cluster.length; n++) {\n cost += getDist('manhattan', cluster[n], potentialNewMedoid, attributes, 'kMedoids');\n }\n\n return cost;\n };\n\n var kMeans = function kMeans(options) {\n var cy = this.cy();\n var nodes = this.nodes();\n var node = null; // Set parameters of algorithm: # of clusters, distance metric, etc.\n\n var opts = setOptions$2(options); // Begin k-means algorithm\n\n var clusters = new Array(opts.k);\n var assignment = {};\n var centroids; // Step 1: Initialize centroid positions\n\n if (opts.testMode) {\n if (typeof opts.testCentroids === 'number') {\n // TODO: implement a seeded random number generator.\n opts.testCentroids;\n centroids = randomCentroids(nodes, opts.k, opts.attributes);\n } else if (_typeof(opts.testCentroids) === 'object') {\n centroids = opts.testCentroids;\n } else {\n centroids = randomCentroids(nodes, opts.k, opts.attributes);\n }\n } else {\n centroids = randomCentroids(nodes, opts.k, opts.attributes);\n }\n\n var isStillMoving = true;\n var iterations = 0;\n\n while (isStillMoving && iterations < opts.maxIterations) {\n // Step 2: Assign nodes to the nearest centroid\n for (var n = 0; n < nodes.length; n++) {\n node = nodes[n]; // Determine which cluster this node belongs to: node id => cluster #\n\n assignment[node.id()] = classify(node, centroids, opts.distance, opts.attributes, 'kMeans');\n } // Step 3: For each of the k clusters, update its centroid\n\n\n isStillMoving = false;\n\n for (var c = 0; c < opts.k; c++) {\n // Get all nodes that belong to this cluster\n var cluster = buildCluster(c, nodes, assignment);\n\n if (cluster.length === 0) {\n // If cluster is empty, break out early & move to next cluster\n continue;\n } // Update centroids by calculating avg of all nodes within the cluster.\n\n\n var ndim = opts.attributes.length;\n var centroid = centroids[c]; // [ dim_1, dim_2, dim_3, ... , dim_n ]\n\n var newCentroid = new Array(ndim);\n var sum = new Array(ndim);\n\n for (var d = 0; d < ndim; d++) {\n sum[d] = 0.0;\n\n for (var i = 0; i < cluster.length; i++) {\n node = cluster[i];\n sum[d] += opts.attributes[d](node);\n }\n\n newCentroid[d] = sum[d] / cluster.length; // Check to see if algorithm has converged, i.e. when centroids no longer change\n\n if (!haveValuesConverged(newCentroid[d], centroid[d], opts.sensitivityThreshold)) {\n isStillMoving = true;\n }\n }\n\n centroids[c] = newCentroid;\n clusters[c] = cy.collection(cluster);\n }\n\n iterations++;\n }\n\n return clusters;\n };\n\n var kMedoids = function kMedoids(options) {\n var cy = this.cy();\n var nodes = this.nodes();\n var node = null;\n var opts = setOptions$2(options); // Begin k-medoids algorithm\n\n var clusters = new Array(opts.k);\n var medoids;\n var assignment = {};\n var curCost;\n var minCosts = new Array(opts.k); // minimum cost configuration for each cluster\n // Step 1: Initialize k medoids\n\n if (opts.testMode) {\n if (typeof opts.testCentroids === 'number') ; else if (_typeof(opts.testCentroids) === 'object') {\n medoids = opts.testCentroids;\n } else {\n medoids = randomMedoids(nodes, opts.k);\n }\n } else {\n medoids = randomMedoids(nodes, opts.k);\n }\n\n var isStillMoving = true;\n var iterations = 0;\n\n while (isStillMoving && iterations < opts.maxIterations) {\n // Step 2: Assign nodes to the nearest medoid\n for (var n = 0; n < nodes.length; n++) {\n node = nodes[n]; // Determine which cluster this node belongs to: node id => cluster #\n\n assignment[node.id()] = classify(node, medoids, opts.distance, opts.attributes, 'kMedoids');\n }\n\n isStillMoving = false; // Step 3: For each medoid m, and for each node associated with mediod m,\n // select the node with the lowest configuration cost as new medoid.\n\n for (var m = 0; m < medoids.length; m++) {\n // Get all nodes that belong to this medoid\n var cluster = buildCluster(m, nodes, assignment);\n\n if (cluster.length === 0) {\n // If cluster is empty, break out early & move to next cluster\n continue;\n }\n\n minCosts[m] = findCost(medoids[m], cluster, opts.attributes); // original cost\n // Select different medoid if its configuration has the lowest cost\n\n for (var _n = 0; _n < cluster.length; _n++) {\n curCost = findCost(cluster[_n], cluster, opts.attributes);\n\n if (curCost < minCosts[m]) {\n minCosts[m] = curCost;\n medoids[m] = cluster[_n];\n isStillMoving = true;\n }\n }\n\n clusters[m] = cy.collection(cluster);\n }\n\n iterations++;\n }\n\n return clusters;\n };\n\n var updateCentroids = function updateCentroids(centroids, nodes, U, weight, opts) {\n var numerator, denominator;\n\n for (var n = 0; n < nodes.length; n++) {\n for (var c = 0; c < centroids.length; c++) {\n weight[n][c] = Math.pow(U[n][c], opts.m);\n }\n }\n\n for (var _c = 0; _c < centroids.length; _c++) {\n for (var dim = 0; dim < opts.attributes.length; dim++) {\n numerator = 0;\n denominator = 0;\n\n for (var _n2 = 0; _n2 < nodes.length; _n2++) {\n numerator += weight[_n2][_c] * opts.attributes[dim](nodes[_n2]);\n denominator += weight[_n2][_c];\n }\n\n centroids[_c][dim] = numerator / denominator;\n }\n }\n };\n\n var updateMembership = function updateMembership(U, _U, centroids, nodes, opts) {\n // Save previous step\n for (var i = 0; i < U.length; i++) {\n _U[i] = U[i].slice();\n }\n\n var sum, numerator, denominator;\n var pow = 2 / (opts.m - 1);\n\n for (var c = 0; c < centroids.length; c++) {\n for (var n = 0; n < nodes.length; n++) {\n sum = 0;\n\n for (var k = 0; k < centroids.length; k++) {\n // against all other centroids\n numerator = getDist(opts.distance, nodes[n], centroids[c], opts.attributes, 'cmeans');\n denominator = getDist(opts.distance, nodes[n], centroids[k], opts.attributes, 'cmeans');\n sum += Math.pow(numerator / denominator, pow);\n }\n\n U[n][c] = 1 / sum;\n }\n }\n };\n\n var assign$1 = function assign(nodes, U, opts, cy) {\n var clusters = new Array(opts.k);\n\n for (var c = 0; c < clusters.length; c++) {\n clusters[c] = [];\n }\n\n var max;\n var index;\n\n for (var n = 0; n < U.length; n++) {\n // for each node (U is N x C matrix)\n max = -Infinity;\n index = -1; // Determine which cluster the node is most likely to belong in\n\n for (var _c2 = 0; _c2 < U[0].length; _c2++) {\n if (U[n][_c2] > max) {\n max = U[n][_c2];\n index = _c2;\n }\n }\n\n clusters[index].push(nodes[n]);\n } // Turn every array into a collection of nodes\n\n\n for (var _c3 = 0; _c3 < clusters.length; _c3++) {\n clusters[_c3] = cy.collection(clusters[_c3]);\n }\n\n return clusters;\n };\n\n var fuzzyCMeans = function fuzzyCMeans(options) {\n var cy = this.cy();\n var nodes = this.nodes();\n var opts = setOptions$2(options); // Begin fuzzy c-means algorithm\n\n var clusters;\n var centroids;\n var U;\n\n var _U;\n\n var weight; // Step 1: Initialize letiables.\n\n _U = new Array(nodes.length);\n\n for (var i = 0; i < nodes.length; i++) {\n // N x C matrix\n _U[i] = new Array(opts.k);\n }\n\n U = new Array(nodes.length);\n\n for (var _i3 = 0; _i3 < nodes.length; _i3++) {\n // N x C matrix\n U[_i3] = new Array(opts.k);\n }\n\n for (var _i4 = 0; _i4 < nodes.length; _i4++) {\n var total = 0;\n\n for (var j = 0; j < opts.k; j++) {\n U[_i4][j] = Math.random();\n total += U[_i4][j];\n }\n\n for (var _j = 0; _j < opts.k; _j++) {\n U[_i4][_j] = U[_i4][_j] / total;\n }\n }\n\n centroids = new Array(opts.k);\n\n for (var _i5 = 0; _i5 < opts.k; _i5++) {\n centroids[_i5] = new Array(opts.attributes.length);\n }\n\n weight = new Array(nodes.length);\n\n for (var _i6 = 0; _i6 < nodes.length; _i6++) {\n // N x C matrix\n weight[_i6] = new Array(opts.k);\n } // end init FCM\n\n\n var isStillMoving = true;\n var iterations = 0;\n\n while (isStillMoving && iterations < opts.maxIterations) {\n isStillMoving = false; // Step 2: Calculate the centroids for each step.\n\n updateCentroids(centroids, nodes, U, weight, opts); // Step 3: Update the partition matrix U.\n\n updateMembership(U, _U, centroids, nodes, opts); // Step 4: Check for convergence.\n\n if (!haveMatricesConverged(U, _U, opts.sensitivityThreshold)) {\n isStillMoving = true;\n }\n\n iterations++;\n } // Assign nodes to clusters with highest probability.\n\n\n clusters = assign$1(nodes, U, opts, cy);\n return {\n clusters: clusters,\n degreeOfMembership: U\n };\n };\n\n var kClustering = {\n kMeans: kMeans,\n kMedoids: kMedoids,\n fuzzyCMeans: fuzzyCMeans,\n fcm: fuzzyCMeans\n };\n\n // Implemented by Zoe Xi @zoexi for GSOC 2016\n var defaults$a = defaults$g({\n distance: 'euclidean',\n // distance metric to compare nodes\n linkage: 'min',\n // linkage criterion : how to determine the distance between clusters of nodes\n mode: 'threshold',\n // mode:'threshold' => clusters must be threshold distance apart\n threshold: Infinity,\n // the distance threshold\n // mode:'dendrogram' => the nodes are organised as leaves in a tree (siblings are close), merging makes clusters\n addDendrogram: false,\n // whether to add the dendrogram to the graph for viz\n dendrogramDepth: 0,\n // depth at which dendrogram branches are merged into the returned clusters\n attributes: [] // array of attr functions\n\n });\n var linkageAliases = {\n 'single': 'min',\n 'complete': 'max'\n };\n\n var setOptions$1 = function setOptions(options) {\n var opts = defaults$a(options);\n var preferredAlias = linkageAliases[opts.linkage];\n\n if (preferredAlias != null) {\n opts.linkage = preferredAlias;\n }\n\n return opts;\n };\n\n var mergeClosest = function mergeClosest(clusters, index, dists, mins, opts) {\n // Find two closest clusters from cached mins\n var minKey = 0;\n var min = Infinity;\n var dist;\n var attrs = opts.attributes;\n\n var getDist = function getDist(n1, n2) {\n return clusteringDistance(opts.distance, attrs.length, function (i) {\n return attrs[i](n1);\n }, function (i) {\n return attrs[i](n2);\n }, n1, n2);\n };\n\n for (var i = 0; i < clusters.length; i++) {\n var key = clusters[i].key;\n var _dist = dists[key][mins[key]];\n\n if (_dist < min) {\n minKey = key;\n min = _dist;\n }\n }\n\n if (opts.mode === 'threshold' && min >= opts.threshold || opts.mode === 'dendrogram' && clusters.length === 1) {\n return false;\n }\n\n var c1 = index[minKey];\n var c2 = index[mins[minKey]];\n var merged; // Merge two closest clusters\n\n if (opts.mode === 'dendrogram') {\n merged = {\n left: c1,\n right: c2,\n key: c1.key\n };\n } else {\n merged = {\n value: c1.value.concat(c2.value),\n key: c1.key\n };\n }\n\n clusters[c1.index] = merged;\n clusters.splice(c2.index, 1);\n index[c1.key] = merged; // Update distances with new merged cluster\n\n for (var _i = 0; _i < clusters.length; _i++) {\n var cur = clusters[_i];\n\n if (c1.key === cur.key) {\n dist = Infinity;\n } else if (opts.linkage === 'min') {\n dist = dists[c1.key][cur.key];\n\n if (dists[c1.key][cur.key] > dists[c2.key][cur.key]) {\n dist = dists[c2.key][cur.key];\n }\n } else if (opts.linkage === 'max') {\n dist = dists[c1.key][cur.key];\n\n if (dists[c1.key][cur.key] < dists[c2.key][cur.key]) {\n dist = dists[c2.key][cur.key];\n }\n } else if (opts.linkage === 'mean') {\n dist = (dists[c1.key][cur.key] * c1.size + dists[c2.key][cur.key] * c2.size) / (c1.size + c2.size);\n } else {\n if (opts.mode === 'dendrogram') dist = getDist(cur.value, c1.value);else dist = getDist(cur.value[0], c1.value[0]);\n }\n\n dists[c1.key][cur.key] = dists[cur.key][c1.key] = dist; // distance matrix is symmetric\n } // Update cached mins\n\n\n for (var _i2 = 0; _i2 < clusters.length; _i2++) {\n var key1 = clusters[_i2].key;\n\n if (mins[key1] === c1.key || mins[key1] === c2.key) {\n var _min = key1;\n\n for (var j = 0; j < clusters.length; j++) {\n var key2 = clusters[j].key;\n\n if (dists[key1][key2] < dists[key1][_min]) {\n _min = key2;\n }\n }\n\n mins[key1] = _min;\n }\n\n clusters[_i2].index = _i2;\n } // Clean up meta data used for clustering\n\n\n c1.key = c2.key = c1.index = c2.index = null;\n return true;\n };\n\n var getAllChildren = function getAllChildren(root, arr, cy) {\n if (!root) return;\n\n if (root.value) {\n arr.push(root.value);\n } else {\n if (root.left) getAllChildren(root.left, arr);\n if (root.right) getAllChildren(root.right, arr);\n }\n };\n\n var buildDendrogram = function buildDendrogram(root, cy) {\n if (!root) return '';\n\n if (root.left && root.right) {\n var leftStr = buildDendrogram(root.left, cy);\n var rightStr = buildDendrogram(root.right, cy);\n var node = cy.add({\n group: 'nodes',\n data: {\n id: leftStr + ',' + rightStr\n }\n });\n cy.add({\n group: 'edges',\n data: {\n source: leftStr,\n target: node.id()\n }\n });\n cy.add({\n group: 'edges',\n data: {\n source: rightStr,\n target: node.id()\n }\n });\n return node.id();\n } else if (root.value) {\n return root.value.id();\n }\n };\n\n var buildClustersFromTree = function buildClustersFromTree(root, k, cy) {\n if (!root) return [];\n var left = [],\n right = [],\n leaves = [];\n\n if (k === 0) {\n // don't cut tree, simply return all nodes as 1 single cluster\n if (root.left) getAllChildren(root.left, left);\n if (root.right) getAllChildren(root.right, right);\n leaves = left.concat(right);\n return [cy.collection(leaves)];\n } else if (k === 1) {\n // cut at root\n if (root.value) {\n // leaf node\n return [cy.collection(root.value)];\n } else {\n if (root.left) getAllChildren(root.left, left);\n if (root.right) getAllChildren(root.right, right);\n return [cy.collection(left), cy.collection(right)];\n }\n } else {\n if (root.value) {\n return [cy.collection(root.value)];\n } else {\n if (root.left) left = buildClustersFromTree(root.left, k - 1, cy);\n if (root.right) right = buildClustersFromTree(root.right, k - 1, cy);\n return left.concat(right);\n }\n }\n };\n /* eslint-enable */\n\n\n var hierarchicalClustering = function hierarchicalClustering(options) {\n var cy = this.cy();\n var nodes = this.nodes(); // Set parameters of algorithm: linkage type, distance metric, etc.\n\n var opts = setOptions$1(options);\n var attrs = opts.attributes;\n\n var getDist = function getDist(n1, n2) {\n return clusteringDistance(opts.distance, attrs.length, function (i) {\n return attrs[i](n1);\n }, function (i) {\n return attrs[i](n2);\n }, n1, n2);\n }; // Begin hierarchical algorithm\n\n\n var clusters = [];\n var dists = []; // distances between each pair of clusters\n\n var mins = []; // closest cluster for each cluster\n\n var index = []; // hash of all clusters by key\n // In agglomerative (bottom-up) clustering, each node starts as its own cluster\n\n for (var n = 0; n < nodes.length; n++) {\n var cluster = {\n value: opts.mode === 'dendrogram' ? nodes[n] : [nodes[n]],\n key: n,\n index: n\n };\n clusters[n] = cluster;\n index[n] = cluster;\n dists[n] = [];\n mins[n] = 0;\n } // Calculate the distance between each pair of clusters\n\n\n for (var i = 0; i < clusters.length; i++) {\n for (var j = 0; j <= i; j++) {\n var dist = void 0;\n\n if (opts.mode === 'dendrogram') {\n // modes store cluster values differently\n dist = i === j ? Infinity : getDist(clusters[i].value, clusters[j].value);\n } else {\n dist = i === j ? Infinity : getDist(clusters[i].value[0], clusters[j].value[0]);\n }\n\n dists[i][j] = dist;\n dists[j][i] = dist;\n\n if (dist < dists[i][mins[i]]) {\n mins[i] = j; // Cache mins: closest cluster to cluster i is cluster j\n }\n }\n } // Find the closest pair of clusters and merge them into a single cluster.\n // Update distances between new cluster and each of the old clusters, and loop until threshold reached.\n\n\n var merged = mergeClosest(clusters, index, dists, mins, opts);\n\n while (merged) {\n merged = mergeClosest(clusters, index, dists, mins, opts);\n }\n\n var retClusters; // Dendrogram mode builds the hierarchy and adds intermediary nodes + edges\n // in addition to returning the clusters.\n\n if (opts.mode === 'dendrogram') {\n retClusters = buildClustersFromTree(clusters[0], opts.dendrogramDepth, cy);\n if (opts.addDendrogram) buildDendrogram(clusters[0], cy);\n } else {\n // Regular mode simply returns the clusters\n retClusters = new Array(clusters.length);\n clusters.forEach(function (cluster, i) {\n // Clean up meta data used for clustering\n cluster.key = cluster.index = null;\n retClusters[i] = cy.collection(cluster.value);\n });\n }\n\n return retClusters;\n };\n\n var hierarchicalClustering$1 = {\n hierarchicalClustering: hierarchicalClustering,\n hca: hierarchicalClustering\n };\n\n // Implemented by Zoe Xi @zoexi for GSOC 2016\n var defaults$9 = defaults$g({\n distance: 'euclidean',\n // distance metric to compare attributes between two nodes\n preference: 'median',\n // suitability of a data point to serve as an exemplar\n damping: 0.8,\n // damping factor between [0.5, 1)\n maxIterations: 1000,\n // max number of iterations to run\n minIterations: 100,\n // min number of iterations to run in order for clustering to stop\n attributes: [// functions to quantify the similarity between any two points\n // e.g. node => node.data('weight')\n ]\n });\n\n var setOptions = function setOptions(options) {\n var dmp = options.damping;\n var pref = options.preference;\n\n if (!(0.5 <= dmp && dmp < 1)) {\n error(\"Damping must range on [0.5, 1). Got: \".concat(dmp));\n }\n\n var validPrefs = ['median', 'mean', 'min', 'max'];\n\n if (!(validPrefs.some(function (v) {\n return v === pref;\n }) || number$1(pref))) {\n error(\"Preference must be one of [\".concat(validPrefs.map(function (p) {\n return \"'\".concat(p, \"'\");\n }).join(', '), \"] or a number. Got: \").concat(pref));\n }\n\n return defaults$9(options);\n };\n /* eslint-enable */\n\n\n var getSimilarity = function getSimilarity(type, n1, n2, attributes) {\n var attr = function attr(n, i) {\n return attributes[i](n);\n }; // nb negative because similarity should have an inverse relationship to distance\n\n\n return -clusteringDistance(type, attributes.length, function (i) {\n return attr(n1, i);\n }, function (i) {\n return attr(n2, i);\n }, n1, n2);\n };\n\n var getPreference = function getPreference(S, preference) {\n // larger preference = greater # of clusters\n var p = null;\n\n if (preference === 'median') {\n p = median(S);\n } else if (preference === 'mean') {\n p = mean(S);\n } else if (preference === 'min') {\n p = min(S);\n } else if (preference === 'max') {\n p = max(S);\n } else {\n // Custom preference number, as set by user\n p = preference;\n }\n\n return p;\n };\n\n var findExemplars = function findExemplars(n, R, A) {\n var indices = [];\n\n for (var i = 0; i < n; i++) {\n if (R[i * n + i] + A[i * n + i] > 0) {\n indices.push(i);\n }\n }\n\n return indices;\n };\n\n var assignClusters = function assignClusters(n, S, exemplars) {\n var clusters = [];\n\n for (var i = 0; i < n; i++) {\n var index = -1;\n var max = -Infinity;\n\n for (var ei = 0; ei < exemplars.length; ei++) {\n var e = exemplars[ei];\n\n if (S[i * n + e] > max) {\n index = e;\n max = S[i * n + e];\n }\n }\n\n if (index > 0) {\n clusters.push(index);\n }\n }\n\n for (var _ei = 0; _ei < exemplars.length; _ei++) {\n clusters[exemplars[_ei]] = exemplars[_ei];\n }\n\n return clusters;\n };\n\n var assign = function assign(n, S, exemplars) {\n var clusters = assignClusters(n, S, exemplars);\n\n for (var ei = 0; ei < exemplars.length; ei++) {\n var ii = [];\n\n for (var c = 0; c < clusters.length; c++) {\n if (clusters[c] === exemplars[ei]) {\n ii.push(c);\n }\n }\n\n var maxI = -1;\n var maxSum = -Infinity;\n\n for (var i = 0; i < ii.length; i++) {\n var sum = 0;\n\n for (var j = 0; j < ii.length; j++) {\n sum += S[ii[j] * n + ii[i]];\n }\n\n if (sum > maxSum) {\n maxI = i;\n maxSum = sum;\n }\n }\n\n exemplars[ei] = ii[maxI];\n }\n\n clusters = assignClusters(n, S, exemplars);\n return clusters;\n };\n\n var affinityPropagation = function affinityPropagation(options) {\n var cy = this.cy();\n var nodes = this.nodes();\n var opts = setOptions(options); // Map each node to its position in node array\n\n var id2position = {};\n\n for (var i = 0; i < nodes.length; i++) {\n id2position[nodes[i].id()] = i;\n } // Begin affinity propagation algorithm\n\n\n var n; // number of data points\n\n var n2; // size of matrices\n\n var S; // similarity matrix (1D array)\n\n var p; // preference/suitability of a data point to serve as an exemplar\n\n var R; // responsibility matrix (1D array)\n\n var A; // availability matrix (1D array)\n\n n = nodes.length;\n n2 = n * n; // Initialize and build S similarity matrix\n\n S = new Array(n2);\n\n for (var _i = 0; _i < n2; _i++) {\n S[_i] = -Infinity; // for cases where two data points shouldn't be linked together\n }\n\n for (var _i2 = 0; _i2 < n; _i2++) {\n for (var j = 0; j < n; j++) {\n if (_i2 !== j) {\n S[_i2 * n + j] = getSimilarity(opts.distance, nodes[_i2], nodes[j], opts.attributes);\n }\n }\n } // Place preferences on the diagonal of S\n\n\n p = getPreference(S, opts.preference);\n\n for (var _i3 = 0; _i3 < n; _i3++) {\n S[_i3 * n + _i3] = p;\n } // Initialize R responsibility matrix\n\n\n R = new Array(n2);\n\n for (var _i4 = 0; _i4 < n2; _i4++) {\n R[_i4] = 0.0;\n } // Initialize A availability matrix\n\n\n A = new Array(n2);\n\n for (var _i5 = 0; _i5 < n2; _i5++) {\n A[_i5] = 0.0;\n }\n\n var old = new Array(n);\n var Rp = new Array(n);\n var se = new Array(n);\n\n for (var _i6 = 0; _i6 < n; _i6++) {\n old[_i6] = 0.0;\n Rp[_i6] = 0.0;\n se[_i6] = 0;\n }\n\n var e = new Array(n * opts.minIterations);\n\n for (var _i7 = 0; _i7 < e.length; _i7++) {\n e[_i7] = 0;\n }\n\n var iter;\n\n for (iter = 0; iter < opts.maxIterations; iter++) {\n // main algorithmic loop\n // Update R responsibility matrix\n for (var _i8 = 0; _i8 < n; _i8++) {\n var max = -Infinity,\n max2 = -Infinity,\n maxI = -1,\n AS = 0.0;\n\n for (var _j = 0; _j < n; _j++) {\n old[_j] = R[_i8 * n + _j];\n AS = A[_i8 * n + _j] + S[_i8 * n + _j];\n\n if (AS >= max) {\n max2 = max;\n max = AS;\n maxI = _j;\n } else if (AS > max2) {\n max2 = AS;\n }\n }\n\n for (var _j2 = 0; _j2 < n; _j2++) {\n R[_i8 * n + _j2] = (1 - opts.damping) * (S[_i8 * n + _j2] - max) + opts.damping * old[_j2];\n }\n\n R[_i8 * n + maxI] = (1 - opts.damping) * (S[_i8 * n + maxI] - max2) + opts.damping * old[maxI];\n } // Update A availability matrix\n\n\n for (var _i9 = 0; _i9 < n; _i9++) {\n var sum = 0;\n\n for (var _j3 = 0; _j3 < n; _j3++) {\n old[_j3] = A[_j3 * n + _i9];\n Rp[_j3] = Math.max(0, R[_j3 * n + _i9]);\n sum += Rp[_j3];\n }\n\n sum -= Rp[_i9];\n Rp[_i9] = R[_i9 * n + _i9];\n sum += Rp[_i9];\n\n for (var _j4 = 0; _j4 < n; _j4++) {\n A[_j4 * n + _i9] = (1 - opts.damping) * Math.min(0, sum - Rp[_j4]) + opts.damping * old[_j4];\n }\n\n A[_i9 * n + _i9] = (1 - opts.damping) * (sum - Rp[_i9]) + opts.damping * old[_i9];\n } // Check for convergence\n\n\n var K = 0;\n\n for (var _i10 = 0; _i10 < n; _i10++) {\n var E = A[_i10 * n + _i10] + R[_i10 * n + _i10] > 0 ? 1 : 0;\n e[iter % opts.minIterations * n + _i10] = E;\n K += E;\n }\n\n if (K > 0 && (iter >= opts.minIterations - 1 || iter == opts.maxIterations - 1)) {\n var _sum = 0;\n\n for (var _i11 = 0; _i11 < n; _i11++) {\n se[_i11] = 0;\n\n for (var _j5 = 0; _j5 < opts.minIterations; _j5++) {\n se[_i11] += e[_j5 * n + _i11];\n }\n\n if (se[_i11] === 0 || se[_i11] === opts.minIterations) {\n _sum++;\n }\n }\n\n if (_sum === n) {\n // then we have convergence\n break;\n }\n }\n } // Identify exemplars (cluster centers)\n\n\n var exemplarsIndices = findExemplars(n, R, A); // Assign nodes to clusters\n\n var clusterIndices = assign(n, S, exemplarsIndices);\n var clusters = {};\n\n for (var c = 0; c < exemplarsIndices.length; c++) {\n clusters[exemplarsIndices[c]] = [];\n }\n\n for (var _i12 = 0; _i12 < nodes.length; _i12++) {\n var pos = id2position[nodes[_i12].id()];\n\n var clusterIndex = clusterIndices[pos];\n\n if (clusterIndex != null) {\n // the node may have not been assigned a cluster if no valid attributes were specified\n clusters[clusterIndex].push(nodes[_i12]);\n }\n }\n\n var retClusters = new Array(exemplarsIndices.length);\n\n for (var _c = 0; _c < exemplarsIndices.length; _c++) {\n retClusters[_c] = cy.collection(clusters[exemplarsIndices[_c]]);\n }\n\n return retClusters;\n };\n\n var affinityPropagation$1 = {\n affinityPropagation: affinityPropagation,\n ap: affinityPropagation\n };\n\n var hierholzerDefaults = defaults$g({\n root: undefined,\n directed: false\n });\n var elesfn$k = {\n hierholzer: function hierholzer(options) {\n if (!plainObject(options)) {\n var args = arguments;\n options = {\n root: args[0],\n directed: args[1]\n };\n }\n\n var _hierholzerDefaults = hierholzerDefaults(options),\n root = _hierholzerDefaults.root,\n directed = _hierholzerDefaults.directed;\n\n var eles = this;\n var dflag = false;\n var oddIn;\n var oddOut;\n var startVertex;\n if (root) startVertex = string(root) ? this.filter(root)[0].id() : root[0].id();\n var nodes = {};\n var edges = {};\n\n if (directed) {\n eles.forEach(function (ele) {\n var id = ele.id();\n\n if (ele.isNode()) {\n var ind = ele.indegree(true);\n var outd = ele.outdegree(true);\n var d1 = ind - outd;\n var d2 = outd - ind;\n\n if (d1 == 1) {\n if (oddIn) dflag = true;else oddIn = id;\n } else if (d2 == 1) {\n if (oddOut) dflag = true;else oddOut = id;\n } else if (d2 > 1 || d1 > 1) {\n dflag = true;\n }\n\n nodes[id] = [];\n ele.outgoers().forEach(function (e) {\n if (e.isEdge()) nodes[id].push(e.id());\n });\n } else {\n edges[id] = [undefined, ele.target().id()];\n }\n });\n } else {\n eles.forEach(function (ele) {\n var id = ele.id();\n\n if (ele.isNode()) {\n var d = ele.degree(true);\n\n if (d % 2) {\n if (!oddIn) oddIn = id;else if (!oddOut) oddOut = id;else dflag = true;\n }\n\n nodes[id] = [];\n ele.connectedEdges().forEach(function (e) {\n return nodes[id].push(e.id());\n });\n } else {\n edges[id] = [ele.source().id(), ele.target().id()];\n }\n });\n }\n\n var result = {\n found: false,\n trail: undefined\n };\n if (dflag) return result;else if (oddOut && oddIn) {\n if (directed) {\n if (startVertex && oddOut != startVertex) {\n return result;\n }\n\n startVertex = oddOut;\n } else {\n if (startVertex && oddOut != startVertex && oddIn != startVertex) {\n return result;\n } else if (!startVertex) {\n startVertex = oddOut;\n }\n }\n } else {\n if (!startVertex) startVertex = eles[0].id();\n }\n\n var walk = function walk(v) {\n var currentNode = v;\n var subtour = [v];\n var adj, adjTail, adjHead;\n\n while (nodes[currentNode].length) {\n adj = nodes[currentNode].shift();\n adjTail = edges[adj][0];\n adjHead = edges[adj][1];\n\n if (currentNode != adjHead) {\n nodes[adjHead] = nodes[adjHead].filter(function (e) {\n return e != adj;\n });\n currentNode = adjHead;\n } else if (!directed && currentNode != adjTail) {\n nodes[adjTail] = nodes[adjTail].filter(function (e) {\n return e != adj;\n });\n currentNode = adjTail;\n }\n\n subtour.unshift(adj);\n subtour.unshift(currentNode);\n }\n\n return subtour;\n };\n\n var trail = [];\n var subtour = [];\n subtour = walk(startVertex);\n\n while (subtour.length != 1) {\n if (nodes[subtour[0]].length == 0) {\n trail.unshift(eles.getElementById(subtour.shift()));\n trail.unshift(eles.getElementById(subtour.shift()));\n } else {\n subtour = walk(subtour.shift()).concat(subtour);\n }\n }\n\n trail.unshift(eles.getElementById(subtour.shift())); // final node\n\n for (var d in nodes) {\n if (nodes[d].length) {\n return result;\n }\n }\n\n result.found = true;\n result.trail = this.spawn(trail, true);\n return result;\n }\n };\n\n var hopcroftTarjanBiconnected = function hopcroftTarjanBiconnected() {\n var eles = this;\n var nodes = {};\n var id = 0;\n var edgeCount = 0;\n var components = [];\n var stack = [];\n var visitedEdges = {};\n\n var buildComponent = function buildComponent(x, y) {\n var i = stack.length - 1;\n var cutset = [];\n var component = eles.spawn();\n\n while (stack[i].x != x || stack[i].y != y) {\n cutset.push(stack.pop().edge);\n i--;\n }\n\n cutset.push(stack.pop().edge);\n cutset.forEach(function (edge) {\n var connectedNodes = edge.connectedNodes().intersection(eles);\n component.merge(edge);\n connectedNodes.forEach(function (node) {\n var nodeId = node.id();\n var connectedEdges = node.connectedEdges().intersection(eles);\n component.merge(node);\n\n if (!nodes[nodeId].cutVertex) {\n component.merge(connectedEdges);\n } else {\n component.merge(connectedEdges.filter(function (edge) {\n return edge.isLoop();\n }));\n }\n });\n });\n components.push(component);\n };\n\n var biconnectedSearch = function biconnectedSearch(root, currentNode, parent) {\n if (root === parent) edgeCount += 1;\n nodes[currentNode] = {\n id: id,\n low: id++,\n cutVertex: false\n };\n var edges = eles.getElementById(currentNode).connectedEdges().intersection(eles);\n\n if (edges.size() === 0) {\n components.push(eles.spawn(eles.getElementById(currentNode)));\n } else {\n var sourceId, targetId, otherNodeId, edgeId;\n edges.forEach(function (edge) {\n sourceId = edge.source().id();\n targetId = edge.target().id();\n otherNodeId = sourceId === currentNode ? targetId : sourceId;\n\n if (otherNodeId !== parent) {\n edgeId = edge.id();\n\n if (!visitedEdges[edgeId]) {\n visitedEdges[edgeId] = true;\n stack.push({\n x: currentNode,\n y: otherNodeId,\n edge: edge\n });\n }\n\n if (!(otherNodeId in nodes)) {\n biconnectedSearch(root, otherNodeId, currentNode);\n nodes[currentNode].low = Math.min(nodes[currentNode].low, nodes[otherNodeId].low);\n\n if (nodes[currentNode].id <= nodes[otherNodeId].low) {\n nodes[currentNode].cutVertex = true;\n buildComponent(currentNode, otherNodeId);\n }\n } else {\n nodes[currentNode].low = Math.min(nodes[currentNode].low, nodes[otherNodeId].id);\n }\n }\n });\n }\n };\n\n eles.forEach(function (ele) {\n if (ele.isNode()) {\n var nodeId = ele.id();\n\n if (!(nodeId in nodes)) {\n edgeCount = 0;\n biconnectedSearch(nodeId, nodeId);\n nodes[nodeId].cutVertex = edgeCount > 1;\n }\n }\n });\n var cutVertices = Object.keys(nodes).filter(function (id) {\n return nodes[id].cutVertex;\n }).map(function (id) {\n return eles.getElementById(id);\n });\n return {\n cut: eles.spawn(cutVertices),\n components: components\n };\n };\n\n var hopcroftTarjanBiconnected$1 = {\n hopcroftTarjanBiconnected: hopcroftTarjanBiconnected,\n htbc: hopcroftTarjanBiconnected,\n htb: hopcroftTarjanBiconnected,\n hopcroftTarjanBiconnectedComponents: hopcroftTarjanBiconnected\n };\n\n var tarjanStronglyConnected = function tarjanStronglyConnected() {\n var eles = this;\n var nodes = {};\n var index = 0;\n var components = [];\n var stack = [];\n var cut = eles.spawn(eles);\n\n var stronglyConnectedSearch = function stronglyConnectedSearch(sourceNodeId) {\n stack.push(sourceNodeId);\n nodes[sourceNodeId] = {\n index: index,\n low: index++,\n explored: false\n };\n var connectedEdges = eles.getElementById(sourceNodeId).connectedEdges().intersection(eles);\n connectedEdges.forEach(function (edge) {\n var targetNodeId = edge.target().id();\n\n if (targetNodeId !== sourceNodeId) {\n if (!(targetNodeId in nodes)) {\n stronglyConnectedSearch(targetNodeId);\n }\n\n if (!nodes[targetNodeId].explored) {\n nodes[sourceNodeId].low = Math.min(nodes[sourceNodeId].low, nodes[targetNodeId].low);\n }\n }\n });\n\n if (nodes[sourceNodeId].index === nodes[sourceNodeId].low) {\n var componentNodes = eles.spawn();\n\n for (;;) {\n var nodeId = stack.pop();\n componentNodes.merge(eles.getElementById(nodeId));\n nodes[nodeId].low = nodes[sourceNodeId].index;\n nodes[nodeId].explored = true;\n\n if (nodeId === sourceNodeId) {\n break;\n }\n }\n\n var componentEdges = componentNodes.edgesWith(componentNodes);\n var component = componentNodes.merge(componentEdges);\n components.push(component);\n cut = cut.difference(component);\n }\n };\n\n eles.forEach(function (ele) {\n if (ele.isNode()) {\n var nodeId = ele.id();\n\n if (!(nodeId in nodes)) {\n stronglyConnectedSearch(nodeId);\n }\n }\n });\n return {\n cut: cut,\n components: components\n };\n };\n\n var tarjanStronglyConnected$1 = {\n tarjanStronglyConnected: tarjanStronglyConnected,\n tsc: tarjanStronglyConnected,\n tscc: tarjanStronglyConnected,\n tarjanStronglyConnectedComponents: tarjanStronglyConnected\n };\n\n var elesfn$j = {};\n [elesfn$v, elesfn$u, elesfn$t, elesfn$s, elesfn$r, elesfn$q, elesfn$p, elesfn$o, elesfn$n, elesfn$m, elesfn$l, markovClustering$1, kClustering, hierarchicalClustering$1, affinityPropagation$1, elesfn$k, hopcroftTarjanBiconnected$1, tarjanStronglyConnected$1].forEach(function (props) {\n extend(elesfn$j, props);\n });\n\n /*!\n Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable\n Copyright (c) 2013-2014 Ralf S. Engelschall (http://engelschall.com)\n Licensed under The MIT License (http://opensource.org/licenses/MIT)\n */\n\n /* promise states [Promises/A+ 2.1] */\n var STATE_PENDING = 0;\n /* [Promises/A+ 2.1.1] */\n\n var STATE_FULFILLED = 1;\n /* [Promises/A+ 2.1.2] */\n\n var STATE_REJECTED = 2;\n /* [Promises/A+ 2.1.3] */\n\n /* promise object constructor */\n\n var api = function api(executor) {\n /* optionally support non-constructor/plain-function call */\n if (!(this instanceof api)) return new api(executor);\n /* initialize object */\n\n this.id = 'Thenable/1.0.7';\n this.state = STATE_PENDING;\n /* initial state */\n\n this.fulfillValue = undefined;\n /* initial value */\n\n /* [Promises/A+ 1.3, 2.1.2.2] */\n\n this.rejectReason = undefined;\n /* initial reason */\n\n /* [Promises/A+ 1.5, 2.1.3.2] */\n\n this.onFulfilled = [];\n /* initial handlers */\n\n this.onRejected = [];\n /* initial handlers */\n\n /* provide optional information-hiding proxy */\n\n this.proxy = {\n then: this.then.bind(this)\n };\n /* support optional executor function */\n\n if (typeof executor === 'function') executor.call(this, this.fulfill.bind(this), this.reject.bind(this));\n };\n /* promise API methods */\n\n\n api.prototype = {\n /* promise resolving methods */\n fulfill: function fulfill(value) {\n return deliver(this, STATE_FULFILLED, 'fulfillValue', value);\n },\n reject: function reject(value) {\n return deliver(this, STATE_REJECTED, 'rejectReason', value);\n },\n\n /* \"The then Method\" [Promises/A+ 1.1, 1.2, 2.2] */\n then: function then(onFulfilled, onRejected) {\n var curr = this;\n var next = new api();\n /* [Promises/A+ 2.2.7] */\n\n curr.onFulfilled.push(resolver(onFulfilled, next, 'fulfill'));\n /* [Promises/A+ 2.2.2/2.2.6] */\n\n curr.onRejected.push(resolver(onRejected, next, 'reject'));\n /* [Promises/A+ 2.2.3/2.2.6] */\n\n execute(curr);\n return next.proxy;\n /* [Promises/A+ 2.2.7, 3.3] */\n }\n };\n /* deliver an action */\n\n var deliver = function deliver(curr, state, name, value) {\n if (curr.state === STATE_PENDING) {\n curr.state = state;\n /* [Promises/A+ 2.1.2.1, 2.1.3.1] */\n\n curr[name] = value;\n /* [Promises/A+ 2.1.2.2, 2.1.3.2] */\n\n execute(curr);\n }\n\n return curr;\n };\n /* execute all handlers */\n\n\n var execute = function execute(curr) {\n if (curr.state === STATE_FULFILLED) execute_handlers(curr, 'onFulfilled', curr.fulfillValue);else if (curr.state === STATE_REJECTED) execute_handlers(curr, 'onRejected', curr.rejectReason);\n };\n /* execute particular set of handlers */\n\n\n var execute_handlers = function execute_handlers(curr, name, value) {\n /* global setImmediate: true */\n\n /* global setTimeout: true */\n\n /* short-circuit processing */\n if (curr[name].length === 0) return;\n /* iterate over all handlers, exactly once */\n\n var handlers = curr[name];\n curr[name] = [];\n /* [Promises/A+ 2.2.2.3, 2.2.3.3] */\n\n var func = function func() {\n for (var i = 0; i < handlers.length; i++) {\n handlers[i](value);\n }\n /* [Promises/A+ 2.2.5] */\n\n };\n /* execute procedure asynchronously */\n\n /* [Promises/A+ 2.2.4, 3.1] */\n\n\n if (typeof setImmediate === 'function') setImmediate(func);else setTimeout(func, 0);\n };\n /* generate a resolver function */\n\n\n var resolver = function resolver(cb, next, method) {\n return function (value) {\n if (typeof cb !== 'function')\n /* [Promises/A+ 2.2.1, 2.2.7.3, 2.2.7.4] */\n next[method].call(next, value);\n /* [Promises/A+ 2.2.7.3, 2.2.7.4] */\n else {\n var result;\n\n try {\n result = cb(value);\n }\n /* [Promises/A+ 2.2.2.1, 2.2.3.1, 2.2.5, 3.2] */\n catch (e) {\n next.reject(e);\n /* [Promises/A+ 2.2.7.2] */\n\n return;\n }\n\n resolve(next, result);\n /* [Promises/A+ 2.2.7.1] */\n }\n };\n };\n /* \"Promise Resolution Procedure\" */\n\n /* [Promises/A+ 2.3] */\n\n\n var resolve = function resolve(promise, x) {\n /* sanity check arguments */\n\n /* [Promises/A+ 2.3.1] */\n if (promise === x || promise.proxy === x) {\n promise.reject(new TypeError('cannot resolve promise with itself'));\n return;\n }\n /* surgically check for a \"then\" method\n (mainly to just call the \"getter\" of \"then\" only once) */\n\n\n var then;\n\n if (_typeof(x) === 'object' && x !== null || typeof x === 'function') {\n try {\n then = x.then;\n }\n /* [Promises/A+ 2.3.3.1, 3.5] */\n catch (e) {\n promise.reject(e);\n /* [Promises/A+ 2.3.3.2] */\n\n return;\n }\n }\n /* handle own Thenables [Promises/A+ 2.3.2]\n and similar \"thenables\" [Promises/A+ 2.3.3] */\n\n\n if (typeof then === 'function') {\n var resolved = false;\n\n try {\n /* call retrieved \"then\" method */\n\n /* [Promises/A+ 2.3.3.3] */\n then.call(x,\n /* resolvePromise */\n\n /* [Promises/A+ 2.3.3.3.1] */\n function (y) {\n if (resolved) return;\n resolved = true;\n /* [Promises/A+ 2.3.3.3.3] */\n\n if (y === x)\n /* [Promises/A+ 3.6] */\n promise.reject(new TypeError('circular thenable chain'));else resolve(promise, y);\n },\n /* rejectPromise */\n\n /* [Promises/A+ 2.3.3.3.2] */\n function (r) {\n if (resolved) return;\n resolved = true;\n /* [Promises/A+ 2.3.3.3.3] */\n\n promise.reject(r);\n });\n } catch (e) {\n if (!resolved)\n /* [Promises/A+ 2.3.3.3.3] */\n promise.reject(e);\n /* [Promises/A+ 2.3.3.3.4] */\n }\n\n return;\n }\n /* handle other values */\n\n\n promise.fulfill(x);\n /* [Promises/A+ 2.3.4, 2.3.3.4] */\n }; // so we always have Promise.all()\n\n\n api.all = function (ps) {\n return new api(function (resolveAll, rejectAll) {\n var vals = new Array(ps.length);\n var doneCount = 0;\n\n var fulfill = function fulfill(i, val) {\n vals[i] = val;\n doneCount++;\n\n if (doneCount === ps.length) {\n resolveAll(vals);\n }\n };\n\n for (var i = 0; i < ps.length; i++) {\n (function (i) {\n var p = ps[i];\n var isPromise = p != null && p.then != null;\n\n if (isPromise) {\n p.then(function (val) {\n fulfill(i, val);\n }, function (err) {\n rejectAll(err);\n });\n } else {\n var val = p;\n fulfill(i, val);\n }\n })(i);\n }\n });\n };\n\n api.resolve = function (val) {\n return new api(function (resolve, reject) {\n resolve(val);\n });\n };\n\n api.reject = function (val) {\n return new api(function (resolve, reject) {\n reject(val);\n });\n };\n\n var Promise$1 = typeof Promise !== 'undefined' ? Promise : api; // eslint-disable-line no-undef\n\n var Animation = function Animation(target, opts, opts2) {\n var isCore = core(target);\n var isEle = !isCore;\n\n var _p = this._private = extend({\n duration: 1000\n }, opts, opts2);\n\n _p.target = target;\n _p.style = _p.style || _p.css;\n _p.started = false;\n _p.playing = false;\n _p.hooked = false;\n _p.applying = false;\n _p.progress = 0;\n _p.completes = [];\n _p.frames = [];\n\n if (_p.complete && fn$6(_p.complete)) {\n _p.completes.push(_p.complete);\n }\n\n if (isEle) {\n var pos = target.position();\n _p.startPosition = _p.startPosition || {\n x: pos.x,\n y: pos.y\n };\n _p.startStyle = _p.startStyle || target.cy().style().getAnimationStartStyle(target, _p.style);\n }\n\n if (isCore) {\n var pan = target.pan();\n _p.startPan = {\n x: pan.x,\n y: pan.y\n };\n _p.startZoom = target.zoom();\n } // for future timeline/animations impl\n\n\n this.length = 1;\n this[0] = this;\n };\n\n var anifn = Animation.prototype;\n extend(anifn, {\n instanceString: function instanceString() {\n return 'animation';\n },\n hook: function hook() {\n var _p = this._private;\n\n if (!_p.hooked) {\n // add to target's animation queue\n var q;\n var tAni = _p.target._private.animation;\n\n if (_p.queue) {\n q = tAni.queue;\n } else {\n q = tAni.current;\n }\n\n q.push(this); // add to the animation loop pool\n\n if (elementOrCollection(_p.target)) {\n _p.target.cy().addToAnimationPool(_p.target);\n }\n\n _p.hooked = true;\n }\n\n return this;\n },\n play: function play() {\n var _p = this._private; // autorewind\n\n if (_p.progress === 1) {\n _p.progress = 0;\n }\n\n _p.playing = true;\n _p.started = false; // needs to be started by animation loop\n\n _p.stopped = false;\n this.hook(); // the animation loop will start the animation...\n\n return this;\n },\n playing: function playing() {\n return this._private.playing;\n },\n apply: function apply() {\n var _p = this._private;\n _p.applying = true;\n _p.started = false; // needs to be started by animation loop\n\n _p.stopped = false;\n this.hook(); // the animation loop will apply the animation at this progress\n\n return this;\n },\n applying: function applying() {\n return this._private.applying;\n },\n pause: function pause() {\n var _p = this._private;\n _p.playing = false;\n _p.started = false;\n return this;\n },\n stop: function stop() {\n var _p = this._private;\n _p.playing = false;\n _p.started = false;\n _p.stopped = true; // to be removed from animation queues\n\n return this;\n },\n rewind: function rewind() {\n return this.progress(0);\n },\n fastforward: function fastforward() {\n return this.progress(1);\n },\n time: function time(t) {\n var _p = this._private;\n\n if (t === undefined) {\n return _p.progress * _p.duration;\n } else {\n return this.progress(t / _p.duration);\n }\n },\n progress: function progress(p) {\n var _p = this._private;\n var wasPlaying = _p.playing;\n\n if (p === undefined) {\n return _p.progress;\n } else {\n if (wasPlaying) {\n this.pause();\n }\n\n _p.progress = p;\n _p.started = false;\n\n if (wasPlaying) {\n this.play();\n }\n }\n\n return this;\n },\n completed: function completed() {\n return this._private.progress === 1;\n },\n reverse: function reverse() {\n var _p = this._private;\n var wasPlaying = _p.playing;\n\n if (wasPlaying) {\n this.pause();\n }\n\n _p.progress = 1 - _p.progress;\n _p.started = false;\n\n var swap = function swap(a, b) {\n var _pa = _p[a];\n\n if (_pa == null) {\n return;\n }\n\n _p[a] = _p[b];\n _p[b] = _pa;\n };\n\n swap('zoom', 'startZoom');\n swap('pan', 'startPan');\n swap('position', 'startPosition'); // swap styles\n\n if (_p.style) {\n for (var i = 0; i < _p.style.length; i++) {\n var prop = _p.style[i];\n var name = prop.name;\n var startStyleProp = _p.startStyle[name];\n _p.startStyle[name] = prop;\n _p.style[i] = startStyleProp;\n }\n }\n\n if (wasPlaying) {\n this.play();\n }\n\n return this;\n },\n promise: function promise(type) {\n var _p = this._private;\n var arr;\n\n switch (type) {\n case 'frame':\n arr = _p.frames;\n break;\n\n default:\n case 'complete':\n case 'completed':\n arr = _p.completes;\n }\n\n return new Promise$1(function (resolve, reject) {\n arr.push(function () {\n resolve();\n });\n });\n }\n });\n anifn.complete = anifn.completed;\n anifn.run = anifn.play;\n anifn.running = anifn.playing;\n\n var define$3 = {\n animated: function animated() {\n return function animatedImpl() {\n var self = this;\n var selfIsArrayLike = self.length !== undefined;\n var all = selfIsArrayLike ? self : [self]; // put in array if not array-like\n\n var cy = this._private.cy || this;\n\n if (!cy.styleEnabled()) {\n return false;\n }\n\n var ele = all[0];\n\n if (ele) {\n return ele._private.animation.current.length > 0;\n }\n };\n },\n // animated\n clearQueue: function clearQueue() {\n return function clearQueueImpl() {\n var self = this;\n var selfIsArrayLike = self.length !== undefined;\n var all = selfIsArrayLike ? self : [self]; // put in array if not array-like\n\n var cy = this._private.cy || this;\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n for (var i = 0; i < all.length; i++) {\n var ele = all[i];\n ele._private.animation.queue = [];\n }\n\n return this;\n };\n },\n // clearQueue\n delay: function delay() {\n return function delayImpl(time, complete) {\n var cy = this._private.cy || this;\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n return this.animate({\n delay: time,\n duration: time,\n complete: complete\n });\n };\n },\n // delay\n delayAnimation: function delayAnimation() {\n return function delayAnimationImpl(time, complete) {\n var cy = this._private.cy || this;\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n return this.animation({\n delay: time,\n duration: time,\n complete: complete\n });\n };\n },\n // delay\n animation: function animation() {\n return function animationImpl(properties, params) {\n var self = this;\n var selfIsArrayLike = self.length !== undefined;\n var all = selfIsArrayLike ? self : [self]; // put in array if not array-like\n\n var cy = this._private.cy || this;\n var isCore = !selfIsArrayLike;\n var isEles = !isCore;\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n var style = cy.style();\n properties = extend({}, properties, params);\n var propertiesEmpty = Object.keys(properties).length === 0;\n\n if (propertiesEmpty) {\n return new Animation(all[0], properties); // nothing to animate\n }\n\n if (properties.duration === undefined) {\n properties.duration = 400;\n }\n\n switch (properties.duration) {\n case 'slow':\n properties.duration = 600;\n break;\n\n case 'fast':\n properties.duration = 200;\n break;\n }\n\n if (isEles) {\n properties.style = style.getPropsList(properties.style || properties.css);\n properties.css = undefined;\n }\n\n if (isEles && properties.renderedPosition != null) {\n var rpos = properties.renderedPosition;\n var pan = cy.pan();\n var zoom = cy.zoom();\n properties.position = renderedToModelPosition(rpos, zoom, pan);\n } // override pan w/ panBy if set\n\n\n if (isCore && properties.panBy != null) {\n var panBy = properties.panBy;\n var cyPan = cy.pan();\n properties.pan = {\n x: cyPan.x + panBy.x,\n y: cyPan.y + panBy.y\n };\n } // override pan w/ center if set\n\n\n var center = properties.center || properties.centre;\n\n if (isCore && center != null) {\n var centerPan = cy.getCenterPan(center.eles, properties.zoom);\n\n if (centerPan != null) {\n properties.pan = centerPan;\n }\n } // override pan & zoom w/ fit if set\n\n\n if (isCore && properties.fit != null) {\n var fit = properties.fit;\n var fitVp = cy.getFitViewport(fit.eles || fit.boundingBox, fit.padding);\n\n if (fitVp != null) {\n properties.pan = fitVp.pan;\n properties.zoom = fitVp.zoom;\n }\n } // override zoom (& potentially pan) w/ zoom obj if set\n\n\n if (isCore && plainObject(properties.zoom)) {\n var vp = cy.getZoomedViewport(properties.zoom);\n\n if (vp != null) {\n if (vp.zoomed) {\n properties.zoom = vp.zoom;\n }\n\n if (vp.panned) {\n properties.pan = vp.pan;\n }\n } else {\n properties.zoom = null; // an inavalid zoom (e.g. no delta) gets automatically destroyed\n }\n }\n\n return new Animation(all[0], properties);\n };\n },\n // animate\n animate: function animate() {\n return function animateImpl(properties, params) {\n var self = this;\n var selfIsArrayLike = self.length !== undefined;\n var all = selfIsArrayLike ? self : [self]; // put in array if not array-like\n\n var cy = this._private.cy || this;\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n if (params) {\n properties = extend({}, properties, params);\n } // manually hook and run the animation\n\n\n for (var i = 0; i < all.length; i++) {\n var ele = all[i];\n var queue = ele.animated() && (properties.queue === undefined || properties.queue);\n var ani = ele.animation(properties, queue ? {\n queue: true\n } : undefined);\n ani.play();\n }\n\n return this; // chaining\n };\n },\n // animate\n stop: function stop() {\n return function stopImpl(clearQueue, jumpToEnd) {\n var self = this;\n var selfIsArrayLike = self.length !== undefined;\n var all = selfIsArrayLike ? self : [self]; // put in array if not array-like\n\n var cy = this._private.cy || this;\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n for (var i = 0; i < all.length; i++) {\n var ele = all[i];\n var _p = ele._private;\n var anis = _p.animation.current;\n\n for (var j = 0; j < anis.length; j++) {\n var ani = anis[j];\n var ani_p = ani._private;\n\n if (jumpToEnd) {\n // next iteration of the animation loop, the animation\n // will go straight to the end and be removed\n ani_p.duration = 0;\n }\n } // clear the queue of future animations\n\n\n if (clearQueue) {\n _p.animation.queue = [];\n }\n\n if (!jumpToEnd) {\n _p.animation.current = [];\n }\n } // we have to notify (the animation loop doesn't do it for us on `stop`)\n\n\n cy.notify('draw');\n return this;\n };\n } // stop\n\n }; // define\n\n /**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\n var isArray = Array.isArray;\n\n var isArray_1 = isArray;\n\n /** Used to match property names within property paths. */\n var reIsDeepProp = /\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,\n reIsPlainProp = /^\\w*$/;\n\n /**\n * Checks if `value` is a property name and not a property path.\n *\n * @private\n * @param {*} value The value to check.\n * @param {Object} [object] The object to query keys on.\n * @returns {boolean} Returns `true` if `value` is a property name, else `false`.\n */\n function isKey(value, object) {\n if (isArray_1(value)) {\n return false;\n }\n var type = typeof value;\n if (type == 'number' || type == 'symbol' || type == 'boolean' ||\n value == null || isSymbol_1(value)) {\n return true;\n }\n return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||\n (object != null && value in Object(object));\n }\n\n var _isKey = isKey;\n\n /** `Object#toString` result references. */\n var asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n /**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\n function isFunction(value) {\n if (!isObject_1(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = _baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n }\n\n var isFunction_1 = isFunction;\n\n /** Used to detect overreaching core-js shims. */\n var coreJsData = _root['__core-js_shared__'];\n\n var _coreJsData = coreJsData;\n\n /** Used to detect methods masquerading as native. */\n var maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(_coreJsData && _coreJsData.keys && _coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n }());\n\n /**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\n function isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n }\n\n var _isMasked = isMasked;\n\n /** Used for built-in method references. */\n var funcProto$1 = Function.prototype;\n\n /** Used to resolve the decompiled source of functions. */\n var funcToString$1 = funcProto$1.toString;\n\n /**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\n function toSource(func) {\n if (func != null) {\n try {\n return funcToString$1.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n }\n\n var _toSource = toSource;\n\n /**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\n var reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n /** Used to detect host constructors (Safari). */\n var reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n /** Used for built-in method references. */\n var funcProto = Function.prototype,\n objectProto$3 = Object.prototype;\n\n /** Used to resolve the decompiled source of functions. */\n var funcToString = funcProto.toString;\n\n /** Used to check objects for own properties. */\n var hasOwnProperty$3 = objectProto$3.hasOwnProperty;\n\n /** Used to detect if a method is native. */\n var reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty$3).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n );\n\n /**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\n function baseIsNative(value) {\n if (!isObject_1(value) || _isMasked(value)) {\n return false;\n }\n var pattern = isFunction_1(value) ? reIsNative : reIsHostCtor;\n return pattern.test(_toSource(value));\n }\n\n var _baseIsNative = baseIsNative;\n\n /**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\n function getValue$1(object, key) {\n return object == null ? undefined : object[key];\n }\n\n var _getValue = getValue$1;\n\n /**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\n function getNative(object, key) {\n var value = _getValue(object, key);\n return _baseIsNative(value) ? value : undefined;\n }\n\n var _getNative = getNative;\n\n /* Built-in method references that are verified to be native. */\n var nativeCreate = _getNative(Object, 'create');\n\n var _nativeCreate = nativeCreate;\n\n /**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\n function hashClear() {\n this.__data__ = _nativeCreate ? _nativeCreate(null) : {};\n this.size = 0;\n }\n\n var _hashClear = hashClear;\n\n /**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\n function hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n }\n\n var _hashDelete = hashDelete;\n\n /** Used to stand-in for `undefined` hash values. */\n var HASH_UNDEFINED$1 = '__lodash_hash_undefined__';\n\n /** Used for built-in method references. */\n var objectProto$2 = Object.prototype;\n\n /** Used to check objects for own properties. */\n var hasOwnProperty$2 = objectProto$2.hasOwnProperty;\n\n /**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\n function hashGet(key) {\n var data = this.__data__;\n if (_nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED$1 ? undefined : result;\n }\n return hasOwnProperty$2.call(data, key) ? data[key] : undefined;\n }\n\n var _hashGet = hashGet;\n\n /** Used for built-in method references. */\n var objectProto$1 = Object.prototype;\n\n /** Used to check objects for own properties. */\n var hasOwnProperty$1 = objectProto$1.hasOwnProperty;\n\n /**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\n function hashHas(key) {\n var data = this.__data__;\n return _nativeCreate ? (data[key] !== undefined) : hasOwnProperty$1.call(data, key);\n }\n\n var _hashHas = hashHas;\n\n /** Used to stand-in for `undefined` hash values. */\n var HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n /**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\n function hashSet(key, value) {\n var data = this.__data__;\n this.size += this.has(key) ? 0 : 1;\n data[key] = (_nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n }\n\n var _hashSet = hashSet;\n\n /**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\n function Hash(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n }\n\n // Add methods to `Hash`.\n Hash.prototype.clear = _hashClear;\n Hash.prototype['delete'] = _hashDelete;\n Hash.prototype.get = _hashGet;\n Hash.prototype.has = _hashHas;\n Hash.prototype.set = _hashSet;\n\n var _Hash = Hash;\n\n /**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\n function listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n }\n\n var _listCacheClear = listCacheClear;\n\n /**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\n function eq(value, other) {\n return value === other || (value !== value && other !== other);\n }\n\n var eq_1 = eq;\n\n /**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\n function assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq_1(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n }\n\n var _assocIndexOf = assocIndexOf;\n\n /** Used for built-in method references. */\n var arrayProto = Array.prototype;\n\n /** Built-in value references. */\n var splice = arrayProto.splice;\n\n /**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\n function listCacheDelete(key) {\n var data = this.__data__,\n index = _assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n --this.size;\n return true;\n }\n\n var _listCacheDelete = listCacheDelete;\n\n /**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\n function listCacheGet(key) {\n var data = this.__data__,\n index = _assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n }\n\n var _listCacheGet = listCacheGet;\n\n /**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\n function listCacheHas(key) {\n return _assocIndexOf(this.__data__, key) > -1;\n }\n\n var _listCacheHas = listCacheHas;\n\n /**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\n function listCacheSet(key, value) {\n var data = this.__data__,\n index = _assocIndexOf(data, key);\n\n if (index < 0) {\n ++this.size;\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n }\n\n var _listCacheSet = listCacheSet;\n\n /**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\n function ListCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n }\n\n // Add methods to `ListCache`.\n ListCache.prototype.clear = _listCacheClear;\n ListCache.prototype['delete'] = _listCacheDelete;\n ListCache.prototype.get = _listCacheGet;\n ListCache.prototype.has = _listCacheHas;\n ListCache.prototype.set = _listCacheSet;\n\n var _ListCache = ListCache;\n\n /* Built-in method references that are verified to be native. */\n var Map$1 = _getNative(_root, 'Map');\n\n var _Map = Map$1;\n\n /**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\n function mapCacheClear() {\n this.size = 0;\n this.__data__ = {\n 'hash': new _Hash,\n 'map': new (_Map || _ListCache),\n 'string': new _Hash\n };\n }\n\n var _mapCacheClear = mapCacheClear;\n\n /**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\n function isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n }\n\n var _isKeyable = isKeyable;\n\n /**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\n function getMapData(map, key) {\n var data = map.__data__;\n return _isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n }\n\n var _getMapData = getMapData;\n\n /**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\n function mapCacheDelete(key) {\n var result = _getMapData(this, key)['delete'](key);\n this.size -= result ? 1 : 0;\n return result;\n }\n\n var _mapCacheDelete = mapCacheDelete;\n\n /**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\n function mapCacheGet(key) {\n return _getMapData(this, key).get(key);\n }\n\n var _mapCacheGet = mapCacheGet;\n\n /**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\n function mapCacheHas(key) {\n return _getMapData(this, key).has(key);\n }\n\n var _mapCacheHas = mapCacheHas;\n\n /**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\n function mapCacheSet(key, value) {\n var data = _getMapData(this, key),\n size = data.size;\n\n data.set(key, value);\n this.size += data.size == size ? 0 : 1;\n return this;\n }\n\n var _mapCacheSet = mapCacheSet;\n\n /**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\n function MapCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n }\n\n // Add methods to `MapCache`.\n MapCache.prototype.clear = _mapCacheClear;\n MapCache.prototype['delete'] = _mapCacheDelete;\n MapCache.prototype.get = _mapCacheGet;\n MapCache.prototype.has = _mapCacheHas;\n MapCache.prototype.set = _mapCacheSet;\n\n var _MapCache = MapCache;\n\n /** Error message constants. */\n var FUNC_ERROR_TEXT = 'Expected a function';\n\n /**\n * Creates a function that memoizes the result of `func`. If `resolver` is\n * provided, it determines the cache key for storing the result based on the\n * arguments provided to the memoized function. By default, the first argument\n * provided to the memoized function is used as the map cache key. The `func`\n * is invoked with the `this` binding of the memoized function.\n *\n * **Note:** The cache is exposed as the `cache` property on the memoized\n * function. Its creation may be customized by replacing the `_.memoize.Cache`\n * constructor with one whose instances implement the\n * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)\n * method interface of `clear`, `delete`, `get`, `has`, and `set`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to have its output memoized.\n * @param {Function} [resolver] The function to resolve the cache key.\n * @returns {Function} Returns the new memoized function.\n * @example\n *\n * var object = { 'a': 1, 'b': 2 };\n * var other = { 'c': 3, 'd': 4 };\n *\n * var values = _.memoize(_.values);\n * values(object);\n * // => [1, 2]\n *\n * values(other);\n * // => [3, 4]\n *\n * object.a = 2;\n * values(object);\n * // => [1, 2]\n *\n * // Modify the result cache.\n * values.cache.set(object, ['a', 'b']);\n * values(object);\n * // => ['a', 'b']\n *\n * // Replace `_.memoize.Cache`.\n * _.memoize.Cache = WeakMap;\n */\n function memoize(func, resolver) {\n if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n var memoized = function() {\n var args = arguments,\n key = resolver ? resolver.apply(this, args) : args[0],\n cache = memoized.cache;\n\n if (cache.has(key)) {\n return cache.get(key);\n }\n var result = func.apply(this, args);\n memoized.cache = cache.set(key, result) || cache;\n return result;\n };\n memoized.cache = new (memoize.Cache || _MapCache);\n return memoized;\n }\n\n // Expose `MapCache`.\n memoize.Cache = _MapCache;\n\n var memoize_1 = memoize;\n\n /** Used as the maximum memoize cache size. */\n var MAX_MEMOIZE_SIZE = 500;\n\n /**\n * A specialized version of `_.memoize` which clears the memoized function's\n * cache when it exceeds `MAX_MEMOIZE_SIZE`.\n *\n * @private\n * @param {Function} func The function to have its output memoized.\n * @returns {Function} Returns the new memoized function.\n */\n function memoizeCapped(func) {\n var result = memoize_1(func, function(key) {\n if (cache.size === MAX_MEMOIZE_SIZE) {\n cache.clear();\n }\n return key;\n });\n\n var cache = result.cache;\n return result;\n }\n\n var _memoizeCapped = memoizeCapped;\n\n /** Used to match property names within property paths. */\n var rePropName = /[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g;\n\n /** Used to match backslashes in property paths. */\n var reEscapeChar = /\\\\(\\\\)?/g;\n\n /**\n * Converts `string` to a property path array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the property path array.\n */\n var stringToPath = _memoizeCapped(function(string) {\n var result = [];\n if (string.charCodeAt(0) === 46 /* . */) {\n result.push('');\n }\n string.replace(rePropName, function(match, number, quote, subString) {\n result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));\n });\n return result;\n });\n\n var _stringToPath = stringToPath;\n\n /**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\n function arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n }\n\n var _arrayMap = arrayMap;\n\n /** Used as references for various `Number` constants. */\n var INFINITY$1 = 1 / 0;\n\n /** Used to convert symbols to primitives and strings. */\n var symbolProto = _Symbol ? _Symbol.prototype : undefined,\n symbolToString = symbolProto ? symbolProto.toString : undefined;\n\n /**\n * The base implementation of `_.toString` which doesn't convert nullish\n * values to empty strings.\n *\n * @private\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n */\n function baseToString(value) {\n // Exit early for strings to avoid a performance hit in some environments.\n if (typeof value == 'string') {\n return value;\n }\n if (isArray_1(value)) {\n // Recursively convert values (susceptible to call stack limits).\n return _arrayMap(value, baseToString) + '';\n }\n if (isSymbol_1(value)) {\n return symbolToString ? symbolToString.call(value) : '';\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY$1) ? '-0' : result;\n }\n\n var _baseToString = baseToString;\n\n /**\n * Converts `value` to a string. An empty string is returned for `null`\n * and `undefined` values. The sign of `-0` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\n function toString$1(value) {\n return value == null ? '' : _baseToString(value);\n }\n\n var toString_1 = toString$1;\n\n /**\n * Casts `value` to a path array if it's not one.\n *\n * @private\n * @param {*} value The value to inspect.\n * @param {Object} [object] The object to query keys on.\n * @returns {Array} Returns the cast property path array.\n */\n function castPath(value, object) {\n if (isArray_1(value)) {\n return value;\n }\n return _isKey(value, object) ? [value] : _stringToPath(toString_1(value));\n }\n\n var _castPath = castPath;\n\n /** Used as references for various `Number` constants. */\n var INFINITY = 1 / 0;\n\n /**\n * Converts `value` to a string key if it's not a string or symbol.\n *\n * @private\n * @param {*} value The value to inspect.\n * @returns {string|symbol} Returns the key.\n */\n function toKey(value) {\n if (typeof value == 'string' || isSymbol_1(value)) {\n return value;\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n }\n\n var _toKey = toKey;\n\n /**\n * The base implementation of `_.get` without support for default values.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @returns {*} Returns the resolved value.\n */\n function baseGet(object, path) {\n path = _castPath(path, object);\n\n var index = 0,\n length = path.length;\n\n while (object != null && index < length) {\n object = object[_toKey(path[index++])];\n }\n return (index && index == length) ? object : undefined;\n }\n\n var _baseGet = baseGet;\n\n /**\n * Gets the value at `path` of `object`. If the resolved value is\n * `undefined`, the `defaultValue` is returned in its place.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @param {*} [defaultValue] The value returned for `undefined` resolved values.\n * @returns {*} Returns the resolved value.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.get(object, 'a[0].b.c');\n * // => 3\n *\n * _.get(object, ['a', '0', 'b', 'c']);\n * // => 3\n *\n * _.get(object, 'a.b.c', 'default');\n * // => 'default'\n */\n function get(object, path, defaultValue) {\n var result = object == null ? undefined : _baseGet(object, path);\n return result === undefined ? defaultValue : result;\n }\n\n var get_1 = get;\n\n var defineProperty = (function() {\n try {\n var func = _getNative(Object, 'defineProperty');\n func({}, '', {});\n return func;\n } catch (e) {}\n }());\n\n var _defineProperty = defineProperty;\n\n /**\n * The base implementation of `assignValue` and `assignMergeValue` without\n * value checks.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\n function baseAssignValue(object, key, value) {\n if (key == '__proto__' && _defineProperty) {\n _defineProperty(object, key, {\n 'configurable': true,\n 'enumerable': true,\n 'value': value,\n 'writable': true\n });\n } else {\n object[key] = value;\n }\n }\n\n var _baseAssignValue = baseAssignValue;\n\n /** Used for built-in method references. */\n var objectProto = Object.prototype;\n\n /** Used to check objects for own properties. */\n var hasOwnProperty = objectProto.hasOwnProperty;\n\n /**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\n function assignValue(object, key, value) {\n var objValue = object[key];\n if (!(hasOwnProperty.call(object, key) && eq_1(objValue, value)) ||\n (value === undefined && !(key in object))) {\n _baseAssignValue(object, key, value);\n }\n }\n\n var _assignValue = assignValue;\n\n /** Used as references for various `Number` constants. */\n var MAX_SAFE_INTEGER = 9007199254740991;\n\n /** Used to detect unsigned integer values. */\n var reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n /**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\n function isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n }\n\n var _isIndex = isIndex;\n\n /**\n * The base implementation of `_.set`.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {*} value The value to set.\n * @param {Function} [customizer] The function to customize path creation.\n * @returns {Object} Returns `object`.\n */\n function baseSet(object, path, value, customizer) {\n if (!isObject_1(object)) {\n return object;\n }\n path = _castPath(path, object);\n\n var index = -1,\n length = path.length,\n lastIndex = length - 1,\n nested = object;\n\n while (nested != null && ++index < length) {\n var key = _toKey(path[index]),\n newValue = value;\n\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n return object;\n }\n\n if (index != lastIndex) {\n var objValue = nested[key];\n newValue = customizer ? customizer(objValue, key, nested) : undefined;\n if (newValue === undefined) {\n newValue = isObject_1(objValue)\n ? objValue\n : (_isIndex(path[index + 1]) ? [] : {});\n }\n }\n _assignValue(nested, key, newValue);\n nested = nested[key];\n }\n return object;\n }\n\n var _baseSet = baseSet;\n\n /**\n * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,\n * it's created. Arrays are created for missing index properties while objects\n * are created for all other missing properties. Use `_.setWith` to customize\n * `path` creation.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.set(object, 'a[0].b.c', 4);\n * console.log(object.a[0].b.c);\n * // => 4\n *\n * _.set(object, ['x', '0', 'y', 'z'], 5);\n * console.log(object.x[0].y.z);\n * // => 5\n */\n function set(object, path, value) {\n return object == null ? object : _baseSet(object, path, value);\n }\n\n var set_1 = set;\n\n /**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\n function copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n }\n\n var _copyArray = copyArray;\n\n /**\n * Converts `value` to a property path array.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Util\n * @param {*} value The value to convert.\n * @returns {Array} Returns the new property path array.\n * @example\n *\n * _.toPath('a.b.c');\n * // => ['a', 'b', 'c']\n *\n * _.toPath('a[0].b.c');\n * // => ['a', '0', 'b', 'c']\n */\n function toPath(value) {\n if (isArray_1(value)) {\n return _arrayMap(value, _toKey);\n }\n return isSymbol_1(value) ? [value] : _copyArray(_stringToPath(toString_1(value)));\n }\n\n var toPath_1 = toPath;\n\n var define$2 = {\n // access data field\n data: function data(params) {\n var defaults = {\n field: 'data',\n bindingEvent: 'data',\n allowBinding: false,\n allowSetting: false,\n allowGetting: false,\n settingEvent: 'data',\n settingTriggersEvent: false,\n triggerFnName: 'trigger',\n immutableKeys: {},\n // key => true if immutable\n updateStyle: false,\n beforeGet: function beforeGet(self) {},\n beforeSet: function beforeSet(self, obj) {},\n onSet: function onSet(self) {},\n canSet: function canSet(self) {\n return true;\n }\n };\n params = extend({}, defaults, params);\n return function dataImpl(name, value) {\n var p = params;\n var self = this;\n var selfIsArrayLike = self.length !== undefined;\n var all = selfIsArrayLike ? self : [self]; // put in array if not array-like\n\n var single = selfIsArrayLike ? self[0] : self; // .data('foo', ...)\n\n if (string(name)) {\n // set or get property\n var isPathLike = name.indexOf('.') !== -1; // there might be a normal field with a dot \n\n var path = isPathLike && toPath_1(name); // .data('foo')\n\n if (p.allowGetting && value === undefined) {\n // get\n var ret;\n\n if (single) {\n p.beforeGet(single); // check if it's path and a field with the same name doesn't exist\n\n if (path && single._private[p.field][name] === undefined) {\n ret = get_1(single._private[p.field], path);\n } else {\n ret = single._private[p.field][name];\n }\n }\n\n return ret; // .data('foo', 'bar')\n } else if (p.allowSetting && value !== undefined) {\n // set\n var valid = !p.immutableKeys[name];\n\n if (valid) {\n var change = _defineProperty$1({}, name, value);\n\n p.beforeSet(self, change);\n\n for (var i = 0, l = all.length; i < l; i++) {\n var ele = all[i];\n\n if (p.canSet(ele)) {\n if (path && single._private[p.field][name] === undefined) {\n set_1(ele._private[p.field], path, value);\n } else {\n ele._private[p.field][name] = value;\n }\n }\n } // update mappers if asked\n\n\n if (p.updateStyle) {\n self.updateStyle();\n } // call onSet callback\n\n\n p.onSet(self);\n\n if (p.settingTriggersEvent) {\n self[p.triggerFnName](p.settingEvent);\n }\n }\n } // .data({ 'foo': 'bar' })\n\n } else if (p.allowSetting && plainObject(name)) {\n // extend\n var obj = name;\n var k, v;\n var keys = Object.keys(obj);\n p.beforeSet(self, obj);\n\n for (var _i = 0; _i < keys.length; _i++) {\n k = keys[_i];\n v = obj[k];\n\n var _valid = !p.immutableKeys[k];\n\n if (_valid) {\n for (var j = 0; j < all.length; j++) {\n var _ele = all[j];\n\n if (p.canSet(_ele)) {\n _ele._private[p.field][k] = v;\n }\n }\n }\n } // update mappers if asked\n\n\n if (p.updateStyle) {\n self.updateStyle();\n } // call onSet callback\n\n\n p.onSet(self);\n\n if (p.settingTriggersEvent) {\n self[p.triggerFnName](p.settingEvent);\n } // .data(function(){ ... })\n\n } else if (p.allowBinding && fn$6(name)) {\n // bind to event\n var fn = name;\n self.on(p.bindingEvent, fn); // .data()\n } else if (p.allowGetting && name === undefined) {\n // get whole object\n var _ret;\n\n if (single) {\n p.beforeGet(single);\n _ret = single._private[p.field];\n }\n\n return _ret;\n }\n\n return self; // maintain chainability\n }; // function\n },\n // data\n // remove data field\n removeData: function removeData(params) {\n var defaults = {\n field: 'data',\n event: 'data',\n triggerFnName: 'trigger',\n triggerEvent: false,\n immutableKeys: {} // key => true if immutable\n\n };\n params = extend({}, defaults, params);\n return function removeDataImpl(names) {\n var p = params;\n var self = this;\n var selfIsArrayLike = self.length !== undefined;\n var all = selfIsArrayLike ? self : [self]; // put in array if not array-like\n // .removeData('foo bar')\n\n if (string(names)) {\n // then get the list of keys, and delete them\n var keys = names.split(/\\s+/);\n var l = keys.length;\n\n for (var i = 0; i < l; i++) {\n // delete each non-empty key\n var key = keys[i];\n\n if (emptyString(key)) {\n continue;\n }\n\n var valid = !p.immutableKeys[key]; // not valid if immutable\n\n if (valid) {\n for (var i_a = 0, l_a = all.length; i_a < l_a; i_a++) {\n all[i_a]._private[p.field][key] = undefined;\n }\n }\n }\n\n if (p.triggerEvent) {\n self[p.triggerFnName](p.event);\n } // .removeData()\n\n } else if (names === undefined) {\n // then delete all keys\n for (var _i_a = 0, _l_a = all.length; _i_a < _l_a; _i_a++) {\n var _privateFields = all[_i_a]._private[p.field];\n\n var _keys = Object.keys(_privateFields);\n\n for (var _i2 = 0; _i2 < _keys.length; _i2++) {\n var _key = _keys[_i2];\n var validKeyToDelete = !p.immutableKeys[_key];\n\n if (validKeyToDelete) {\n _privateFields[_key] = undefined;\n }\n }\n }\n\n if (p.triggerEvent) {\n self[p.triggerFnName](p.event);\n }\n }\n\n return self; // maintain chaining\n }; // function\n } // removeData\n\n }; // define\n\n var define$1 = {\n eventAliasesOn: function eventAliasesOn(proto) {\n var p = proto;\n p.addListener = p.listen = p.bind = p.on;\n p.unlisten = p.unbind = p.off = p.removeListener;\n p.trigger = p.emit; // this is just a wrapper alias of .on()\n\n p.pon = p.promiseOn = function (events, selector) {\n var self = this;\n var args = Array.prototype.slice.call(arguments, 0);\n return new Promise$1(function (resolve, reject) {\n var callback = function callback(e) {\n self.off.apply(self, offArgs);\n resolve(e);\n };\n\n var onArgs = args.concat([callback]);\n var offArgs = onArgs.concat([]);\n self.on.apply(self, onArgs);\n });\n };\n }\n }; // define\n\n // use this module to cherry pick functions into your prototype\n var define = {};\n [define$3, define$2, define$1].forEach(function (m) {\n extend(define, m);\n });\n\n var elesfn$i = {\n animate: define.animate(),\n animation: define.animation(),\n animated: define.animated(),\n clearQueue: define.clearQueue(),\n delay: define.delay(),\n delayAnimation: define.delayAnimation(),\n stop: define.stop()\n };\n\n var elesfn$h = {\n classes: function classes(_classes) {\n var self = this;\n\n if (_classes === undefined) {\n var ret = [];\n\n self[0]._private.classes.forEach(function (cls) {\n return ret.push(cls);\n });\n\n return ret;\n } else if (!array(_classes)) {\n // extract classes from string\n _classes = (_classes || '').match(/\\S+/g) || [];\n }\n\n var changed = [];\n var classesSet = new Set$1(_classes); // check and update each ele\n\n for (var j = 0; j < self.length; j++) {\n var ele = self[j];\n var _p = ele._private;\n var eleClasses = _p.classes;\n var changedEle = false; // check if ele has all of the passed classes\n\n for (var i = 0; i < _classes.length; i++) {\n var cls = _classes[i];\n var eleHasClass = eleClasses.has(cls);\n\n if (!eleHasClass) {\n changedEle = true;\n break;\n }\n } // check if ele has classes outside of those passed\n\n\n if (!changedEle) {\n changedEle = eleClasses.size !== _classes.length;\n }\n\n if (changedEle) {\n _p.classes = classesSet;\n changed.push(ele);\n }\n } // trigger update style on those eles that had class changes\n\n\n if (changed.length > 0) {\n this.spawn(changed).updateStyle().emit('class');\n }\n\n return self;\n },\n addClass: function addClass(classes) {\n return this.toggleClass(classes, true);\n },\n hasClass: function hasClass(className) {\n var ele = this[0];\n return ele != null && ele._private.classes.has(className);\n },\n toggleClass: function toggleClass(classes, toggle) {\n if (!array(classes)) {\n // extract classes from string\n classes = classes.match(/\\S+/g) || [];\n }\n\n var self = this;\n var toggleUndefd = toggle === undefined;\n var changed = []; // eles who had classes changed\n\n for (var i = 0, il = self.length; i < il; i++) {\n var ele = self[i];\n var eleClasses = ele._private.classes;\n var changedEle = false;\n\n for (var j = 0; j < classes.length; j++) {\n var cls = classes[j];\n var hasClass = eleClasses.has(cls);\n var changedNow = false;\n\n if (toggle || toggleUndefd && !hasClass) {\n eleClasses.add(cls);\n changedNow = true;\n } else if (!toggle || toggleUndefd && hasClass) {\n eleClasses[\"delete\"](cls);\n changedNow = true;\n }\n\n if (!changedEle && changedNow) {\n changed.push(ele);\n changedEle = true;\n }\n } // for j classes\n\n } // for i eles\n // trigger update style on those eles that had class changes\n\n\n if (changed.length > 0) {\n this.spawn(changed).updateStyle().emit('class');\n }\n\n return self;\n },\n removeClass: function removeClass(classes) {\n return this.toggleClass(classes, false);\n },\n flashClass: function flashClass(classes, duration) {\n var self = this;\n\n if (duration == null) {\n duration = 250;\n } else if (duration === 0) {\n return self; // nothing to do really\n }\n\n self.addClass(classes);\n setTimeout(function () {\n self.removeClass(classes);\n }, duration);\n return self;\n }\n };\n elesfn$h.className = elesfn$h.classNames = elesfn$h.classes;\n\n var tokens = {\n metaChar: '[\\\\!\\\\\"\\\\#\\\\$\\\\%\\\\&\\\\\\'\\\\(\\\\)\\\\*\\\\+\\\\,\\\\.\\\\/\\\\:\\\\;\\\\<\\\\=\\\\>\\\\?\\\\@\\\\[\\\\]\\\\^\\\\`\\\\{\\\\|\\\\}\\\\~]',\n // chars we need to escape in let names, etc\n comparatorOp: '=|\\\\!=|>|>=|<|<=|\\\\$=|\\\\^=|\\\\*=',\n // binary comparison op (used in data selectors)\n boolOp: '\\\\?|\\\\!|\\\\^',\n // boolean (unary) operators (used in data selectors)\n string: '\"(?:\\\\\\\\\"|[^\"])*\"' + '|' + \"'(?:\\\\\\\\'|[^'])*'\",\n // string literals (used in data selectors) -- doublequotes | singlequotes\n number: number,\n // number literal (used in data selectors) --- e.g. 0.1234, 1234, 12e123\n meta: 'degree|indegree|outdegree',\n // allowed metadata fields (i.e. allowed functions to use from Collection)\n separator: '\\\\s*,\\\\s*',\n // queries are separated by commas, e.g. edge[foo = 'bar'], node.someClass\n descendant: '\\\\s+',\n child: '\\\\s+>\\\\s+',\n subject: '\\\\$',\n group: 'node|edge|\\\\*',\n directedEdge: '\\\\s+->\\\\s+',\n undirectedEdge: '\\\\s+<->\\\\s+'\n };\n tokens.variable = '(?:[\\\\w-.]|(?:\\\\\\\\' + tokens.metaChar + '))+'; // a variable name can have letters, numbers, dashes, and periods\n\n tokens.className = '(?:[\\\\w-]|(?:\\\\\\\\' + tokens.metaChar + '))+'; // a class name has the same rules as a variable except it can't have a '.' in the name\n\n tokens.value = tokens.string + '|' + tokens.number; // a value literal, either a string or number\n\n tokens.id = tokens.variable; // an element id (follows variable conventions)\n\n (function () {\n var ops, op, i; // add @ variants to comparatorOp\n\n ops = tokens.comparatorOp.split('|');\n\n for (i = 0; i < ops.length; i++) {\n op = ops[i];\n tokens.comparatorOp += '|@' + op;\n } // add ! variants to comparatorOp\n\n\n ops = tokens.comparatorOp.split('|');\n\n for (i = 0; i < ops.length; i++) {\n op = ops[i];\n\n if (op.indexOf('!') >= 0) {\n continue;\n } // skip ops that explicitly contain !\n\n\n if (op === '=') {\n continue;\n } // skip = b/c != is explicitly defined\n\n\n tokens.comparatorOp += '|\\\\!' + op;\n }\n })();\n\n /**\n * Make a new query object\n *\n * @prop type {Type} The type enum (int) of the query\n * @prop checks List of checks to make against an ele to test for a match\n */\n var newQuery = function newQuery() {\n return {\n checks: []\n };\n };\n\n /**\n * A check type enum-like object. Uses integer values for fast match() lookup.\n * The ordering does not matter as long as the ints are unique.\n */\n var Type = {\n /** E.g. node */\n GROUP: 0,\n\n /** A collection of elements */\n COLLECTION: 1,\n\n /** A filter(ele) function */\n FILTER: 2,\n\n /** E.g. [foo > 1] */\n DATA_COMPARE: 3,\n\n /** E.g. [foo] */\n DATA_EXIST: 4,\n\n /** E.g. [?foo] */\n DATA_BOOL: 5,\n\n /** E.g. [[degree > 2]] */\n META_COMPARE: 6,\n\n /** E.g. :selected */\n STATE: 7,\n\n /** E.g. #foo */\n ID: 8,\n\n /** E.g. .foo */\n CLASS: 9,\n\n /** E.g. #foo <-> #bar */\n UNDIRECTED_EDGE: 10,\n\n /** E.g. #foo -> #bar */\n DIRECTED_EDGE: 11,\n\n /** E.g. $#foo -> #bar */\n NODE_SOURCE: 12,\n\n /** E.g. #foo -> $#bar */\n NODE_TARGET: 13,\n\n /** E.g. $#foo <-> #bar */\n NODE_NEIGHBOR: 14,\n\n /** E.g. #foo > #bar */\n CHILD: 15,\n\n /** E.g. #foo #bar */\n DESCENDANT: 16,\n\n /** E.g. $#foo > #bar */\n PARENT: 17,\n\n /** E.g. $#foo #bar */\n ANCESTOR: 18,\n\n /** E.g. #foo > $bar > #baz */\n COMPOUND_SPLIT: 19,\n\n /** Always matches, useful placeholder for subject in `COMPOUND_SPLIT` */\n TRUE: 20\n };\n\n var stateSelectors = [{\n selector: ':selected',\n matches: function matches(ele) {\n return ele.selected();\n }\n }, {\n selector: ':unselected',\n matches: function matches(ele) {\n return !ele.selected();\n }\n }, {\n selector: ':selectable',\n matches: function matches(ele) {\n return ele.selectable();\n }\n }, {\n selector: ':unselectable',\n matches: function matches(ele) {\n return !ele.selectable();\n }\n }, {\n selector: ':locked',\n matches: function matches(ele) {\n return ele.locked();\n }\n }, {\n selector: ':unlocked',\n matches: function matches(ele) {\n return !ele.locked();\n }\n }, {\n selector: ':visible',\n matches: function matches(ele) {\n return ele.visible();\n }\n }, {\n selector: ':hidden',\n matches: function matches(ele) {\n return !ele.visible();\n }\n }, {\n selector: ':transparent',\n matches: function matches(ele) {\n return ele.transparent();\n }\n }, {\n selector: ':grabbed',\n matches: function matches(ele) {\n return ele.grabbed();\n }\n }, {\n selector: ':free',\n matches: function matches(ele) {\n return !ele.grabbed();\n }\n }, {\n selector: ':removed',\n matches: function matches(ele) {\n return ele.removed();\n }\n }, {\n selector: ':inside',\n matches: function matches(ele) {\n return !ele.removed();\n }\n }, {\n selector: ':grabbable',\n matches: function matches(ele) {\n return ele.grabbable();\n }\n }, {\n selector: ':ungrabbable',\n matches: function matches(ele) {\n return !ele.grabbable();\n }\n }, {\n selector: ':animated',\n matches: function matches(ele) {\n return ele.animated();\n }\n }, {\n selector: ':unanimated',\n matches: function matches(ele) {\n return !ele.animated();\n }\n }, {\n selector: ':parent',\n matches: function matches(ele) {\n return ele.isParent();\n }\n }, {\n selector: ':childless',\n matches: function matches(ele) {\n return ele.isChildless();\n }\n }, {\n selector: ':child',\n matches: function matches(ele) {\n return ele.isChild();\n }\n }, {\n selector: ':orphan',\n matches: function matches(ele) {\n return ele.isOrphan();\n }\n }, {\n selector: ':nonorphan',\n matches: function matches(ele) {\n return ele.isChild();\n }\n }, {\n selector: ':compound',\n matches: function matches(ele) {\n if (ele.isNode()) {\n return ele.isParent();\n } else {\n return ele.source().isParent() || ele.target().isParent();\n }\n }\n }, {\n selector: ':loop',\n matches: function matches(ele) {\n return ele.isLoop();\n }\n }, {\n selector: ':simple',\n matches: function matches(ele) {\n return ele.isSimple();\n }\n }, {\n selector: ':active',\n matches: function matches(ele) {\n return ele.active();\n }\n }, {\n selector: ':inactive',\n matches: function matches(ele) {\n return !ele.active();\n }\n }, {\n selector: ':backgrounding',\n matches: function matches(ele) {\n return ele.backgrounding();\n }\n }, {\n selector: ':nonbackgrounding',\n matches: function matches(ele) {\n return !ele.backgrounding();\n }\n }].sort(function (a, b) {\n // n.b. selectors that are starting substrings of others must have the longer ones first\n return descending(a.selector, b.selector);\n });\n\n var lookup = function () {\n var selToFn = {};\n var s;\n\n for (var i = 0; i < stateSelectors.length; i++) {\n s = stateSelectors[i];\n selToFn[s.selector] = s.matches;\n }\n\n return selToFn;\n }();\n\n var stateSelectorMatches = function stateSelectorMatches(sel, ele) {\n return lookup[sel](ele);\n };\n var stateSelectorRegex = '(' + stateSelectors.map(function (s) {\n return s.selector;\n }).join('|') + ')';\n\n // so that values get compared properly in Selector.filter()\n\n var cleanMetaChars = function cleanMetaChars(str) {\n return str.replace(new RegExp('\\\\\\\\(' + tokens.metaChar + ')', 'g'), function (match, $1) {\n return $1;\n });\n };\n\n var replaceLastQuery = function replaceLastQuery(selector, examiningQuery, replacementQuery) {\n selector[selector.length - 1] = replacementQuery;\n }; // NOTE: add new expression syntax here to have it recognised by the parser;\n // - a query contains all adjacent (i.e. no separator in between) expressions;\n // - the current query is stored in selector[i]\n // - you need to check the query objects in match() for it actually filter properly, but that's pretty straight forward\n\n\n var exprs = [{\n name: 'group',\n // just used for identifying when debugging\n query: true,\n regex: '(' + tokens.group + ')',\n populate: function populate(selector, query, _ref) {\n var _ref2 = _slicedToArray(_ref, 1),\n group = _ref2[0];\n\n query.checks.push({\n type: Type.GROUP,\n value: group === '*' ? group : group + 's'\n });\n }\n }, {\n name: 'state',\n query: true,\n regex: stateSelectorRegex,\n populate: function populate(selector, query, _ref3) {\n var _ref4 = _slicedToArray(_ref3, 1),\n state = _ref4[0];\n\n query.checks.push({\n type: Type.STATE,\n value: state\n });\n }\n }, {\n name: 'id',\n query: true,\n regex: '\\\\#(' + tokens.id + ')',\n populate: function populate(selector, query, _ref5) {\n var _ref6 = _slicedToArray(_ref5, 1),\n id = _ref6[0];\n\n query.checks.push({\n type: Type.ID,\n value: cleanMetaChars(id)\n });\n }\n }, {\n name: 'className',\n query: true,\n regex: '\\\\.(' + tokens.className + ')',\n populate: function populate(selector, query, _ref7) {\n var _ref8 = _slicedToArray(_ref7, 1),\n className = _ref8[0];\n\n query.checks.push({\n type: Type.CLASS,\n value: cleanMetaChars(className)\n });\n }\n }, {\n name: 'dataExists',\n query: true,\n regex: '\\\\[\\\\s*(' + tokens.variable + ')\\\\s*\\\\]',\n populate: function populate(selector, query, _ref9) {\n var _ref10 = _slicedToArray(_ref9, 1),\n variable = _ref10[0];\n\n query.checks.push({\n type: Type.DATA_EXIST,\n field: cleanMetaChars(variable)\n });\n }\n }, {\n name: 'dataCompare',\n query: true,\n regex: '\\\\[\\\\s*(' + tokens.variable + ')\\\\s*(' + tokens.comparatorOp + ')\\\\s*(' + tokens.value + ')\\\\s*\\\\]',\n populate: function populate(selector, query, _ref11) {\n var _ref12 = _slicedToArray(_ref11, 3),\n variable = _ref12[0],\n comparatorOp = _ref12[1],\n value = _ref12[2];\n\n var valueIsString = new RegExp('^' + tokens.string + '$').exec(value) != null;\n\n if (valueIsString) {\n value = value.substring(1, value.length - 1);\n } else {\n value = parseFloat(value);\n }\n\n query.checks.push({\n type: Type.DATA_COMPARE,\n field: cleanMetaChars(variable),\n operator: comparatorOp,\n value: value\n });\n }\n }, {\n name: 'dataBool',\n query: true,\n regex: '\\\\[\\\\s*(' + tokens.boolOp + ')\\\\s*(' + tokens.variable + ')\\\\s*\\\\]',\n populate: function populate(selector, query, _ref13) {\n var _ref14 = _slicedToArray(_ref13, 2),\n boolOp = _ref14[0],\n variable = _ref14[1];\n\n query.checks.push({\n type: Type.DATA_BOOL,\n field: cleanMetaChars(variable),\n operator: boolOp\n });\n }\n }, {\n name: 'metaCompare',\n query: true,\n regex: '\\\\[\\\\[\\\\s*(' + tokens.meta + ')\\\\s*(' + tokens.comparatorOp + ')\\\\s*(' + tokens.number + ')\\\\s*\\\\]\\\\]',\n populate: function populate(selector, query, _ref15) {\n var _ref16 = _slicedToArray(_ref15, 3),\n meta = _ref16[0],\n comparatorOp = _ref16[1],\n number = _ref16[2];\n\n query.checks.push({\n type: Type.META_COMPARE,\n field: cleanMetaChars(meta),\n operator: comparatorOp,\n value: parseFloat(number)\n });\n }\n }, {\n name: 'nextQuery',\n separator: true,\n regex: tokens.separator,\n populate: function populate(selector, query) {\n var currentSubject = selector.currentSubject;\n var edgeCount = selector.edgeCount;\n var compoundCount = selector.compoundCount;\n var lastQ = selector[selector.length - 1];\n\n if (currentSubject != null) {\n lastQ.subject = currentSubject;\n selector.currentSubject = null;\n }\n\n lastQ.edgeCount = edgeCount;\n lastQ.compoundCount = compoundCount;\n selector.edgeCount = 0;\n selector.compoundCount = 0; // go on to next query\n\n var nextQuery = selector[selector.length++] = newQuery();\n return nextQuery; // this is the new query to be filled by the following exprs\n }\n }, {\n name: 'directedEdge',\n separator: true,\n regex: tokens.directedEdge,\n populate: function populate(selector, query) {\n if (selector.currentSubject == null) {\n // undirected edge\n var edgeQuery = newQuery();\n var source = query;\n var target = newQuery();\n edgeQuery.checks.push({\n type: Type.DIRECTED_EDGE,\n source: source,\n target: target\n }); // the query in the selector should be the edge rather than the source\n\n replaceLastQuery(selector, query, edgeQuery);\n selector.edgeCount++; // we're now populating the target query with expressions that follow\n\n return target;\n } else {\n // source/target\n var srcTgtQ = newQuery();\n var _source = query;\n\n var _target = newQuery();\n\n srcTgtQ.checks.push({\n type: Type.NODE_SOURCE,\n source: _source,\n target: _target\n }); // the query in the selector should be the neighbourhood rather than the node\n\n replaceLastQuery(selector, query, srcTgtQ);\n selector.edgeCount++;\n return _target; // now populating the target with the following expressions\n }\n }\n }, {\n name: 'undirectedEdge',\n separator: true,\n regex: tokens.undirectedEdge,\n populate: function populate(selector, query) {\n if (selector.currentSubject == null) {\n // undirected edge\n var edgeQuery = newQuery();\n var source = query;\n var target = newQuery();\n edgeQuery.checks.push({\n type: Type.UNDIRECTED_EDGE,\n nodes: [source, target]\n }); // the query in the selector should be the edge rather than the source\n\n replaceLastQuery(selector, query, edgeQuery);\n selector.edgeCount++; // we're now populating the target query with expressions that follow\n\n return target;\n } else {\n // neighbourhood\n var nhoodQ = newQuery();\n var node = query;\n var neighbor = newQuery();\n nhoodQ.checks.push({\n type: Type.NODE_NEIGHBOR,\n node: node,\n neighbor: neighbor\n }); // the query in the selector should be the neighbourhood rather than the node\n\n replaceLastQuery(selector, query, nhoodQ);\n return neighbor; // now populating the neighbor with following expressions\n }\n }\n }, {\n name: 'child',\n separator: true,\n regex: tokens.child,\n populate: function populate(selector, query) {\n if (selector.currentSubject == null) {\n // default: child query\n var parentChildQuery = newQuery();\n var child = newQuery();\n var parent = selector[selector.length - 1];\n parentChildQuery.checks.push({\n type: Type.CHILD,\n parent: parent,\n child: child\n }); // the query in the selector should be the '>' itself\n\n replaceLastQuery(selector, query, parentChildQuery);\n selector.compoundCount++; // we're now populating the child query with expressions that follow\n\n return child;\n } else if (selector.currentSubject === query) {\n // compound split query\n var compound = newQuery();\n var left = selector[selector.length - 1];\n var right = newQuery();\n var subject = newQuery();\n\n var _child = newQuery();\n\n var _parent = newQuery(); // set up the root compound q\n\n\n compound.checks.push({\n type: Type.COMPOUND_SPLIT,\n left: left,\n right: right,\n subject: subject\n }); // populate the subject and replace the q at the old spot (within left) with TRUE\n\n subject.checks = query.checks; // take the checks from the left\n\n query.checks = [{\n type: Type.TRUE\n }]; // checks under left refs the subject implicitly\n // set up the right q\n\n _parent.checks.push({\n type: Type.TRUE\n }); // parent implicitly refs the subject\n\n\n right.checks.push({\n type: Type.PARENT,\n // type is swapped on right side queries\n parent: _parent,\n child: _child // empty for now\n\n });\n replaceLastQuery(selector, left, compound); // update the ref since we moved things around for `query`\n\n selector.currentSubject = subject;\n selector.compoundCount++;\n return _child; // now populating the right side's child\n } else {\n // parent query\n // info for parent query\n var _parent2 = newQuery();\n\n var _child2 = newQuery();\n\n var pcQChecks = [{\n type: Type.PARENT,\n parent: _parent2,\n child: _child2\n }]; // the parent-child query takes the place of the query previously being populated\n\n _parent2.checks = query.checks; // the previous query contains the checks for the parent\n\n query.checks = pcQChecks; // pc query takes over\n\n selector.compoundCount++;\n return _child2; // we're now populating the child\n }\n }\n }, {\n name: 'descendant',\n separator: true,\n regex: tokens.descendant,\n populate: function populate(selector, query) {\n if (selector.currentSubject == null) {\n // default: descendant query\n var ancChQuery = newQuery();\n var descendant = newQuery();\n var ancestor = selector[selector.length - 1];\n ancChQuery.checks.push({\n type: Type.DESCENDANT,\n ancestor: ancestor,\n descendant: descendant\n }); // the query in the selector should be the '>' itself\n\n replaceLastQuery(selector, query, ancChQuery);\n selector.compoundCount++; // we're now populating the descendant query with expressions that follow\n\n return descendant;\n } else if (selector.currentSubject === query) {\n // compound split query\n var compound = newQuery();\n var left = selector[selector.length - 1];\n var right = newQuery();\n var subject = newQuery();\n\n var _descendant = newQuery();\n\n var _ancestor = newQuery(); // set up the root compound q\n\n\n compound.checks.push({\n type: Type.COMPOUND_SPLIT,\n left: left,\n right: right,\n subject: subject\n }); // populate the subject and replace the q at the old spot (within left) with TRUE\n\n subject.checks = query.checks; // take the checks from the left\n\n query.checks = [{\n type: Type.TRUE\n }]; // checks under left refs the subject implicitly\n // set up the right q\n\n _ancestor.checks.push({\n type: Type.TRUE\n }); // ancestor implicitly refs the subject\n\n\n right.checks.push({\n type: Type.ANCESTOR,\n // type is swapped on right side queries\n ancestor: _ancestor,\n descendant: _descendant // empty for now\n\n });\n replaceLastQuery(selector, left, compound); // update the ref since we moved things around for `query`\n\n selector.currentSubject = subject;\n selector.compoundCount++;\n return _descendant; // now populating the right side's descendant\n } else {\n // ancestor query\n // info for parent query\n var _ancestor2 = newQuery();\n\n var _descendant2 = newQuery();\n\n var adQChecks = [{\n type: Type.ANCESTOR,\n ancestor: _ancestor2,\n descendant: _descendant2\n }]; // the parent-child query takes the place of the query previously being populated\n\n _ancestor2.checks = query.checks; // the previous query contains the checks for the parent\n\n query.checks = adQChecks; // pc query takes over\n\n selector.compoundCount++;\n return _descendant2; // we're now populating the child\n }\n }\n }, {\n name: 'subject',\n modifier: true,\n regex: tokens.subject,\n populate: function populate(selector, query) {\n if (selector.currentSubject != null && selector.currentSubject !== query) {\n warn('Redefinition of subject in selector `' + selector.toString() + '`');\n return false;\n }\n\n selector.currentSubject = query;\n var topQ = selector[selector.length - 1];\n var topChk = topQ.checks[0];\n var topType = topChk == null ? null : topChk.type;\n\n if (topType === Type.DIRECTED_EDGE) {\n // directed edge with subject on the target\n // change to target node check\n topChk.type = Type.NODE_TARGET;\n } else if (topType === Type.UNDIRECTED_EDGE) {\n // undirected edge with subject on the second node\n // change to neighbor check\n topChk.type = Type.NODE_NEIGHBOR;\n topChk.node = topChk.nodes[1]; // second node is subject\n\n topChk.neighbor = topChk.nodes[0]; // clean up unused fields for new type\n\n topChk.nodes = null;\n }\n }\n }];\n exprs.forEach(function (e) {\n return e.regexObj = new RegExp('^' + e.regex);\n });\n\n /**\n * Of all the expressions, find the first match in the remaining text.\n * @param {string} remaining The remaining text to parse\n * @returns The matched expression and the newly remaining text `{ expr, match, name, remaining }`\n */\n\n var consumeExpr = function consumeExpr(remaining) {\n var expr;\n var match;\n var name;\n\n for (var j = 0; j < exprs.length; j++) {\n var e = exprs[j];\n var n = e.name;\n var m = remaining.match(e.regexObj);\n\n if (m != null) {\n match = m;\n expr = e;\n name = n;\n var consumed = m[0];\n remaining = remaining.substring(consumed.length);\n break; // we've consumed one expr, so we can return now\n }\n }\n\n return {\n expr: expr,\n match: match,\n name: name,\n remaining: remaining\n };\n };\n /**\n * Consume all the leading whitespace\n * @param {string} remaining The text to consume\n * @returns The text with the leading whitespace removed\n */\n\n\n var consumeWhitespace = function consumeWhitespace(remaining) {\n var match = remaining.match(/^\\s+/);\n\n if (match) {\n var consumed = match[0];\n remaining = remaining.substring(consumed.length);\n }\n\n return remaining;\n };\n /**\n * Parse the string and store the parsed representation in the Selector.\n * @param {string} selector The selector string\n * @returns `true` if the selector was successfully parsed, `false` otherwise\n */\n\n\n var parse = function parse(selector) {\n var self = this;\n var remaining = self.inputText = selector;\n var currentQuery = self[0] = newQuery();\n self.length = 1;\n remaining = consumeWhitespace(remaining); // get rid of leading whitespace\n\n for (;;) {\n var exprInfo = consumeExpr(remaining);\n\n if (exprInfo.expr == null) {\n warn('The selector `' + selector + '`is invalid');\n return false;\n } else {\n var args = exprInfo.match.slice(1); // let the token populate the selector object in currentQuery\n\n var ret = exprInfo.expr.populate(self, currentQuery, args);\n\n if (ret === false) {\n return false; // exit if population failed\n } else if (ret != null) {\n currentQuery = ret; // change the current query to be filled if the expr specifies\n }\n }\n\n remaining = exprInfo.remaining; // we're done when there's nothing left to parse\n\n if (remaining.match(/^\\s*$/)) {\n break;\n }\n }\n\n var lastQ = self[self.length - 1];\n\n if (self.currentSubject != null) {\n lastQ.subject = self.currentSubject;\n }\n\n lastQ.edgeCount = self.edgeCount;\n lastQ.compoundCount = self.compoundCount;\n\n for (var i = 0; i < self.length; i++) {\n var q = self[i]; // in future, this could potentially be allowed if there were operator precedence and detection of invalid combinations\n\n if (q.compoundCount > 0 && q.edgeCount > 0) {\n warn('The selector `' + selector + '` is invalid because it uses both a compound selector and an edge selector');\n return false;\n }\n\n if (q.edgeCount > 1) {\n warn('The selector `' + selector + '` is invalid because it uses multiple edge selectors');\n return false;\n } else if (q.edgeCount === 1) {\n warn('The selector `' + selector + '` is deprecated. Edge selectors do not take effect on changes to source and target nodes after an edge is added, for performance reasons. Use a class or data selector on edges instead, updating the class or data of an edge when your app detects a change in source or target nodes.');\n }\n }\n\n return true; // success\n };\n /**\n * Get the selector represented as a string. This value uses default formatting,\n * so things like spacing may differ from the input text passed to the constructor.\n * @returns {string} The selector string\n */\n\n\n var toString = function toString() {\n if (this.toStringCache != null) {\n return this.toStringCache;\n }\n\n var clean = function clean(obj) {\n if (obj == null) {\n return '';\n } else {\n return obj;\n }\n };\n\n var cleanVal = function cleanVal(val) {\n if (string(val)) {\n return '\"' + val + '\"';\n } else {\n return clean(val);\n }\n };\n\n var space = function space(val) {\n return ' ' + val + ' ';\n };\n\n var checkToString = function checkToString(check, subject) {\n var type = check.type,\n value = check.value;\n\n switch (type) {\n case Type.GROUP:\n {\n var group = clean(value);\n return group.substring(0, group.length - 1);\n }\n\n case Type.DATA_COMPARE:\n {\n var field = check.field,\n operator = check.operator;\n return '[' + field + space(clean(operator)) + cleanVal(value) + ']';\n }\n\n case Type.DATA_BOOL:\n {\n var _operator = check.operator,\n _field = check.field;\n return '[' + clean(_operator) + _field + ']';\n }\n\n case Type.DATA_EXIST:\n {\n var _field2 = check.field;\n return '[' + _field2 + ']';\n }\n\n case Type.META_COMPARE:\n {\n var _operator2 = check.operator,\n _field3 = check.field;\n return '[[' + _field3 + space(clean(_operator2)) + cleanVal(value) + ']]';\n }\n\n case Type.STATE:\n {\n return value;\n }\n\n case Type.ID:\n {\n return '#' + value;\n }\n\n case Type.CLASS:\n {\n return '.' + value;\n }\n\n case Type.PARENT:\n case Type.CHILD:\n {\n return queryToString(check.parent, subject) + space('>') + queryToString(check.child, subject);\n }\n\n case Type.ANCESTOR:\n case Type.DESCENDANT:\n {\n return queryToString(check.ancestor, subject) + ' ' + queryToString(check.descendant, subject);\n }\n\n case Type.COMPOUND_SPLIT:\n {\n var lhs = queryToString(check.left, subject);\n var sub = queryToString(check.subject, subject);\n var rhs = queryToString(check.right, subject);\n return lhs + (lhs.length > 0 ? ' ' : '') + sub + rhs;\n }\n\n case Type.TRUE:\n {\n return '';\n }\n }\n };\n\n var queryToString = function queryToString(query, subject) {\n return query.checks.reduce(function (str, chk, i) {\n return str + (subject === query && i === 0 ? '$' : '') + checkToString(chk, subject);\n }, '');\n };\n\n var str = '';\n\n for (var i = 0; i < this.length; i++) {\n var query = this[i];\n str += queryToString(query, query.subject);\n\n if (this.length > 1 && i < this.length - 1) {\n str += ', ';\n }\n }\n\n this.toStringCache = str;\n return str;\n };\n var parse$1 = {\n parse: parse,\n toString: toString\n };\n\n var valCmp = function valCmp(fieldVal, operator, value) {\n var matches;\n var isFieldStr = string(fieldVal);\n var isFieldNum = number$1(fieldVal);\n var isValStr = string(value);\n var fieldStr, valStr;\n var caseInsensitive = false;\n var notExpr = false;\n var isIneqCmp = false;\n\n if (operator.indexOf('!') >= 0) {\n operator = operator.replace('!', '');\n notExpr = true;\n }\n\n if (operator.indexOf('@') >= 0) {\n operator = operator.replace('@', '');\n caseInsensitive = true;\n }\n\n if (isFieldStr || isValStr || caseInsensitive) {\n fieldStr = !isFieldStr && !isFieldNum ? '' : '' + fieldVal;\n valStr = '' + value;\n } // if we're doing a case insensitive comparison, then we're using a STRING comparison\n // even if we're comparing numbers\n\n\n if (caseInsensitive) {\n fieldVal = fieldStr = fieldStr.toLowerCase();\n value = valStr = valStr.toLowerCase();\n }\n\n switch (operator) {\n case '*=':\n matches = fieldStr.indexOf(valStr) >= 0;\n break;\n\n case '$=':\n matches = fieldStr.indexOf(valStr, fieldStr.length - valStr.length) >= 0;\n break;\n\n case '^=':\n matches = fieldStr.indexOf(valStr) === 0;\n break;\n\n case '=':\n matches = fieldVal === value;\n break;\n\n case '>':\n isIneqCmp = true;\n matches = fieldVal > value;\n break;\n\n case '>=':\n isIneqCmp = true;\n matches = fieldVal >= value;\n break;\n\n case '<':\n isIneqCmp = true;\n matches = fieldVal < value;\n break;\n\n case '<=':\n isIneqCmp = true;\n matches = fieldVal <= value;\n break;\n\n default:\n matches = false;\n break;\n } // apply the not op, but null vals for inequalities should always stay non-matching\n\n\n if (notExpr && (fieldVal != null || !isIneqCmp)) {\n matches = !matches;\n }\n\n return matches;\n };\n var boolCmp = function boolCmp(fieldVal, operator) {\n switch (operator) {\n case '?':\n return fieldVal ? true : false;\n\n case '!':\n return fieldVal ? false : true;\n\n case '^':\n return fieldVal === undefined;\n }\n };\n var existCmp = function existCmp(fieldVal) {\n return fieldVal !== undefined;\n };\n var data$1 = function data(ele, field) {\n return ele.data(field);\n };\n var meta = function meta(ele, field) {\n return ele[field]();\n };\n\n /** A lookup of `match(check, ele)` functions by `Type` int */\n\n var match = [];\n /**\n * Returns whether the query matches for the element\n * @param query The `{ type, value, ... }` query object\n * @param ele The element to compare against\n */\n\n var matches$1 = function matches(query, ele) {\n return query.checks.every(function (chk) {\n return match[chk.type](chk, ele);\n });\n };\n\n match[Type.GROUP] = function (check, ele) {\n var group = check.value;\n return group === '*' || group === ele.group();\n };\n\n match[Type.STATE] = function (check, ele) {\n var stateSelector = check.value;\n return stateSelectorMatches(stateSelector, ele);\n };\n\n match[Type.ID] = function (check, ele) {\n var id = check.value;\n return ele.id() === id;\n };\n\n match[Type.CLASS] = function (check, ele) {\n var cls = check.value;\n return ele.hasClass(cls);\n };\n\n match[Type.META_COMPARE] = function (check, ele) {\n var field = check.field,\n operator = check.operator,\n value = check.value;\n return valCmp(meta(ele, field), operator, value);\n };\n\n match[Type.DATA_COMPARE] = function (check, ele) {\n var field = check.field,\n operator = check.operator,\n value = check.value;\n return valCmp(data$1(ele, field), operator, value);\n };\n\n match[Type.DATA_BOOL] = function (check, ele) {\n var field = check.field,\n operator = check.operator;\n return boolCmp(data$1(ele, field), operator);\n };\n\n match[Type.DATA_EXIST] = function (check, ele) {\n var field = check.field;\n check.operator;\n return existCmp(data$1(ele, field));\n };\n\n match[Type.UNDIRECTED_EDGE] = function (check, ele) {\n var qA = check.nodes[0];\n var qB = check.nodes[1];\n var src = ele.source();\n var tgt = ele.target();\n return matches$1(qA, src) && matches$1(qB, tgt) || matches$1(qB, src) && matches$1(qA, tgt);\n };\n\n match[Type.NODE_NEIGHBOR] = function (check, ele) {\n return matches$1(check.node, ele) && ele.neighborhood().some(function (n) {\n return n.isNode() && matches$1(check.neighbor, n);\n });\n };\n\n match[Type.DIRECTED_EDGE] = function (check, ele) {\n return matches$1(check.source, ele.source()) && matches$1(check.target, ele.target());\n };\n\n match[Type.NODE_SOURCE] = function (check, ele) {\n return matches$1(check.source, ele) && ele.outgoers().some(function (n) {\n return n.isNode() && matches$1(check.target, n);\n });\n };\n\n match[Type.NODE_TARGET] = function (check, ele) {\n return matches$1(check.target, ele) && ele.incomers().some(function (n) {\n return n.isNode() && matches$1(check.source, n);\n });\n };\n\n match[Type.CHILD] = function (check, ele) {\n return matches$1(check.child, ele) && matches$1(check.parent, ele.parent());\n };\n\n match[Type.PARENT] = function (check, ele) {\n return matches$1(check.parent, ele) && ele.children().some(function (c) {\n return matches$1(check.child, c);\n });\n };\n\n match[Type.DESCENDANT] = function (check, ele) {\n return matches$1(check.descendant, ele) && ele.ancestors().some(function (a) {\n return matches$1(check.ancestor, a);\n });\n };\n\n match[Type.ANCESTOR] = function (check, ele) {\n return matches$1(check.ancestor, ele) && ele.descendants().some(function (d) {\n return matches$1(check.descendant, d);\n });\n };\n\n match[Type.COMPOUND_SPLIT] = function (check, ele) {\n return matches$1(check.subject, ele) && matches$1(check.left, ele) && matches$1(check.right, ele);\n };\n\n match[Type.TRUE] = function () {\n return true;\n };\n\n match[Type.COLLECTION] = function (check, ele) {\n var collection = check.value;\n return collection.has(ele);\n };\n\n match[Type.FILTER] = function (check, ele) {\n var filter = check.value;\n return filter(ele);\n };\n\n var filter = function filter(collection) {\n var self = this; // for 1 id #foo queries, just get the element\n\n if (self.length === 1 && self[0].checks.length === 1 && self[0].checks[0].type === Type.ID) {\n return collection.getElementById(self[0].checks[0].value).collection();\n }\n\n var selectorFunction = function selectorFunction(element) {\n for (var j = 0; j < self.length; j++) {\n var query = self[j];\n\n if (matches$1(query, element)) {\n return true;\n }\n }\n\n return false;\n };\n\n if (self.text() == null) {\n selectorFunction = function selectorFunction() {\n return true;\n };\n }\n\n return collection.filter(selectorFunction);\n }; // filter\n // does selector match a single element?\n\n\n var matches = function matches(ele) {\n var self = this;\n\n for (var j = 0; j < self.length; j++) {\n var query = self[j];\n\n if (matches$1(query, ele)) {\n return true;\n }\n }\n\n return false;\n }; // matches\n\n\n var matching = {\n matches: matches,\n filter: filter\n };\n\n var Selector = function Selector(selector) {\n this.inputText = selector;\n this.currentSubject = null;\n this.compoundCount = 0;\n this.edgeCount = 0;\n this.length = 0;\n\n if (selector == null || string(selector) && selector.match(/^\\s*$/)) ; else if (elementOrCollection(selector)) {\n this.addQuery({\n checks: [{\n type: Type.COLLECTION,\n value: selector.collection()\n }]\n });\n } else if (fn$6(selector)) {\n this.addQuery({\n checks: [{\n type: Type.FILTER,\n value: selector\n }]\n });\n } else if (string(selector)) {\n if (!this.parse(selector)) {\n this.invalid = true;\n }\n } else {\n error('A selector must be created from a string; found ');\n }\n };\n\n var selfn = Selector.prototype;\n [parse$1, matching].forEach(function (p) {\n return extend(selfn, p);\n });\n\n selfn.text = function () {\n return this.inputText;\n };\n\n selfn.size = function () {\n return this.length;\n };\n\n selfn.eq = function (i) {\n return this[i];\n };\n\n selfn.sameText = function (otherSel) {\n return !this.invalid && !otherSel.invalid && this.text() === otherSel.text();\n };\n\n selfn.addQuery = function (q) {\n this[this.length++] = q;\n };\n\n selfn.selector = selfn.toString;\n\n var elesfn$g = {\n allAre: function allAre(selector) {\n var selObj = new Selector(selector);\n return this.every(function (ele) {\n return selObj.matches(ele);\n });\n },\n is: function is(selector) {\n var selObj = new Selector(selector);\n return this.some(function (ele) {\n return selObj.matches(ele);\n });\n },\n some: function some(fn, thisArg) {\n for (var i = 0; i < this.length; i++) {\n var ret = !thisArg ? fn(this[i], i, this) : fn.apply(thisArg, [this[i], i, this]);\n\n if (ret) {\n return true;\n }\n }\n\n return false;\n },\n every: function every(fn, thisArg) {\n for (var i = 0; i < this.length; i++) {\n var ret = !thisArg ? fn(this[i], i, this) : fn.apply(thisArg, [this[i], i, this]);\n\n if (!ret) {\n return false;\n }\n }\n\n return true;\n },\n same: function same(collection) {\n // cheap collection ref check\n if (this === collection) {\n return true;\n }\n\n collection = this.cy().collection(collection);\n var thisLength = this.length;\n var collectionLength = collection.length; // cheap length check\n\n if (thisLength !== collectionLength) {\n return false;\n } // cheap element ref check\n\n\n if (thisLength === 1) {\n return this[0] === collection[0];\n }\n\n return this.every(function (ele) {\n return collection.hasElementWithId(ele.id());\n });\n },\n anySame: function anySame(collection) {\n collection = this.cy().collection(collection);\n return this.some(function (ele) {\n return collection.hasElementWithId(ele.id());\n });\n },\n allAreNeighbors: function allAreNeighbors(collection) {\n collection = this.cy().collection(collection);\n var nhood = this.neighborhood();\n return collection.every(function (ele) {\n return nhood.hasElementWithId(ele.id());\n });\n },\n contains: function contains(collection) {\n collection = this.cy().collection(collection);\n var self = this;\n return collection.every(function (ele) {\n return self.hasElementWithId(ele.id());\n });\n }\n };\n elesfn$g.allAreNeighbours = elesfn$g.allAreNeighbors;\n elesfn$g.has = elesfn$g.contains;\n elesfn$g.equal = elesfn$g.equals = elesfn$g.same;\n\n var cache = function cache(fn, name) {\n return function traversalCache(arg1, arg2, arg3, arg4) {\n var selectorOrEles = arg1;\n var eles = this;\n var key;\n\n if (selectorOrEles == null) {\n key = '';\n } else if (elementOrCollection(selectorOrEles) && selectorOrEles.length === 1) {\n key = selectorOrEles.id();\n }\n\n if (eles.length === 1 && key) {\n var _p = eles[0]._private;\n var tch = _p.traversalCache = _p.traversalCache || {};\n var ch = tch[name] = tch[name] || [];\n var hash = hashString(key);\n var cacheHit = ch[hash];\n\n if (cacheHit) {\n return cacheHit;\n } else {\n return ch[hash] = fn.call(eles, arg1, arg2, arg3, arg4);\n }\n } else {\n return fn.call(eles, arg1, arg2, arg3, arg4);\n }\n };\n };\n\n var elesfn$f = {\n parent: function parent(selector) {\n var parents = []; // optimisation for single ele call\n\n if (this.length === 1) {\n var parent = this[0]._private.parent;\n\n if (parent) {\n return parent;\n }\n }\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n var _parent = ele._private.parent;\n\n if (_parent) {\n parents.push(_parent);\n }\n }\n\n return this.spawn(parents, true).filter(selector);\n },\n parents: function parents(selector) {\n var parents = [];\n var eles = this.parent();\n\n while (eles.nonempty()) {\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n parents.push(ele);\n }\n\n eles = eles.parent();\n }\n\n return this.spawn(parents, true).filter(selector);\n },\n commonAncestors: function commonAncestors(selector) {\n var ancestors;\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n var parents = ele.parents();\n ancestors = ancestors || parents;\n ancestors = ancestors.intersect(parents); // current list must be common with current ele parents set\n }\n\n return ancestors.filter(selector);\n },\n orphans: function orphans(selector) {\n return this.stdFilter(function (ele) {\n return ele.isOrphan();\n }).filter(selector);\n },\n nonorphans: function nonorphans(selector) {\n return this.stdFilter(function (ele) {\n return ele.isChild();\n }).filter(selector);\n },\n children: cache(function (selector) {\n var children = [];\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n var eleChildren = ele._private.children;\n\n for (var j = 0; j < eleChildren.length; j++) {\n children.push(eleChildren[j]);\n }\n }\n\n return this.spawn(children, true).filter(selector);\n }, 'children'),\n siblings: function siblings(selector) {\n return this.parent().children().not(this).filter(selector);\n },\n isParent: function isParent() {\n var ele = this[0];\n\n if (ele) {\n return ele.isNode() && ele._private.children.length !== 0;\n }\n },\n isChildless: function isChildless() {\n var ele = this[0];\n\n if (ele) {\n return ele.isNode() && ele._private.children.length === 0;\n }\n },\n isChild: function isChild() {\n var ele = this[0];\n\n if (ele) {\n return ele.isNode() && ele._private.parent != null;\n }\n },\n isOrphan: function isOrphan() {\n var ele = this[0];\n\n if (ele) {\n return ele.isNode() && ele._private.parent == null;\n }\n },\n descendants: function descendants(selector) {\n var elements = [];\n\n function add(eles) {\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n elements.push(ele);\n\n if (ele.children().nonempty()) {\n add(ele.children());\n }\n }\n }\n\n add(this.children());\n return this.spawn(elements, true).filter(selector);\n }\n };\n\n function forEachCompound(eles, fn, includeSelf, recursiveStep) {\n var q = [];\n var did = new Set$1();\n var cy = eles.cy();\n var hasCompounds = cy.hasCompoundNodes();\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n\n if (includeSelf) {\n q.push(ele);\n } else if (hasCompounds) {\n recursiveStep(q, did, ele);\n }\n }\n\n while (q.length > 0) {\n var _ele = q.shift();\n\n fn(_ele);\n did.add(_ele.id());\n\n if (hasCompounds) {\n recursiveStep(q, did, _ele);\n }\n }\n\n return eles;\n }\n\n function addChildren(q, did, ele) {\n if (ele.isParent()) {\n var children = ele._private.children;\n\n for (var i = 0; i < children.length; i++) {\n var child = children[i];\n\n if (!did.has(child.id())) {\n q.push(child);\n }\n }\n }\n } // very efficient version of eles.add( eles.descendants() ).forEach()\n // for internal use\n\n\n elesfn$f.forEachDown = function (fn) {\n var includeSelf = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n return forEachCompound(this, fn, includeSelf, addChildren);\n };\n\n function addParent(q, did, ele) {\n if (ele.isChild()) {\n var parent = ele._private.parent;\n\n if (!did.has(parent.id())) {\n q.push(parent);\n }\n }\n }\n\n elesfn$f.forEachUp = function (fn) {\n var includeSelf = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n return forEachCompound(this, fn, includeSelf, addParent);\n };\n\n function addParentAndChildren(q, did, ele) {\n addParent(q, did, ele);\n addChildren(q, did, ele);\n }\n\n elesfn$f.forEachUpAndDown = function (fn) {\n var includeSelf = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n return forEachCompound(this, fn, includeSelf, addParentAndChildren);\n }; // aliases\n\n\n elesfn$f.ancestors = elesfn$f.parents;\n\n var fn$5, elesfn$e;\n fn$5 = elesfn$e = {\n data: define.data({\n field: 'data',\n bindingEvent: 'data',\n allowBinding: true,\n allowSetting: true,\n settingEvent: 'data',\n settingTriggersEvent: true,\n triggerFnName: 'trigger',\n allowGetting: true,\n immutableKeys: {\n 'id': true,\n 'source': true,\n 'target': true,\n 'parent': true\n },\n updateStyle: true\n }),\n removeData: define.removeData({\n field: 'data',\n event: 'data',\n triggerFnName: 'trigger',\n triggerEvent: true,\n immutableKeys: {\n 'id': true,\n 'source': true,\n 'target': true,\n 'parent': true\n },\n updateStyle: true\n }),\n scratch: define.data({\n field: 'scratch',\n bindingEvent: 'scratch',\n allowBinding: true,\n allowSetting: true,\n settingEvent: 'scratch',\n settingTriggersEvent: true,\n triggerFnName: 'trigger',\n allowGetting: true,\n updateStyle: true\n }),\n removeScratch: define.removeData({\n field: 'scratch',\n event: 'scratch',\n triggerFnName: 'trigger',\n triggerEvent: true,\n updateStyle: true\n }),\n rscratch: define.data({\n field: 'rscratch',\n allowBinding: false,\n allowSetting: true,\n settingTriggersEvent: false,\n allowGetting: true\n }),\n removeRscratch: define.removeData({\n field: 'rscratch',\n triggerEvent: false\n }),\n id: function id() {\n var ele = this[0];\n\n if (ele) {\n return ele._private.data.id;\n }\n }\n }; // aliases\n\n fn$5.attr = fn$5.data;\n fn$5.removeAttr = fn$5.removeData;\n var data = elesfn$e;\n\n var elesfn$d = {};\n\n function defineDegreeFunction(callback) {\n return function (includeLoops) {\n var self = this;\n\n if (includeLoops === undefined) {\n includeLoops = true;\n }\n\n if (self.length === 0) {\n return;\n }\n\n if (self.isNode() && !self.removed()) {\n var degree = 0;\n var node = self[0];\n var connectedEdges = node._private.edges;\n\n for (var i = 0; i < connectedEdges.length; i++) {\n var edge = connectedEdges[i];\n\n if (!includeLoops && edge.isLoop()) {\n continue;\n }\n\n degree += callback(node, edge);\n }\n\n return degree;\n } else {\n return;\n }\n };\n }\n\n extend(elesfn$d, {\n degree: defineDegreeFunction(function (node, edge) {\n if (edge.source().same(edge.target())) {\n return 2;\n } else {\n return 1;\n }\n }),\n indegree: defineDegreeFunction(function (node, edge) {\n if (edge.target().same(node)) {\n return 1;\n } else {\n return 0;\n }\n }),\n outdegree: defineDegreeFunction(function (node, edge) {\n if (edge.source().same(node)) {\n return 1;\n } else {\n return 0;\n }\n })\n });\n\n function defineDegreeBoundsFunction(degreeFn, callback) {\n return function (includeLoops) {\n var ret;\n var nodes = this.nodes();\n\n for (var i = 0; i < nodes.length; i++) {\n var ele = nodes[i];\n var degree = ele[degreeFn](includeLoops);\n\n if (degree !== undefined && (ret === undefined || callback(degree, ret))) {\n ret = degree;\n }\n }\n\n return ret;\n };\n }\n\n extend(elesfn$d, {\n minDegree: defineDegreeBoundsFunction('degree', function (degree, min) {\n return degree < min;\n }),\n maxDegree: defineDegreeBoundsFunction('degree', function (degree, max) {\n return degree > max;\n }),\n minIndegree: defineDegreeBoundsFunction('indegree', function (degree, min) {\n return degree < min;\n }),\n maxIndegree: defineDegreeBoundsFunction('indegree', function (degree, max) {\n return degree > max;\n }),\n minOutdegree: defineDegreeBoundsFunction('outdegree', function (degree, min) {\n return degree < min;\n }),\n maxOutdegree: defineDegreeBoundsFunction('outdegree', function (degree, max) {\n return degree > max;\n })\n });\n extend(elesfn$d, {\n totalDegree: function totalDegree(includeLoops) {\n var total = 0;\n var nodes = this.nodes();\n\n for (var i = 0; i < nodes.length; i++) {\n total += nodes[i].degree(includeLoops);\n }\n\n return total;\n }\n });\n\n var fn$4, elesfn$c;\n\n var beforePositionSet = function beforePositionSet(eles, newPos, silent) {\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n\n if (!ele.locked()) {\n var oldPos = ele._private.position;\n var delta = {\n x: newPos.x != null ? newPos.x - oldPos.x : 0,\n y: newPos.y != null ? newPos.y - oldPos.y : 0\n };\n\n if (ele.isParent() && !(delta.x === 0 && delta.y === 0)) {\n ele.children().shift(delta, silent);\n }\n\n ele.dirtyBoundingBoxCache();\n }\n }\n };\n\n var positionDef = {\n field: 'position',\n bindingEvent: 'position',\n allowBinding: true,\n allowSetting: true,\n settingEvent: 'position',\n settingTriggersEvent: true,\n triggerFnName: 'emitAndNotify',\n allowGetting: true,\n validKeys: ['x', 'y'],\n beforeGet: function beforeGet(ele) {\n ele.updateCompoundBounds();\n },\n beforeSet: function beforeSet(eles, newPos) {\n beforePositionSet(eles, newPos, false);\n },\n onSet: function onSet(eles) {\n eles.dirtyCompoundBoundsCache();\n },\n canSet: function canSet(ele) {\n return !ele.locked();\n }\n };\n fn$4 = elesfn$c = {\n position: define.data(positionDef),\n // position but no notification to renderer\n silentPosition: define.data(extend({}, positionDef, {\n allowBinding: false,\n allowSetting: true,\n settingTriggersEvent: false,\n allowGetting: false,\n beforeSet: function beforeSet(eles, newPos) {\n beforePositionSet(eles, newPos, true);\n },\n onSet: function onSet(eles) {\n eles.dirtyCompoundBoundsCache();\n }\n })),\n positions: function positions(pos, silent) {\n if (plainObject(pos)) {\n if (silent) {\n this.silentPosition(pos);\n } else {\n this.position(pos);\n }\n } else if (fn$6(pos)) {\n var _fn = pos;\n var cy = this.cy();\n cy.startBatch();\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n\n var _pos = void 0;\n\n if (_pos = _fn(ele, i)) {\n if (silent) {\n ele.silentPosition(_pos);\n } else {\n ele.position(_pos);\n }\n }\n }\n\n cy.endBatch();\n }\n\n return this; // chaining\n },\n silentPositions: function silentPositions(pos) {\n return this.positions(pos, true);\n },\n shift: function shift(dim, val, silent) {\n var delta;\n\n if (plainObject(dim)) {\n delta = {\n x: number$1(dim.x) ? dim.x : 0,\n y: number$1(dim.y) ? dim.y : 0\n };\n silent = val;\n } else if (string(dim) && number$1(val)) {\n delta = {\n x: 0,\n y: 0\n };\n delta[dim] = val;\n }\n\n if (delta != null) {\n var cy = this.cy();\n cy.startBatch();\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i]; // exclude any node that is a descendant of the calling collection\n\n if (cy.hasCompoundNodes() && ele.isChild() && ele.ancestors().anySame(this)) {\n continue;\n }\n\n var pos = ele.position();\n var newPos = {\n x: pos.x + delta.x,\n y: pos.y + delta.y\n };\n\n if (silent) {\n ele.silentPosition(newPos);\n } else {\n ele.position(newPos);\n }\n }\n\n cy.endBatch();\n }\n\n return this;\n },\n silentShift: function silentShift(dim, val) {\n if (plainObject(dim)) {\n this.shift(dim, true);\n } else if (string(dim) && number$1(val)) {\n this.shift(dim, val, true);\n }\n\n return this;\n },\n // get/set the rendered (i.e. on screen) positon of the element\n renderedPosition: function renderedPosition(dim, val) {\n var ele = this[0];\n var cy = this.cy();\n var zoom = cy.zoom();\n var pan = cy.pan();\n var rpos = plainObject(dim) ? dim : undefined;\n var setting = rpos !== undefined || val !== undefined && string(dim);\n\n if (ele && ele.isNode()) {\n // must have an element and must be a node to return position\n if (setting) {\n for (var i = 0; i < this.length; i++) {\n var _ele = this[i];\n\n if (val !== undefined) {\n // set one dimension\n _ele.position(dim, (val - pan[dim]) / zoom);\n } else if (rpos !== undefined) {\n // set whole position\n _ele.position(renderedToModelPosition(rpos, zoom, pan));\n }\n }\n } else {\n // getting\n var pos = ele.position();\n rpos = modelToRenderedPosition(pos, zoom, pan);\n\n if (dim === undefined) {\n // then return the whole rendered position\n return rpos;\n } else {\n // then return the specified dimension\n return rpos[dim];\n }\n }\n } else if (!setting) {\n return undefined; // for empty collection case\n }\n\n return this; // chaining\n },\n // get/set the position relative to the parent\n relativePosition: function relativePosition(dim, val) {\n var ele = this[0];\n var cy = this.cy();\n var ppos = plainObject(dim) ? dim : undefined;\n var setting = ppos !== undefined || val !== undefined && string(dim);\n var hasCompoundNodes = cy.hasCompoundNodes();\n\n if (ele && ele.isNode()) {\n // must have an element and must be a node to return position\n if (setting) {\n for (var i = 0; i < this.length; i++) {\n var _ele2 = this[i];\n var parent = hasCompoundNodes ? _ele2.parent() : null;\n var hasParent = parent && parent.length > 0;\n var relativeToParent = hasParent;\n\n if (hasParent) {\n parent = parent[0];\n }\n\n var origin = relativeToParent ? parent.position() : {\n x: 0,\n y: 0\n };\n\n if (val !== undefined) {\n // set one dimension\n _ele2.position(dim, val + origin[dim]);\n } else if (ppos !== undefined) {\n // set whole position\n _ele2.position({\n x: ppos.x + origin.x,\n y: ppos.y + origin.y\n });\n }\n }\n } else {\n // getting\n var pos = ele.position();\n\n var _parent = hasCompoundNodes ? ele.parent() : null;\n\n var _hasParent = _parent && _parent.length > 0;\n\n var _relativeToParent = _hasParent;\n\n if (_hasParent) {\n _parent = _parent[0];\n }\n\n var _origin = _relativeToParent ? _parent.position() : {\n x: 0,\n y: 0\n };\n\n ppos = {\n x: pos.x - _origin.x,\n y: pos.y - _origin.y\n };\n\n if (dim === undefined) {\n // then return the whole rendered position\n return ppos;\n } else {\n // then return the specified dimension\n return ppos[dim];\n }\n }\n } else if (!setting) {\n return undefined; // for empty collection case\n }\n\n return this; // chaining\n }\n }; // aliases\n\n fn$4.modelPosition = fn$4.point = fn$4.position;\n fn$4.modelPositions = fn$4.points = fn$4.positions;\n fn$4.renderedPoint = fn$4.renderedPosition;\n fn$4.relativePoint = fn$4.relativePosition;\n var position = elesfn$c;\n\n var fn$3, elesfn$b;\n fn$3 = elesfn$b = {};\n\n elesfn$b.renderedBoundingBox = function (options) {\n var bb = this.boundingBox(options);\n var cy = this.cy();\n var zoom = cy.zoom();\n var pan = cy.pan();\n var x1 = bb.x1 * zoom + pan.x;\n var x2 = bb.x2 * zoom + pan.x;\n var y1 = bb.y1 * zoom + pan.y;\n var y2 = bb.y2 * zoom + pan.y;\n return {\n x1: x1,\n x2: x2,\n y1: y1,\n y2: y2,\n w: x2 - x1,\n h: y2 - y1\n };\n };\n\n elesfn$b.dirtyCompoundBoundsCache = function () {\n var silent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n var cy = this.cy();\n\n if (!cy.styleEnabled() || !cy.hasCompoundNodes()) {\n return this;\n }\n\n this.forEachUp(function (ele) {\n if (ele.isParent()) {\n var _p = ele._private;\n _p.compoundBoundsClean = false;\n _p.bbCache = null;\n\n if (!silent) {\n ele.emitAndNotify('bounds');\n }\n }\n });\n return this;\n };\n\n elesfn$b.updateCompoundBounds = function () {\n var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n var cy = this.cy(); // not possible to do on non-compound graphs or with the style disabled\n\n if (!cy.styleEnabled() || !cy.hasCompoundNodes()) {\n return this;\n } // save cycles when batching -- but bounds will be stale (or not exist yet)\n\n\n if (!force && cy.batching()) {\n return this;\n }\n\n function update(parent) {\n if (!parent.isParent()) {\n return;\n }\n\n var _p = parent._private;\n var children = parent.children();\n var includeLabels = parent.pstyle('compound-sizing-wrt-labels').value === 'include';\n var min = {\n width: {\n val: parent.pstyle('min-width').pfValue,\n left: parent.pstyle('min-width-bias-left'),\n right: parent.pstyle('min-width-bias-right')\n },\n height: {\n val: parent.pstyle('min-height').pfValue,\n top: parent.pstyle('min-height-bias-top'),\n bottom: parent.pstyle('min-height-bias-bottom')\n }\n };\n var bb = children.boundingBox({\n includeLabels: includeLabels,\n includeOverlays: false,\n // updating the compound bounds happens outside of the regular\n // cache cycle (i.e. before fired events)\n useCache: false\n });\n var pos = _p.position; // if children take up zero area then keep position and fall back on stylesheet w/h\n\n if (bb.w === 0 || bb.h === 0) {\n bb = {\n w: parent.pstyle('width').pfValue,\n h: parent.pstyle('height').pfValue\n };\n bb.x1 = pos.x - bb.w / 2;\n bb.x2 = pos.x + bb.w / 2;\n bb.y1 = pos.y - bb.h / 2;\n bb.y2 = pos.y + bb.h / 2;\n }\n\n function computeBiasValues(propDiff, propBias, propBiasComplement) {\n var biasDiff = 0;\n var biasComplementDiff = 0;\n var biasTotal = propBias + propBiasComplement;\n\n if (propDiff > 0 && biasTotal > 0) {\n biasDiff = propBias / biasTotal * propDiff;\n biasComplementDiff = propBiasComplement / biasTotal * propDiff;\n }\n\n return {\n biasDiff: biasDiff,\n biasComplementDiff: biasComplementDiff\n };\n }\n\n function computePaddingValues(width, height, paddingObject, relativeTo) {\n // Assuming percentage is number from 0 to 1\n if (paddingObject.units === '%') {\n switch (relativeTo) {\n case 'width':\n return width > 0 ? paddingObject.pfValue * width : 0;\n\n case 'height':\n return height > 0 ? paddingObject.pfValue * height : 0;\n\n case 'average':\n return width > 0 && height > 0 ? paddingObject.pfValue * (width + height) / 2 : 0;\n\n case 'min':\n return width > 0 && height > 0 ? width > height ? paddingObject.pfValue * height : paddingObject.pfValue * width : 0;\n\n case 'max':\n return width > 0 && height > 0 ? width > height ? paddingObject.pfValue * width : paddingObject.pfValue * height : 0;\n\n default:\n return 0;\n }\n } else if (paddingObject.units === 'px') {\n return paddingObject.pfValue;\n } else {\n return 0;\n }\n }\n\n var leftVal = min.width.left.value;\n\n if (min.width.left.units === 'px' && min.width.val > 0) {\n leftVal = leftVal * 100 / min.width.val;\n }\n\n var rightVal = min.width.right.value;\n\n if (min.width.right.units === 'px' && min.width.val > 0) {\n rightVal = rightVal * 100 / min.width.val;\n }\n\n var topVal = min.height.top.value;\n\n if (min.height.top.units === 'px' && min.height.val > 0) {\n topVal = topVal * 100 / min.height.val;\n }\n\n var bottomVal = min.height.bottom.value;\n\n if (min.height.bottom.units === 'px' && min.height.val > 0) {\n bottomVal = bottomVal * 100 / min.height.val;\n }\n\n var widthBiasDiffs = computeBiasValues(min.width.val - bb.w, leftVal, rightVal);\n var diffLeft = widthBiasDiffs.biasDiff;\n var diffRight = widthBiasDiffs.biasComplementDiff;\n var heightBiasDiffs = computeBiasValues(min.height.val - bb.h, topVal, bottomVal);\n var diffTop = heightBiasDiffs.biasDiff;\n var diffBottom = heightBiasDiffs.biasComplementDiff;\n _p.autoPadding = computePaddingValues(bb.w, bb.h, parent.pstyle('padding'), parent.pstyle('padding-relative-to').value);\n _p.autoWidth = Math.max(bb.w, min.width.val);\n pos.x = (-diffLeft + bb.x1 + bb.x2 + diffRight) / 2;\n _p.autoHeight = Math.max(bb.h, min.height.val);\n pos.y = (-diffTop + bb.y1 + bb.y2 + diffBottom) / 2;\n }\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n var _p = ele._private;\n\n if (!_p.compoundBoundsClean || force) {\n update(ele);\n\n if (!cy.batching()) {\n _p.compoundBoundsClean = true;\n }\n }\n }\n\n return this;\n };\n\n var noninf = function noninf(x) {\n if (x === Infinity || x === -Infinity) {\n return 0;\n }\n\n return x;\n };\n\n var updateBounds = function updateBounds(b, x1, y1, x2, y2) {\n // don't update with zero area boxes\n if (x2 - x1 === 0 || y2 - y1 === 0) {\n return;\n } // don't update with null dim\n\n\n if (x1 == null || y1 == null || x2 == null || y2 == null) {\n return;\n }\n\n b.x1 = x1 < b.x1 ? x1 : b.x1;\n b.x2 = x2 > b.x2 ? x2 : b.x2;\n b.y1 = y1 < b.y1 ? y1 : b.y1;\n b.y2 = y2 > b.y2 ? y2 : b.y2;\n b.w = b.x2 - b.x1;\n b.h = b.y2 - b.y1;\n };\n\n var updateBoundsFromBox = function updateBoundsFromBox(b, b2) {\n if (b2 == null) {\n return b;\n }\n\n return updateBounds(b, b2.x1, b2.y1, b2.x2, b2.y2);\n };\n\n var prefixedProperty = function prefixedProperty(obj, field, prefix) {\n return getPrefixedProperty(obj, field, prefix);\n };\n\n var updateBoundsFromArrow = function updateBoundsFromArrow(bounds, ele, prefix) {\n if (ele.cy().headless()) {\n return;\n }\n\n var _p = ele._private;\n var rstyle = _p.rstyle;\n var halfArW = rstyle.arrowWidth / 2;\n var arrowType = ele.pstyle(prefix + '-arrow-shape').value;\n var x;\n var y;\n\n if (arrowType !== 'none') {\n if (prefix === 'source') {\n x = rstyle.srcX;\n y = rstyle.srcY;\n } else if (prefix === 'target') {\n x = rstyle.tgtX;\n y = rstyle.tgtY;\n } else {\n x = rstyle.midX;\n y = rstyle.midY;\n } // always store the individual arrow bounds\n\n\n var bbs = _p.arrowBounds = _p.arrowBounds || {};\n var bb = bbs[prefix] = bbs[prefix] || {};\n bb.x1 = x - halfArW;\n bb.y1 = y - halfArW;\n bb.x2 = x + halfArW;\n bb.y2 = y + halfArW;\n bb.w = bb.x2 - bb.x1;\n bb.h = bb.y2 - bb.y1;\n expandBoundingBox(bb, 1);\n updateBounds(bounds, bb.x1, bb.y1, bb.x2, bb.y2);\n }\n };\n\n var updateBoundsFromLabel = function updateBoundsFromLabel(bounds, ele, prefix) {\n if (ele.cy().headless()) {\n return;\n }\n\n var prefixDash;\n\n if (prefix) {\n prefixDash = prefix + '-';\n } else {\n prefixDash = '';\n }\n\n var _p = ele._private;\n var rstyle = _p.rstyle;\n var label = ele.pstyle(prefixDash + 'label').strValue;\n\n if (label) {\n var halign = ele.pstyle('text-halign');\n var valign = ele.pstyle('text-valign');\n var labelWidth = prefixedProperty(rstyle, 'labelWidth', prefix);\n var labelHeight = prefixedProperty(rstyle, 'labelHeight', prefix);\n var labelX = prefixedProperty(rstyle, 'labelX', prefix);\n var labelY = prefixedProperty(rstyle, 'labelY', prefix);\n var marginX = ele.pstyle(prefixDash + 'text-margin-x').pfValue;\n var marginY = ele.pstyle(prefixDash + 'text-margin-y').pfValue;\n var isEdge = ele.isEdge();\n var rotation = ele.pstyle(prefixDash + 'text-rotation');\n var outlineWidth = ele.pstyle('text-outline-width').pfValue;\n var borderWidth = ele.pstyle('text-border-width').pfValue;\n var halfBorderWidth = borderWidth / 2;\n var padding = ele.pstyle('text-background-padding').pfValue;\n var marginOfError = 2; // expand to work around browser dimension inaccuracies\n\n var lh = labelHeight;\n var lw = labelWidth;\n var lw_2 = lw / 2;\n var lh_2 = lh / 2;\n var lx1, lx2, ly1, ly2;\n\n if (isEdge) {\n lx1 = labelX - lw_2;\n lx2 = labelX + lw_2;\n ly1 = labelY - lh_2;\n ly2 = labelY + lh_2;\n } else {\n switch (halign.value) {\n case 'left':\n lx1 = labelX - lw;\n lx2 = labelX;\n break;\n\n case 'center':\n lx1 = labelX - lw_2;\n lx2 = labelX + lw_2;\n break;\n\n case 'right':\n lx1 = labelX;\n lx2 = labelX + lw;\n break;\n }\n\n switch (valign.value) {\n case 'top':\n ly1 = labelY - lh;\n ly2 = labelY;\n break;\n\n case 'center':\n ly1 = labelY - lh_2;\n ly2 = labelY + lh_2;\n break;\n\n case 'bottom':\n ly1 = labelY;\n ly2 = labelY + lh;\n break;\n }\n } // shift by margin and expand by outline and border\n\n\n lx1 += marginX - Math.max(outlineWidth, halfBorderWidth) - padding - marginOfError;\n lx2 += marginX + Math.max(outlineWidth, halfBorderWidth) + padding + marginOfError;\n ly1 += marginY - Math.max(outlineWidth, halfBorderWidth) - padding - marginOfError;\n ly2 += marginY + Math.max(outlineWidth, halfBorderWidth) + padding + marginOfError; // always store the unrotated label bounds separately\n\n var bbPrefix = prefix || 'main';\n var bbs = _p.labelBounds;\n var bb = bbs[bbPrefix] = bbs[bbPrefix] || {};\n bb.x1 = lx1;\n bb.y1 = ly1;\n bb.x2 = lx2;\n bb.y2 = ly2;\n bb.w = lx2 - lx1;\n bb.h = ly2 - ly1;\n var isAutorotate = isEdge && rotation.strValue === 'autorotate';\n var isPfValue = rotation.pfValue != null && rotation.pfValue !== 0;\n\n if (isAutorotate || isPfValue) {\n var theta = isAutorotate ? prefixedProperty(_p.rstyle, 'labelAngle', prefix) : rotation.pfValue;\n var cos = Math.cos(theta);\n var sin = Math.sin(theta); // rotation point (default value for center-center)\n\n var xo = (lx1 + lx2) / 2;\n var yo = (ly1 + ly2) / 2;\n\n if (!isEdge) {\n switch (halign.value) {\n case 'left':\n xo = lx2;\n break;\n\n case 'right':\n xo = lx1;\n break;\n }\n\n switch (valign.value) {\n case 'top':\n yo = ly2;\n break;\n\n case 'bottom':\n yo = ly1;\n break;\n }\n }\n\n var rotate = function rotate(x, y) {\n x = x - xo;\n y = y - yo;\n return {\n x: x * cos - y * sin + xo,\n y: x * sin + y * cos + yo\n };\n };\n\n var px1y1 = rotate(lx1, ly1);\n var px1y2 = rotate(lx1, ly2);\n var px2y1 = rotate(lx2, ly1);\n var px2y2 = rotate(lx2, ly2);\n lx1 = Math.min(px1y1.x, px1y2.x, px2y1.x, px2y2.x);\n lx2 = Math.max(px1y1.x, px1y2.x, px2y1.x, px2y2.x);\n ly1 = Math.min(px1y1.y, px1y2.y, px2y1.y, px2y2.y);\n ly2 = Math.max(px1y1.y, px1y2.y, px2y1.y, px2y2.y);\n }\n\n var bbPrefixRot = bbPrefix + 'Rot';\n var bbRot = bbs[bbPrefixRot] = bbs[bbPrefixRot] || {};\n bbRot.x1 = lx1;\n bbRot.y1 = ly1;\n bbRot.x2 = lx2;\n bbRot.y2 = ly2;\n bbRot.w = lx2 - lx1;\n bbRot.h = ly2 - ly1;\n updateBounds(bounds, lx1, ly1, lx2, ly2);\n updateBounds(_p.labelBounds.all, lx1, ly1, lx2, ly2);\n }\n\n return bounds;\n }; // get the bounding box of the elements (in raw model position)\n\n\n var boundingBoxImpl = function boundingBoxImpl(ele, options) {\n var cy = ele._private.cy;\n var styleEnabled = cy.styleEnabled();\n var headless = cy.headless();\n var bounds = makeBoundingBox();\n var _p = ele._private;\n var isNode = ele.isNode();\n var isEdge = ele.isEdge();\n var ex1, ex2, ey1, ey2; // extrema of body / lines\n\n var x, y; // node pos\n\n var rstyle = _p.rstyle;\n var manualExpansion = isNode && styleEnabled ? ele.pstyle('bounds-expansion').pfValue : [0]; // must use `display` prop only, as reading `compound.width()` causes recursion\n // (other factors like width values will be considered later in this function anyway)\n\n var isDisplayed = function isDisplayed(ele) {\n return ele.pstyle('display').value !== 'none';\n };\n\n var displayed = !styleEnabled || isDisplayed(ele) // must take into account connected nodes b/c of implicit edge hiding on display:none node\n && (!isEdge || isDisplayed(ele.source()) && isDisplayed(ele.target()));\n\n if (displayed) {\n // displayed suffices, since we will find zero area eles anyway\n var overlayOpacity = 0;\n var overlayPadding = 0;\n\n if (styleEnabled && options.includeOverlays) {\n overlayOpacity = ele.pstyle('overlay-opacity').value;\n\n if (overlayOpacity !== 0) {\n overlayPadding = ele.pstyle('overlay-padding').value;\n }\n }\n\n var underlayOpacity = 0;\n var underlayPadding = 0;\n\n if (styleEnabled && options.includeUnderlays) {\n underlayOpacity = ele.pstyle('underlay-opacity').value;\n\n if (underlayOpacity !== 0) {\n underlayPadding = ele.pstyle('underlay-padding').value;\n }\n }\n\n var padding = Math.max(overlayPadding, underlayPadding);\n var w = 0;\n var wHalf = 0;\n\n if (styleEnabled) {\n w = ele.pstyle('width').pfValue;\n wHalf = w / 2;\n }\n\n if (isNode && options.includeNodes) {\n var pos = ele.position();\n x = pos.x;\n y = pos.y;\n\n var _w = ele.outerWidth();\n\n var halfW = _w / 2;\n var h = ele.outerHeight();\n var halfH = h / 2; // handle node dimensions\n /////////////////////////\n\n ex1 = x - halfW;\n ex2 = x + halfW;\n ey1 = y - halfH;\n ey2 = y + halfH;\n updateBounds(bounds, ex1, ey1, ex2, ey2);\n } else if (isEdge && options.includeEdges) {\n if (styleEnabled && !headless) {\n var curveStyle = ele.pstyle('curve-style').strValue; // handle edge dimensions (rough box estimate)\n //////////////////////////////////////////////\n\n ex1 = Math.min(rstyle.srcX, rstyle.midX, rstyle.tgtX);\n ex2 = Math.max(rstyle.srcX, rstyle.midX, rstyle.tgtX);\n ey1 = Math.min(rstyle.srcY, rstyle.midY, rstyle.tgtY);\n ey2 = Math.max(rstyle.srcY, rstyle.midY, rstyle.tgtY); // take into account edge width\n\n ex1 -= wHalf;\n ex2 += wHalf;\n ey1 -= wHalf;\n ey2 += wHalf;\n updateBounds(bounds, ex1, ey1, ex2, ey2); // precise edges\n ////////////////\n\n if (curveStyle === 'haystack') {\n var hpts = rstyle.haystackPts;\n\n if (hpts && hpts.length === 2) {\n ex1 = hpts[0].x;\n ey1 = hpts[0].y;\n ex2 = hpts[1].x;\n ey2 = hpts[1].y;\n\n if (ex1 > ex2) {\n var temp = ex1;\n ex1 = ex2;\n ex2 = temp;\n }\n\n if (ey1 > ey2) {\n var _temp = ey1;\n ey1 = ey2;\n ey2 = _temp;\n }\n\n updateBounds(bounds, ex1 - wHalf, ey1 - wHalf, ex2 + wHalf, ey2 + wHalf);\n }\n } else if (curveStyle === 'bezier' || curveStyle === 'unbundled-bezier' || curveStyle === 'segments' || curveStyle === 'taxi') {\n var pts;\n\n switch (curveStyle) {\n case 'bezier':\n case 'unbundled-bezier':\n pts = rstyle.bezierPts;\n break;\n\n case 'segments':\n case 'taxi':\n pts = rstyle.linePts;\n break;\n }\n\n if (pts != null) {\n for (var j = 0; j < pts.length; j++) {\n var pt = pts[j];\n ex1 = pt.x - wHalf;\n ex2 = pt.x + wHalf;\n ey1 = pt.y - wHalf;\n ey2 = pt.y + wHalf;\n updateBounds(bounds, ex1, ey1, ex2, ey2);\n }\n }\n } // bezier-like or segment-like edge\n\n } else {\n // headless or style disabled\n // fallback on source and target positions\n //////////////////////////////////////////\n var n1 = ele.source();\n var n1pos = n1.position();\n var n2 = ele.target();\n var n2pos = n2.position();\n ex1 = n1pos.x;\n ex2 = n2pos.x;\n ey1 = n1pos.y;\n ey2 = n2pos.y;\n\n if (ex1 > ex2) {\n var _temp2 = ex1;\n ex1 = ex2;\n ex2 = _temp2;\n }\n\n if (ey1 > ey2) {\n var _temp3 = ey1;\n ey1 = ey2;\n ey2 = _temp3;\n } // take into account edge width\n\n\n ex1 -= wHalf;\n ex2 += wHalf;\n ey1 -= wHalf;\n ey2 += wHalf;\n updateBounds(bounds, ex1, ey1, ex2, ey2);\n } // headless or style disabled\n\n } // edges\n // handle edge arrow size\n /////////////////////////\n\n\n if (styleEnabled && options.includeEdges && isEdge) {\n updateBoundsFromArrow(bounds, ele, 'mid-source');\n updateBoundsFromArrow(bounds, ele, 'mid-target');\n updateBoundsFromArrow(bounds, ele, 'source');\n updateBoundsFromArrow(bounds, ele, 'target');\n } // ghost\n ////////\n\n\n if (styleEnabled) {\n var ghost = ele.pstyle('ghost').value === 'yes';\n\n if (ghost) {\n var gx = ele.pstyle('ghost-offset-x').pfValue;\n var gy = ele.pstyle('ghost-offset-y').pfValue;\n updateBounds(bounds, bounds.x1 + gx, bounds.y1 + gy, bounds.x2 + gx, bounds.y2 + gy);\n }\n } // always store the body bounds separately from the labels\n\n\n var bbBody = _p.bodyBounds = _p.bodyBounds || {};\n assignBoundingBox(bbBody, bounds);\n expandBoundingBoxSides(bbBody, manualExpansion);\n expandBoundingBox(bbBody, 1); // expand to work around browser dimension inaccuracies\n // overlay\n //////////\n\n if (styleEnabled) {\n ex1 = bounds.x1;\n ex2 = bounds.x2;\n ey1 = bounds.y1;\n ey2 = bounds.y2;\n updateBounds(bounds, ex1 - padding, ey1 - padding, ex2 + padding, ey2 + padding);\n } // always store the body bounds separately from the labels\n\n\n var bbOverlay = _p.overlayBounds = _p.overlayBounds || {};\n assignBoundingBox(bbOverlay, bounds);\n expandBoundingBoxSides(bbOverlay, manualExpansion);\n expandBoundingBox(bbOverlay, 1); // expand to work around browser dimension inaccuracies\n // handle label dimensions\n //////////////////////////\n\n var bbLabels = _p.labelBounds = _p.labelBounds || {};\n\n if (bbLabels.all != null) {\n clearBoundingBox(bbLabels.all);\n } else {\n bbLabels.all = makeBoundingBox();\n }\n\n if (styleEnabled && options.includeLabels) {\n if (options.includeMainLabels) {\n updateBoundsFromLabel(bounds, ele, null);\n }\n\n if (isEdge) {\n if (options.includeSourceLabels) {\n updateBoundsFromLabel(bounds, ele, 'source');\n }\n\n if (options.includeTargetLabels) {\n updateBoundsFromLabel(bounds, ele, 'target');\n }\n }\n } // style enabled for labels\n\n } // if displayed\n\n\n bounds.x1 = noninf(bounds.x1);\n bounds.y1 = noninf(bounds.y1);\n bounds.x2 = noninf(bounds.x2);\n bounds.y2 = noninf(bounds.y2);\n bounds.w = noninf(bounds.x2 - bounds.x1);\n bounds.h = noninf(bounds.y2 - bounds.y1);\n\n if (bounds.w > 0 && bounds.h > 0 && displayed) {\n expandBoundingBoxSides(bounds, manualExpansion); // expand bounds by 1 because antialiasing can increase the visual/effective size by 1 on all sides\n\n expandBoundingBox(bounds, 1);\n }\n\n return bounds;\n };\n\n var getKey = function getKey(opts) {\n var i = 0;\n\n var tf = function tf(val) {\n return (val ? 1 : 0) << i++;\n };\n\n var key = 0;\n key += tf(opts.incudeNodes);\n key += tf(opts.includeEdges);\n key += tf(opts.includeLabels);\n key += tf(opts.includeMainLabels);\n key += tf(opts.includeSourceLabels);\n key += tf(opts.includeTargetLabels);\n key += tf(opts.includeOverlays);\n return key;\n };\n\n var getBoundingBoxPosKey = function getBoundingBoxPosKey(ele) {\n if (ele.isEdge()) {\n var p1 = ele.source().position();\n var p2 = ele.target().position();\n\n var r = function r(x) {\n return Math.round(x);\n };\n\n return hashIntsArray([r(p1.x), r(p1.y), r(p2.x), r(p2.y)]);\n } else {\n return 0;\n }\n };\n\n var cachedBoundingBoxImpl = function cachedBoundingBoxImpl(ele, opts) {\n var _p = ele._private;\n var bb;\n var isEdge = ele.isEdge();\n var key = opts == null ? defBbOptsKey : getKey(opts);\n var usingDefOpts = key === defBbOptsKey;\n var currPosKey = getBoundingBoxPosKey(ele);\n var isPosKeySame = _p.bbCachePosKey === currPosKey;\n var useCache = opts.useCache && isPosKeySame;\n\n var isDirty = function isDirty(ele) {\n return ele._private.bbCache == null || ele._private.styleDirty;\n };\n\n var needRecalc = !useCache || isDirty(ele) || isEdge && isDirty(ele.source()) || isDirty(ele.target());\n\n if (needRecalc) {\n if (!isPosKeySame) {\n ele.recalculateRenderedStyle(useCache);\n }\n\n bb = boundingBoxImpl(ele, defBbOpts);\n _p.bbCache = bb;\n _p.bbCachePosKey = currPosKey;\n } else {\n bb = _p.bbCache;\n } // not using def opts => need to build up bb from combination of sub bbs\n\n\n if (!usingDefOpts) {\n var isNode = ele.isNode();\n bb = makeBoundingBox();\n\n if (opts.includeNodes && isNode || opts.includeEdges && !isNode) {\n if (opts.includeOverlays) {\n updateBoundsFromBox(bb, _p.overlayBounds);\n } else {\n updateBoundsFromBox(bb, _p.bodyBounds);\n }\n }\n\n if (opts.includeLabels) {\n if (opts.includeMainLabels && (!isEdge || opts.includeSourceLabels && opts.includeTargetLabels)) {\n updateBoundsFromBox(bb, _p.labelBounds.all);\n } else {\n if (opts.includeMainLabels) {\n updateBoundsFromBox(bb, _p.labelBounds.mainRot);\n }\n\n if (opts.includeSourceLabels) {\n updateBoundsFromBox(bb, _p.labelBounds.sourceRot);\n }\n\n if (opts.includeTargetLabels) {\n updateBoundsFromBox(bb, _p.labelBounds.targetRot);\n }\n }\n }\n\n bb.w = bb.x2 - bb.x1;\n bb.h = bb.y2 - bb.y1;\n }\n\n return bb;\n };\n\n var defBbOpts = {\n includeNodes: true,\n includeEdges: true,\n includeLabels: true,\n includeMainLabels: true,\n includeSourceLabels: true,\n includeTargetLabels: true,\n includeOverlays: true,\n includeUnderlays: true,\n useCache: true\n };\n var defBbOptsKey = getKey(defBbOpts);\n var filledBbOpts = defaults$g(defBbOpts);\n\n elesfn$b.boundingBox = function (options) {\n var bounds; // the main usecase is ele.boundingBox() for a single element with no/def options\n // specified s.t. the cache is used, so check for this case to make it faster by\n // avoiding the overhead of the rest of the function\n\n if (this.length === 1 && this[0]._private.bbCache != null && !this[0]._private.styleDirty && (options === undefined || options.useCache === undefined || options.useCache === true)) {\n if (options === undefined) {\n options = defBbOpts;\n } else {\n options = filledBbOpts(options);\n }\n\n bounds = cachedBoundingBoxImpl(this[0], options);\n } else {\n bounds = makeBoundingBox();\n options = options || defBbOpts;\n var opts = filledBbOpts(options);\n var eles = this;\n var cy = eles.cy();\n var styleEnabled = cy.styleEnabled();\n\n if (styleEnabled) {\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var _p = ele._private;\n var currPosKey = getBoundingBoxPosKey(ele);\n var isPosKeySame = _p.bbCachePosKey === currPosKey;\n var useCache = opts.useCache && isPosKeySame && !_p.styleDirty;\n ele.recalculateRenderedStyle(useCache);\n }\n }\n\n this.updateCompoundBounds(!options.useCache);\n\n for (var _i = 0; _i < eles.length; _i++) {\n var _ele = eles[_i];\n updateBoundsFromBox(bounds, cachedBoundingBoxImpl(_ele, opts));\n }\n }\n\n bounds.x1 = noninf(bounds.x1);\n bounds.y1 = noninf(bounds.y1);\n bounds.x2 = noninf(bounds.x2);\n bounds.y2 = noninf(bounds.y2);\n bounds.w = noninf(bounds.x2 - bounds.x1);\n bounds.h = noninf(bounds.y2 - bounds.y1);\n return bounds;\n };\n\n elesfn$b.dirtyBoundingBoxCache = function () {\n for (var i = 0; i < this.length; i++) {\n var _p = this[i]._private;\n _p.bbCache = null;\n _p.bbCachePosKey = null;\n _p.bodyBounds = null;\n _p.overlayBounds = null;\n _p.labelBounds.all = null;\n _p.labelBounds.source = null;\n _p.labelBounds.target = null;\n _p.labelBounds.main = null;\n _p.labelBounds.sourceRot = null;\n _p.labelBounds.targetRot = null;\n _p.labelBounds.mainRot = null;\n _p.arrowBounds.source = null;\n _p.arrowBounds.target = null;\n _p.arrowBounds['mid-source'] = null;\n _p.arrowBounds['mid-target'] = null;\n }\n\n this.emitAndNotify('bounds');\n return this;\n }; // private helper to get bounding box for custom node positions\n // - good for perf in certain cases but currently requires dirtying the rendered style\n // - would be better to not modify the nodes but the nodes are read directly everywhere in the renderer...\n // - try to use for only things like discrete layouts where the node position would change anyway\n\n\n elesfn$b.boundingBoxAt = function (fn) {\n var nodes = this.nodes();\n var cy = this.cy();\n var hasCompoundNodes = cy.hasCompoundNodes();\n var parents = cy.collection();\n\n if (hasCompoundNodes) {\n parents = nodes.filter(function (node) {\n return node.isParent();\n });\n nodes = nodes.not(parents);\n }\n\n if (plainObject(fn)) {\n var obj = fn;\n\n fn = function fn() {\n return obj;\n };\n }\n\n var storeOldPos = function storeOldPos(node, i) {\n return node._private.bbAtOldPos = fn(node, i);\n };\n\n var getOldPos = function getOldPos(node) {\n return node._private.bbAtOldPos;\n };\n\n cy.startBatch();\n nodes.forEach(storeOldPos).silentPositions(fn);\n\n if (hasCompoundNodes) {\n parents.dirtyCompoundBoundsCache();\n parents.dirtyBoundingBoxCache();\n parents.updateCompoundBounds(true); // force update b/c we're inside a batch cycle\n }\n\n var bb = copyBoundingBox(this.boundingBox({\n useCache: false\n }));\n nodes.silentPositions(getOldPos);\n\n if (hasCompoundNodes) {\n parents.dirtyCompoundBoundsCache();\n parents.dirtyBoundingBoxCache();\n parents.updateCompoundBounds(true); // force update b/c we're inside a batch cycle\n }\n\n cy.endBatch();\n return bb;\n };\n\n fn$3.boundingbox = fn$3.bb = fn$3.boundingBox;\n fn$3.renderedBoundingbox = fn$3.renderedBoundingBox;\n var bounds = elesfn$b;\n\n var fn$2, elesfn$a;\n fn$2 = elesfn$a = {};\n\n var defineDimFns = function defineDimFns(opts) {\n opts.uppercaseName = capitalize(opts.name);\n opts.autoName = 'auto' + opts.uppercaseName;\n opts.labelName = 'label' + opts.uppercaseName;\n opts.outerName = 'outer' + opts.uppercaseName;\n opts.uppercaseOuterName = capitalize(opts.outerName);\n\n fn$2[opts.name] = function dimImpl() {\n var ele = this[0];\n var _p = ele._private;\n var cy = _p.cy;\n var styleEnabled = cy._private.styleEnabled;\n\n if (ele) {\n if (styleEnabled) {\n if (ele.isParent()) {\n ele.updateCompoundBounds();\n return _p[opts.autoName] || 0;\n }\n\n var d = ele.pstyle(opts.name);\n\n switch (d.strValue) {\n case 'label':\n ele.recalculateRenderedStyle();\n return _p.rstyle[opts.labelName] || 0;\n\n default:\n return d.pfValue;\n }\n } else {\n return 1;\n }\n }\n };\n\n fn$2['outer' + opts.uppercaseName] = function outerDimImpl() {\n var ele = this[0];\n var _p = ele._private;\n var cy = _p.cy;\n var styleEnabled = cy._private.styleEnabled;\n\n if (ele) {\n if (styleEnabled) {\n var dim = ele[opts.name]();\n var border = ele.pstyle('border-width').pfValue; // n.b. 1/2 each side\n\n var padding = 2 * ele.padding();\n return dim + border + padding;\n } else {\n return 1;\n }\n }\n };\n\n fn$2['rendered' + opts.uppercaseName] = function renderedDimImpl() {\n var ele = this[0];\n\n if (ele) {\n var d = ele[opts.name]();\n return d * this.cy().zoom();\n }\n };\n\n fn$2['rendered' + opts.uppercaseOuterName] = function renderedOuterDimImpl() {\n var ele = this[0];\n\n if (ele) {\n var od = ele[opts.outerName]();\n return od * this.cy().zoom();\n }\n };\n };\n\n defineDimFns({\n name: 'width'\n });\n defineDimFns({\n name: 'height'\n });\n\n elesfn$a.padding = function () {\n var ele = this[0];\n var _p = ele._private;\n\n if (ele.isParent()) {\n ele.updateCompoundBounds();\n\n if (_p.autoPadding !== undefined) {\n return _p.autoPadding;\n } else {\n return ele.pstyle('padding').pfValue;\n }\n } else {\n return ele.pstyle('padding').pfValue;\n }\n };\n\n elesfn$a.paddedHeight = function () {\n var ele = this[0];\n return ele.height() + 2 * ele.padding();\n };\n\n elesfn$a.paddedWidth = function () {\n var ele = this[0];\n return ele.width() + 2 * ele.padding();\n };\n\n var widthHeight = elesfn$a;\n\n var ifEdge = function ifEdge(ele, getValue) {\n if (ele.isEdge()) {\n return getValue(ele);\n }\n };\n\n var ifEdgeRenderedPosition = function ifEdgeRenderedPosition(ele, getPoint) {\n if (ele.isEdge()) {\n var cy = ele.cy();\n return modelToRenderedPosition(getPoint(ele), cy.zoom(), cy.pan());\n }\n };\n\n var ifEdgeRenderedPositions = function ifEdgeRenderedPositions(ele, getPoints) {\n if (ele.isEdge()) {\n var cy = ele.cy();\n var pan = cy.pan();\n var zoom = cy.zoom();\n return getPoints(ele).map(function (p) {\n return modelToRenderedPosition(p, zoom, pan);\n });\n }\n };\n\n var controlPoints = function controlPoints(ele) {\n return ele.renderer().getControlPoints(ele);\n };\n\n var segmentPoints = function segmentPoints(ele) {\n return ele.renderer().getSegmentPoints(ele);\n };\n\n var sourceEndpoint = function sourceEndpoint(ele) {\n return ele.renderer().getSourceEndpoint(ele);\n };\n\n var targetEndpoint = function targetEndpoint(ele) {\n return ele.renderer().getTargetEndpoint(ele);\n };\n\n var midpoint = function midpoint(ele) {\n return ele.renderer().getEdgeMidpoint(ele);\n };\n\n var pts = {\n controlPoints: {\n get: controlPoints,\n mult: true\n },\n segmentPoints: {\n get: segmentPoints,\n mult: true\n },\n sourceEndpoint: {\n get: sourceEndpoint\n },\n targetEndpoint: {\n get: targetEndpoint\n },\n midpoint: {\n get: midpoint\n }\n };\n\n var renderedName = function renderedName(name) {\n return 'rendered' + name[0].toUpperCase() + name.substr(1);\n };\n\n var edgePoints = Object.keys(pts).reduce(function (obj, name) {\n var spec = pts[name];\n var rName = renderedName(name);\n\n obj[name] = function () {\n return ifEdge(this, spec.get);\n };\n\n if (spec.mult) {\n obj[rName] = function () {\n return ifEdgeRenderedPositions(this, spec.get);\n };\n } else {\n obj[rName] = function () {\n return ifEdgeRenderedPosition(this, spec.get);\n };\n }\n\n return obj;\n }, {});\n\n var dimensions = extend({}, position, bounds, widthHeight, edgePoints);\n\n /*!\n Event object based on jQuery events, MIT license\n\n https://jquery.org/license/\n https://tldrlegal.com/license/mit-license\n https://github.com/jquery/jquery/blob/master/src/event.js\n */\n var Event = function Event(src, props) {\n this.recycle(src, props);\n };\n\n function returnFalse() {\n return false;\n }\n\n function returnTrue() {\n return true;\n } // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\n\n\n Event.prototype = {\n instanceString: function instanceString() {\n return 'event';\n },\n recycle: function recycle(src, props) {\n this.isImmediatePropagationStopped = this.isPropagationStopped = this.isDefaultPrevented = returnFalse;\n\n if (src != null && src.preventDefault) {\n // Browser Event object\n this.type = src.type; // Events bubbling up the document may have been marked as prevented\n // by a handler lower down the tree; reflect the correct value.\n\n this.isDefaultPrevented = src.defaultPrevented ? returnTrue : returnFalse;\n } else if (src != null && src.type) {\n // Plain object containing all event details\n props = src;\n } else {\n // Event string\n this.type = src;\n } // Put explicitly provided properties onto the event object\n\n\n if (props != null) {\n // more efficient to manually copy fields we use\n this.originalEvent = props.originalEvent;\n this.type = props.type != null ? props.type : this.type;\n this.cy = props.cy;\n this.target = props.target;\n this.position = props.position;\n this.renderedPosition = props.renderedPosition;\n this.namespace = props.namespace;\n this.layout = props.layout;\n }\n\n if (this.cy != null && this.position != null && this.renderedPosition == null) {\n // create a rendered position based on the passed position\n var pos = this.position;\n var zoom = this.cy.zoom();\n var pan = this.cy.pan();\n this.renderedPosition = {\n x: pos.x * zoom + pan.x,\n y: pos.y * zoom + pan.y\n };\n } // Create a timestamp if incoming event doesn't have one\n\n\n this.timeStamp = src && src.timeStamp || Date.now();\n },\n preventDefault: function preventDefault() {\n this.isDefaultPrevented = returnTrue;\n var e = this.originalEvent;\n\n if (!e) {\n return;\n } // if preventDefault exists run it on the original event\n\n\n if (e.preventDefault) {\n e.preventDefault();\n }\n },\n stopPropagation: function stopPropagation() {\n this.isPropagationStopped = returnTrue;\n var e = this.originalEvent;\n\n if (!e) {\n return;\n } // if stopPropagation exists run it on the original event\n\n\n if (e.stopPropagation) {\n e.stopPropagation();\n }\n },\n stopImmediatePropagation: function stopImmediatePropagation() {\n this.isImmediatePropagationStopped = returnTrue;\n this.stopPropagation();\n },\n isDefaultPrevented: returnFalse,\n isPropagationStopped: returnFalse,\n isImmediatePropagationStopped: returnFalse\n };\n\n var eventRegex = /^([^.]+)(\\.(?:[^.]+))?$/; // regex for matching event strings (e.g. \"click.namespace\")\n\n var universalNamespace = '.*'; // matches as if no namespace specified and prevents users from unbinding accidentally\n\n var defaults$8 = {\n qualifierCompare: function qualifierCompare(q1, q2) {\n return q1 === q2;\n },\n eventMatches: function\n /*context, listener, eventObj*/\n eventMatches() {\n return true;\n },\n addEventFields: function\n /*context, evt*/\n addEventFields() {},\n callbackContext: function callbackContext(context\n /*, listener, eventObj*/\n ) {\n return context;\n },\n beforeEmit: function\n /* context, listener, eventObj */\n beforeEmit() {},\n afterEmit: function\n /* context, listener, eventObj */\n afterEmit() {},\n bubble: function\n /*context*/\n bubble() {\n return false;\n },\n parent: function\n /*context*/\n parent() {\n return null;\n },\n context: null\n };\n var defaultsKeys = Object.keys(defaults$8);\n var emptyOpts = {};\n\n function Emitter() {\n var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : emptyOpts;\n var context = arguments.length > 1 ? arguments[1] : undefined;\n\n // micro-optimisation vs Object.assign() -- reduces Element instantiation time\n for (var i = 0; i < defaultsKeys.length; i++) {\n var key = defaultsKeys[i];\n this[key] = opts[key] || defaults$8[key];\n }\n\n this.context = context || this.context;\n this.listeners = [];\n this.emitting = 0;\n }\n\n var p = Emitter.prototype;\n\n var forEachEvent = function forEachEvent(self, handler, events, qualifier, callback, conf, confOverrides) {\n if (fn$6(qualifier)) {\n callback = qualifier;\n qualifier = null;\n }\n\n if (confOverrides) {\n if (conf == null) {\n conf = confOverrides;\n } else {\n conf = extend({}, conf, confOverrides);\n }\n }\n\n var eventList = array(events) ? events : events.split(/\\s+/);\n\n for (var i = 0; i < eventList.length; i++) {\n var evt = eventList[i];\n\n if (emptyString(evt)) {\n continue;\n }\n\n var match = evt.match(eventRegex); // type[.namespace]\n\n if (match) {\n var type = match[1];\n var namespace = match[2] ? match[2] : null;\n var ret = handler(self, evt, type, namespace, qualifier, callback, conf);\n\n if (ret === false) {\n break;\n } // allow exiting early\n\n }\n }\n };\n\n var makeEventObj = function makeEventObj(self, obj) {\n self.addEventFields(self.context, obj);\n return new Event(obj.type, obj);\n };\n\n var forEachEventObj = function forEachEventObj(self, handler, events) {\n if (event(events)) {\n handler(self, events);\n return;\n } else if (plainObject(events)) {\n handler(self, makeEventObj(self, events));\n return;\n }\n\n var eventList = array(events) ? events : events.split(/\\s+/);\n\n for (var i = 0; i < eventList.length; i++) {\n var evt = eventList[i];\n\n if (emptyString(evt)) {\n continue;\n }\n\n var match = evt.match(eventRegex); // type[.namespace]\n\n if (match) {\n var type = match[1];\n var namespace = match[2] ? match[2] : null;\n var eventObj = makeEventObj(self, {\n type: type,\n namespace: namespace,\n target: self.context\n });\n handler(self, eventObj);\n }\n }\n };\n\n p.on = p.addListener = function (events, qualifier, callback, conf, confOverrides) {\n forEachEvent(this, function (self, event, type, namespace, qualifier, callback, conf) {\n if (fn$6(callback)) {\n self.listeners.push({\n event: event,\n // full event string\n callback: callback,\n // callback to run\n type: type,\n // the event type (e.g. 'click')\n namespace: namespace,\n // the event namespace (e.g. \".foo\")\n qualifier: qualifier,\n // a restriction on whether to match this emitter\n conf: conf // additional configuration\n\n });\n }\n }, events, qualifier, callback, conf, confOverrides);\n return this;\n };\n\n p.one = function (events, qualifier, callback, conf) {\n return this.on(events, qualifier, callback, conf, {\n one: true\n });\n };\n\n p.removeListener = p.off = function (events, qualifier, callback, conf) {\n var _this = this;\n\n if (this.emitting !== 0) {\n this.listeners = copyArray$1(this.listeners);\n }\n\n var listeners = this.listeners;\n\n var _loop = function _loop(i) {\n var listener = listeners[i];\n forEachEvent(_this, function (self, event, type, namespace, qualifier, callback\n /*, conf*/\n ) {\n if ((listener.type === type || events === '*') && (!namespace && listener.namespace !== '.*' || listener.namespace === namespace) && (!qualifier || self.qualifierCompare(listener.qualifier, qualifier)) && (!callback || listener.callback === callback)) {\n listeners.splice(i, 1);\n return false;\n }\n }, events, qualifier, callback, conf);\n };\n\n for (var i = listeners.length - 1; i >= 0; i--) {\n _loop(i);\n }\n\n return this;\n };\n\n p.removeAllListeners = function () {\n return this.removeListener('*');\n };\n\n p.emit = p.trigger = function (events, extraParams, manualCallback) {\n var listeners = this.listeners;\n var numListenersBeforeEmit = listeners.length;\n this.emitting++;\n\n if (!array(extraParams)) {\n extraParams = [extraParams];\n }\n\n forEachEventObj(this, function (self, eventObj) {\n if (manualCallback != null) {\n listeners = [{\n event: eventObj.event,\n type: eventObj.type,\n namespace: eventObj.namespace,\n callback: manualCallback\n }];\n numListenersBeforeEmit = listeners.length;\n }\n\n var _loop2 = function _loop2(i) {\n var listener = listeners[i];\n\n if (listener.type === eventObj.type && (!listener.namespace || listener.namespace === eventObj.namespace || listener.namespace === universalNamespace) && self.eventMatches(self.context, listener, eventObj)) {\n var args = [eventObj];\n\n if (extraParams != null) {\n push(args, extraParams);\n }\n\n self.beforeEmit(self.context, listener, eventObj);\n\n if (listener.conf && listener.conf.one) {\n self.listeners = self.listeners.filter(function (l) {\n return l !== listener;\n });\n }\n\n var context = self.callbackContext(self.context, listener, eventObj);\n var ret = listener.callback.apply(context, args);\n self.afterEmit(self.context, listener, eventObj);\n\n if (ret === false) {\n eventObj.stopPropagation();\n eventObj.preventDefault();\n }\n } // if listener matches\n\n };\n\n for (var i = 0; i < numListenersBeforeEmit; i++) {\n _loop2(i);\n } // for listener\n\n\n if (self.bubble(self.context) && !eventObj.isPropagationStopped()) {\n self.parent(self.context).emit(eventObj, extraParams);\n }\n }, events);\n this.emitting--;\n return this;\n };\n\n var emitterOptions$1 = {\n qualifierCompare: function qualifierCompare(selector1, selector2) {\n if (selector1 == null || selector2 == null) {\n return selector1 == null && selector2 == null;\n } else {\n return selector1.sameText(selector2);\n }\n },\n eventMatches: function eventMatches(ele, listener, eventObj) {\n var selector = listener.qualifier;\n\n if (selector != null) {\n return ele !== eventObj.target && element(eventObj.target) && selector.matches(eventObj.target);\n }\n\n return true;\n },\n addEventFields: function addEventFields(ele, evt) {\n evt.cy = ele.cy();\n evt.target = ele;\n },\n callbackContext: function callbackContext(ele, listener, eventObj) {\n return listener.qualifier != null ? eventObj.target : ele;\n },\n beforeEmit: function beforeEmit(context, listener\n /*, eventObj*/\n ) {\n if (listener.conf && listener.conf.once) {\n listener.conf.onceCollection.removeListener(listener.event, listener.qualifier, listener.callback);\n }\n },\n bubble: function bubble() {\n return true;\n },\n parent: function parent(ele) {\n return ele.isChild() ? ele.parent() : ele.cy();\n }\n };\n\n var argSelector$1 = function argSelector(arg) {\n if (string(arg)) {\n return new Selector(arg);\n } else {\n return arg;\n }\n };\n\n var elesfn$9 = {\n createEmitter: function createEmitter() {\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n var _p = ele._private;\n\n if (!_p.emitter) {\n _p.emitter = new Emitter(emitterOptions$1, ele);\n }\n }\n\n return this;\n },\n emitter: function emitter() {\n return this._private.emitter;\n },\n on: function on(events, selector, callback) {\n var argSel = argSelector$1(selector);\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n ele.emitter().on(events, argSel, callback);\n }\n\n return this;\n },\n removeListener: function removeListener(events, selector, callback) {\n var argSel = argSelector$1(selector);\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n ele.emitter().removeListener(events, argSel, callback);\n }\n\n return this;\n },\n removeAllListeners: function removeAllListeners() {\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n ele.emitter().removeAllListeners();\n }\n\n return this;\n },\n one: function one(events, selector, callback) {\n var argSel = argSelector$1(selector);\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n ele.emitter().one(events, argSel, callback);\n }\n\n return this;\n },\n once: function once(events, selector, callback) {\n var argSel = argSelector$1(selector);\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n ele.emitter().on(events, argSel, callback, {\n once: true,\n onceCollection: this\n });\n }\n },\n emit: function emit(events, extraParams) {\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n ele.emitter().emit(events, extraParams);\n }\n\n return this;\n },\n emitAndNotify: function emitAndNotify(event, extraParams) {\n // for internal use only\n if (this.length === 0) {\n return;\n } // empty collections don't need to notify anything\n // notify renderer\n\n\n this.cy().notify(event, this);\n this.emit(event, extraParams);\n return this;\n }\n };\n define.eventAliasesOn(elesfn$9);\n\n var elesfn$8 = {\n nodes: function nodes(selector) {\n return this.filter(function (ele) {\n return ele.isNode();\n }).filter(selector);\n },\n edges: function edges(selector) {\n return this.filter(function (ele) {\n return ele.isEdge();\n }).filter(selector);\n },\n // internal helper to get nodes and edges as separate collections with single iteration over elements\n byGroup: function byGroup() {\n var nodes = this.spawn();\n var edges = this.spawn();\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n\n if (ele.isNode()) {\n nodes.push(ele);\n } else {\n edges.push(ele);\n }\n }\n\n return {\n nodes: nodes,\n edges: edges\n };\n },\n filter: function filter(_filter, thisArg) {\n if (_filter === undefined) {\n // check this first b/c it's the most common/performant case\n return this;\n } else if (string(_filter) || elementOrCollection(_filter)) {\n return new Selector(_filter).filter(this);\n } else if (fn$6(_filter)) {\n var filterEles = this.spawn();\n var eles = this;\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var include = thisArg ? _filter.apply(thisArg, [ele, i, eles]) : _filter(ele, i, eles);\n\n if (include) {\n filterEles.push(ele);\n }\n }\n\n return filterEles;\n }\n\n return this.spawn(); // if not handled by above, give 'em an empty collection\n },\n not: function not(toRemove) {\n if (!toRemove) {\n return this;\n } else {\n if (string(toRemove)) {\n toRemove = this.filter(toRemove);\n }\n\n var elements = this.spawn();\n\n for (var i = 0; i < this.length; i++) {\n var element = this[i];\n var remove = toRemove.has(element);\n\n if (!remove) {\n elements.push(element);\n }\n }\n\n return elements;\n }\n },\n absoluteComplement: function absoluteComplement() {\n var cy = this.cy();\n return cy.mutableElements().not(this);\n },\n intersect: function intersect(other) {\n // if a selector is specified, then filter by it instead\n if (string(other)) {\n var selector = other;\n return this.filter(selector);\n }\n\n var elements = this.spawn();\n var col1 = this;\n var col2 = other;\n var col1Smaller = this.length < other.length;\n var colS = col1Smaller ? col1 : col2;\n var colL = col1Smaller ? col2 : col1;\n\n for (var i = 0; i < colS.length; i++) {\n var ele = colS[i];\n\n if (colL.has(ele)) {\n elements.push(ele);\n }\n }\n\n return elements;\n },\n xor: function xor(other) {\n var cy = this._private.cy;\n\n if (string(other)) {\n other = cy.$(other);\n }\n\n var elements = this.spawn();\n var col1 = this;\n var col2 = other;\n\n var add = function add(col, other) {\n for (var i = 0; i < col.length; i++) {\n var ele = col[i];\n var id = ele._private.data.id;\n var inOther = other.hasElementWithId(id);\n\n if (!inOther) {\n elements.push(ele);\n }\n }\n };\n\n add(col1, col2);\n add(col2, col1);\n return elements;\n },\n diff: function diff(other) {\n var cy = this._private.cy;\n\n if (string(other)) {\n other = cy.$(other);\n }\n\n var left = this.spawn();\n var right = this.spawn();\n var both = this.spawn();\n var col1 = this;\n var col2 = other;\n\n var add = function add(col, other, retEles) {\n for (var i = 0; i < col.length; i++) {\n var ele = col[i];\n var id = ele._private.data.id;\n var inOther = other.hasElementWithId(id);\n\n if (inOther) {\n both.merge(ele);\n } else {\n retEles.push(ele);\n }\n }\n };\n\n add(col1, col2, left);\n add(col2, col1, right);\n return {\n left: left,\n right: right,\n both: both\n };\n },\n add: function add(toAdd) {\n var cy = this._private.cy;\n\n if (!toAdd) {\n return this;\n }\n\n if (string(toAdd)) {\n var selector = toAdd;\n toAdd = cy.mutableElements().filter(selector);\n }\n\n var elements = this.spawnSelf();\n\n for (var i = 0; i < toAdd.length; i++) {\n var ele = toAdd[i];\n var add = !this.has(ele);\n\n if (add) {\n elements.push(ele);\n }\n }\n\n return elements;\n },\n // in place merge on calling collection\n merge: function merge(toAdd) {\n var _p = this._private;\n var cy = _p.cy;\n\n if (!toAdd) {\n return this;\n }\n\n if (toAdd && string(toAdd)) {\n var selector = toAdd;\n toAdd = cy.mutableElements().filter(selector);\n }\n\n var map = _p.map;\n\n for (var i = 0; i < toAdd.length; i++) {\n var toAddEle = toAdd[i];\n var id = toAddEle._private.data.id;\n var add = !map.has(id);\n\n if (add) {\n var index = this.length++;\n this[index] = toAddEle;\n map.set(id, {\n ele: toAddEle,\n index: index\n });\n }\n }\n\n return this; // chaining\n },\n unmergeAt: function unmergeAt(i) {\n var ele = this[i];\n var id = ele.id();\n var _p = this._private;\n var map = _p.map; // remove ele\n\n this[i] = undefined;\n map[\"delete\"](id);\n var unmergedLastEle = i === this.length - 1; // replace empty spot with last ele in collection\n\n if (this.length > 1 && !unmergedLastEle) {\n var lastEleI = this.length - 1;\n var lastEle = this[lastEleI];\n var lastEleId = lastEle._private.data.id;\n this[lastEleI] = undefined;\n this[i] = lastEle;\n map.set(lastEleId, {\n ele: lastEle,\n index: i\n });\n } // the collection is now 1 ele smaller\n\n\n this.length--;\n return this;\n },\n // remove single ele in place in calling collection\n unmergeOne: function unmergeOne(ele) {\n ele = ele[0];\n var _p = this._private;\n var id = ele._private.data.id;\n var map = _p.map;\n var entry = map.get(id);\n\n if (!entry) {\n return this; // no need to remove\n }\n\n var i = entry.index;\n this.unmergeAt(i);\n return this;\n },\n // remove eles in place on calling collection\n unmerge: function unmerge(toRemove) {\n var cy = this._private.cy;\n\n if (!toRemove) {\n return this;\n }\n\n if (toRemove && string(toRemove)) {\n var selector = toRemove;\n toRemove = cy.mutableElements().filter(selector);\n }\n\n for (var i = 0; i < toRemove.length; i++) {\n this.unmergeOne(toRemove[i]);\n }\n\n return this; // chaining\n },\n unmergeBy: function unmergeBy(toRmFn) {\n for (var i = this.length - 1; i >= 0; i--) {\n var ele = this[i];\n\n if (toRmFn(ele)) {\n this.unmergeAt(i);\n }\n }\n\n return this;\n },\n map: function map(mapFn, thisArg) {\n var arr = [];\n var eles = this;\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var ret = thisArg ? mapFn.apply(thisArg, [ele, i, eles]) : mapFn(ele, i, eles);\n arr.push(ret);\n }\n\n return arr;\n },\n reduce: function reduce(fn, initialValue) {\n var val = initialValue;\n var eles = this;\n\n for (var i = 0; i < eles.length; i++) {\n val = fn(val, eles[i], i, eles);\n }\n\n return val;\n },\n max: function max(valFn, thisArg) {\n var max = -Infinity;\n var maxEle;\n var eles = this;\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var val = thisArg ? valFn.apply(thisArg, [ele, i, eles]) : valFn(ele, i, eles);\n\n if (val > max) {\n max = val;\n maxEle = ele;\n }\n }\n\n return {\n value: max,\n ele: maxEle\n };\n },\n min: function min(valFn, thisArg) {\n var min = Infinity;\n var minEle;\n var eles = this;\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var val = thisArg ? valFn.apply(thisArg, [ele, i, eles]) : valFn(ele, i, eles);\n\n if (val < min) {\n min = val;\n minEle = ele;\n }\n }\n\n return {\n value: min,\n ele: minEle\n };\n }\n }; // aliases\n\n var fn$1 = elesfn$8;\n fn$1['u'] = fn$1['|'] = fn$1['+'] = fn$1.union = fn$1.or = fn$1.add;\n fn$1['\\\\'] = fn$1['!'] = fn$1['-'] = fn$1.difference = fn$1.relativeComplement = fn$1.subtract = fn$1.not;\n fn$1['n'] = fn$1['&'] = fn$1['.'] = fn$1.and = fn$1.intersection = fn$1.intersect;\n fn$1['^'] = fn$1['(+)'] = fn$1['(-)'] = fn$1.symmetricDifference = fn$1.symdiff = fn$1.xor;\n fn$1.fnFilter = fn$1.filterFn = fn$1.stdFilter = fn$1.filter;\n fn$1.complement = fn$1.abscomp = fn$1.absoluteComplement;\n\n var elesfn$7 = {\n isNode: function isNode() {\n return this.group() === 'nodes';\n },\n isEdge: function isEdge() {\n return this.group() === 'edges';\n },\n isLoop: function isLoop() {\n return this.isEdge() && this.source()[0] === this.target()[0];\n },\n isSimple: function isSimple() {\n return this.isEdge() && this.source()[0] !== this.target()[0];\n },\n group: function group() {\n var ele = this[0];\n\n if (ele) {\n return ele._private.group;\n }\n }\n };\n\n /**\n * Elements are drawn in a specific order based on compound depth (low to high), the element type (nodes above edges),\n * and z-index (low to high). These styles affect how this applies:\n *\n * z-compound-depth: May be `bottom | orphan | auto | top`. The first drawn is `bottom`, then `orphan` which is the\n * same depth as the root of the compound graph, followed by the default value `auto` which draws in order from\n * root to leaves of the compound graph. The last drawn is `top`.\n * z-index-compare: May be `auto | manual`. The default value is `auto` which always draws edges under nodes.\n * `manual` ignores this convention and draws based on the `z-index` value setting.\n * z-index: An integer value that affects the relative draw order of elements. In general, an element with a higher\n * `z-index` will be drawn on top of an element with a lower `z-index`.\n */\n\n var zIndexSort = function zIndexSort(a, b) {\n var cy = a.cy();\n var hasCompoundNodes = cy.hasCompoundNodes();\n\n function getDepth(ele) {\n var style = ele.pstyle('z-compound-depth');\n\n if (style.value === 'auto') {\n return hasCompoundNodes ? ele.zDepth() : 0;\n } else if (style.value === 'bottom') {\n return -1;\n } else if (style.value === 'top') {\n return MAX_INT$1;\n } // 'orphan'\n\n\n return 0;\n }\n\n var depthDiff = getDepth(a) - getDepth(b);\n\n if (depthDiff !== 0) {\n return depthDiff;\n }\n\n function getEleDepth(ele) {\n var style = ele.pstyle('z-index-compare');\n\n if (style.value === 'auto') {\n return ele.isNode() ? 1 : 0;\n } // 'manual'\n\n\n return 0;\n }\n\n var eleDiff = getEleDepth(a) - getEleDepth(b);\n\n if (eleDiff !== 0) {\n return eleDiff;\n }\n\n var zDiff = a.pstyle('z-index').value - b.pstyle('z-index').value;\n\n if (zDiff !== 0) {\n return zDiff;\n } // compare indices in the core (order added to graph w/ last on top)\n\n\n return a.poolIndex() - b.poolIndex();\n };\n\n var elesfn$6 = {\n forEach: function forEach(fn, thisArg) {\n if (fn$6(fn)) {\n var N = this.length;\n\n for (var i = 0; i < N; i++) {\n var ele = this[i];\n var ret = thisArg ? fn.apply(thisArg, [ele, i, this]) : fn(ele, i, this);\n\n if (ret === false) {\n break;\n } // exit each early on return false\n\n }\n }\n\n return this;\n },\n toArray: function toArray() {\n var array = [];\n\n for (var i = 0; i < this.length; i++) {\n array.push(this[i]);\n }\n\n return array;\n },\n slice: function slice(start, end) {\n var array = [];\n var thisSize = this.length;\n\n if (end == null) {\n end = thisSize;\n }\n\n if (start == null) {\n start = 0;\n }\n\n if (start < 0) {\n start = thisSize + start;\n }\n\n if (end < 0) {\n end = thisSize + end;\n }\n\n for (var i = start; i >= 0 && i < end && i < thisSize; i++) {\n array.push(this[i]);\n }\n\n return this.spawn(array);\n },\n size: function size() {\n return this.length;\n },\n eq: function eq(i) {\n return this[i] || this.spawn();\n },\n first: function first() {\n return this[0] || this.spawn();\n },\n last: function last() {\n return this[this.length - 1] || this.spawn();\n },\n empty: function empty() {\n return this.length === 0;\n },\n nonempty: function nonempty() {\n return !this.empty();\n },\n sort: function sort(sortFn) {\n if (!fn$6(sortFn)) {\n return this;\n }\n\n var sorted = this.toArray().sort(sortFn);\n return this.spawn(sorted);\n },\n sortByZIndex: function sortByZIndex() {\n return this.sort(zIndexSort);\n },\n zDepth: function zDepth() {\n var ele = this[0];\n\n if (!ele) {\n return undefined;\n } // let cy = ele.cy();\n\n\n var _p = ele._private;\n var group = _p.group;\n\n if (group === 'nodes') {\n var depth = _p.data.parent ? ele.parents().size() : 0;\n\n if (!ele.isParent()) {\n return MAX_INT$1 - 1; // childless nodes always on top\n }\n\n return depth;\n } else {\n var src = _p.source;\n var tgt = _p.target;\n var srcDepth = src.zDepth();\n var tgtDepth = tgt.zDepth();\n return Math.max(srcDepth, tgtDepth, 0); // depth of deepest parent\n }\n }\n };\n elesfn$6.each = elesfn$6.forEach;\n\n var defineSymbolIterator = function defineSymbolIterator() {\n var typeofUndef = \"undefined\" ;\n var isIteratorSupported = (typeof Symbol === \"undefined\" ? \"undefined\" : _typeof(Symbol)) != typeofUndef && _typeof(Symbol.iterator) != typeofUndef; // eslint-disable-line no-undef\n\n if (isIteratorSupported) {\n elesfn$6[Symbol.iterator] = function () {\n var _this = this;\n\n // eslint-disable-line no-undef\n var entry = {\n value: undefined,\n done: false\n };\n var i = 0;\n var length = this.length;\n return _defineProperty$1({\n next: function next() {\n if (i < length) {\n entry.value = _this[i++];\n } else {\n entry.value = undefined;\n entry.done = true;\n }\n\n return entry;\n }\n }, Symbol.iterator, function () {\n // eslint-disable-line no-undef\n return this;\n });\n };\n }\n };\n\n defineSymbolIterator();\n\n var getLayoutDimensionOptions = defaults$g({\n nodeDimensionsIncludeLabels: false\n });\n var elesfn$5 = {\n // Calculates and returns node dimensions { x, y } based on options given\n layoutDimensions: function layoutDimensions(options) {\n options = getLayoutDimensionOptions(options);\n var dims;\n\n if (!this.takesUpSpace()) {\n dims = {\n w: 0,\n h: 0\n };\n } else if (options.nodeDimensionsIncludeLabels) {\n var bbDim = this.boundingBox();\n dims = {\n w: bbDim.w,\n h: bbDim.h\n };\n } else {\n dims = {\n w: this.outerWidth(),\n h: this.outerHeight()\n };\n } // sanitise the dimensions for external layouts (avoid division by zero)\n\n\n if (dims.w === 0 || dims.h === 0) {\n dims.w = dims.h = 1;\n }\n\n return dims;\n },\n // using standard layout options, apply position function (w/ or w/o animation)\n layoutPositions: function layoutPositions(layout, options, fn) {\n var nodes = this.nodes().filter(function (n) {\n return !n.isParent();\n });\n var cy = this.cy();\n var layoutEles = options.eles; // nodes & edges\n\n var getMemoizeKey = function getMemoizeKey(node) {\n return node.id();\n };\n\n var fnMem = memoize$1(fn, getMemoizeKey); // memoized version of position function\n\n layout.emit({\n type: 'layoutstart',\n layout: layout\n });\n layout.animations = [];\n\n var calculateSpacing = function calculateSpacing(spacing, nodesBb, pos) {\n var center = {\n x: nodesBb.x1 + nodesBb.w / 2,\n y: nodesBb.y1 + nodesBb.h / 2\n };\n var spacingVector = {\n // scale from center of bounding box (not necessarily 0,0)\n x: (pos.x - center.x) * spacing,\n y: (pos.y - center.y) * spacing\n };\n return {\n x: center.x + spacingVector.x,\n y: center.y + spacingVector.y\n };\n };\n\n var useSpacingFactor = options.spacingFactor && options.spacingFactor !== 1;\n\n var spacingBb = function spacingBb() {\n if (!useSpacingFactor) {\n return null;\n }\n\n var bb = makeBoundingBox();\n\n for (var i = 0; i < nodes.length; i++) {\n var node = nodes[i];\n var pos = fnMem(node, i);\n expandBoundingBoxByPoint(bb, pos.x, pos.y);\n }\n\n return bb;\n };\n\n var bb = spacingBb();\n var getFinalPos = memoize$1(function (node, i) {\n var newPos = fnMem(node, i);\n\n if (useSpacingFactor) {\n var spacing = Math.abs(options.spacingFactor);\n newPos = calculateSpacing(spacing, bb, newPos);\n }\n\n if (options.transform != null) {\n newPos = options.transform(node, newPos);\n }\n\n return newPos;\n }, getMemoizeKey);\n\n if (options.animate) {\n for (var i = 0; i < nodes.length; i++) {\n var node = nodes[i];\n var newPos = getFinalPos(node, i);\n var animateNode = options.animateFilter == null || options.animateFilter(node, i);\n\n if (animateNode) {\n var ani = node.animation({\n position: newPos,\n duration: options.animationDuration,\n easing: options.animationEasing\n });\n layout.animations.push(ani);\n } else {\n node.position(newPos);\n }\n }\n\n if (options.fit) {\n var fitAni = cy.animation({\n fit: {\n boundingBox: layoutEles.boundingBoxAt(getFinalPos),\n padding: options.padding\n },\n duration: options.animationDuration,\n easing: options.animationEasing\n });\n layout.animations.push(fitAni);\n } else if (options.zoom !== undefined && options.pan !== undefined) {\n var zoomPanAni = cy.animation({\n zoom: options.zoom,\n pan: options.pan,\n duration: options.animationDuration,\n easing: options.animationEasing\n });\n layout.animations.push(zoomPanAni);\n }\n\n layout.animations.forEach(function (ani) {\n return ani.play();\n });\n layout.one('layoutready', options.ready);\n layout.emit({\n type: 'layoutready',\n layout: layout\n });\n Promise$1.all(layout.animations.map(function (ani) {\n return ani.promise();\n })).then(function () {\n layout.one('layoutstop', options.stop);\n layout.emit({\n type: 'layoutstop',\n layout: layout\n });\n });\n } else {\n nodes.positions(getFinalPos);\n\n if (options.fit) {\n cy.fit(options.eles, options.padding);\n }\n\n if (options.zoom != null) {\n cy.zoom(options.zoom);\n }\n\n if (options.pan) {\n cy.pan(options.pan);\n }\n\n layout.one('layoutready', options.ready);\n layout.emit({\n type: 'layoutready',\n layout: layout\n });\n layout.one('layoutstop', options.stop);\n layout.emit({\n type: 'layoutstop',\n layout: layout\n });\n }\n\n return this; // chaining\n },\n layout: function layout(options) {\n var cy = this.cy();\n return cy.makeLayout(extend({}, options, {\n eles: this\n }));\n }\n }; // aliases:\n\n elesfn$5.createLayout = elesfn$5.makeLayout = elesfn$5.layout;\n\n function styleCache(key, fn, ele) {\n var _p = ele._private;\n var cache = _p.styleCache = _p.styleCache || [];\n var val;\n\n if ((val = cache[key]) != null) {\n return val;\n } else {\n val = cache[key] = fn(ele);\n return val;\n }\n }\n\n function cacheStyleFunction(key, fn) {\n key = hashString(key);\n return function cachedStyleFunction(ele) {\n return styleCache(key, fn, ele);\n };\n }\n\n function cachePrototypeStyleFunction(key, fn) {\n key = hashString(key);\n\n var selfFn = function selfFn(ele) {\n return fn.call(ele);\n };\n\n return function cachedPrototypeStyleFunction() {\n var ele = this[0];\n\n if (ele) {\n return styleCache(key, selfFn, ele);\n }\n };\n }\n\n var elesfn$4 = {\n recalculateRenderedStyle: function recalculateRenderedStyle(useCache) {\n var cy = this.cy();\n var renderer = cy.renderer();\n var styleEnabled = cy.styleEnabled();\n\n if (renderer && styleEnabled) {\n renderer.recalculateRenderedStyle(this, useCache);\n }\n\n return this;\n },\n dirtyStyleCache: function dirtyStyleCache() {\n var cy = this.cy();\n\n var dirty = function dirty(ele) {\n return ele._private.styleCache = null;\n };\n\n if (cy.hasCompoundNodes()) {\n var eles;\n eles = this.spawnSelf().merge(this.descendants()).merge(this.parents());\n eles.merge(eles.connectedEdges());\n eles.forEach(dirty);\n } else {\n this.forEach(function (ele) {\n dirty(ele);\n ele.connectedEdges().forEach(dirty);\n });\n }\n\n return this;\n },\n // fully updates (recalculates) the style for the elements\n updateStyle: function updateStyle(notifyRenderer) {\n var cy = this._private.cy;\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n if (cy.batching()) {\n var bEles = cy._private.batchStyleEles;\n bEles.merge(this);\n return this; // chaining and exit early when batching\n }\n\n var hasCompounds = cy.hasCompoundNodes();\n var updatedEles = this;\n notifyRenderer = notifyRenderer || notifyRenderer === undefined ? true : false;\n\n if (hasCompounds) {\n // then add everything up and down for compound selector checks\n updatedEles = this.spawnSelf().merge(this.descendants()).merge(this.parents());\n } // let changedEles = style.apply( updatedEles );\n\n\n var changedEles = updatedEles;\n\n if (notifyRenderer) {\n changedEles.emitAndNotify('style'); // let renderer know we changed style\n } else {\n changedEles.emit('style'); // just fire the event\n }\n\n updatedEles.forEach(function (ele) {\n return ele._private.styleDirty = true;\n });\n return this; // chaining\n },\n // private: clears dirty flag and recalculates style\n cleanStyle: function cleanStyle() {\n var cy = this.cy();\n\n if (!cy.styleEnabled()) {\n return;\n }\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n\n if (ele._private.styleDirty) {\n // n.b. this flag should be set before apply() to avoid potential infinite recursion\n ele._private.styleDirty = false;\n cy.style().apply(ele);\n }\n }\n },\n // get the internal parsed style object for the specified property\n parsedStyle: function parsedStyle(property) {\n var includeNonDefault = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n var ele = this[0];\n var cy = ele.cy();\n\n if (!cy.styleEnabled()) {\n return;\n }\n\n if (ele) {\n this.cleanStyle();\n var overriddenStyle = ele._private.style[property];\n\n if (overriddenStyle != null) {\n return overriddenStyle;\n } else if (includeNonDefault) {\n return cy.style().getDefaultProperty(property);\n } else {\n return null;\n }\n }\n },\n numericStyle: function numericStyle(property) {\n var ele = this[0];\n\n if (!ele.cy().styleEnabled()) {\n return;\n }\n\n if (ele) {\n var pstyle = ele.pstyle(property);\n return pstyle.pfValue !== undefined ? pstyle.pfValue : pstyle.value;\n }\n },\n numericStyleUnits: function numericStyleUnits(property) {\n var ele = this[0];\n\n if (!ele.cy().styleEnabled()) {\n return;\n }\n\n if (ele) {\n return ele.pstyle(property).units;\n }\n },\n // get the specified css property as a rendered value (i.e. on-screen value)\n // or get the whole rendered style if no property specified (NB doesn't allow setting)\n renderedStyle: function renderedStyle(property) {\n var cy = this.cy();\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n var ele = this[0];\n\n if (ele) {\n return cy.style().getRenderedStyle(ele, property);\n }\n },\n // read the calculated css style of the element or override the style (via a bypass)\n style: function style(name, value) {\n var cy = this.cy();\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n var updateTransitions = false;\n var style = cy.style();\n\n if (plainObject(name)) {\n // then extend the bypass\n var props = name;\n style.applyBypass(this, props, updateTransitions);\n this.emitAndNotify('style'); // let the renderer know we've updated style\n } else if (string(name)) {\n if (value === undefined) {\n // then get the property from the style\n var ele = this[0];\n\n if (ele) {\n return style.getStylePropertyValue(ele, name);\n } else {\n // empty collection => can't get any value\n return;\n }\n } else {\n // then set the bypass with the property value\n style.applyBypass(this, name, value, updateTransitions);\n this.emitAndNotify('style'); // let the renderer know we've updated style\n }\n } else if (name === undefined) {\n var _ele = this[0];\n\n if (_ele) {\n return style.getRawStyle(_ele);\n } else {\n // empty collection => can't get any value\n return;\n }\n }\n\n return this; // chaining\n },\n removeStyle: function removeStyle(names) {\n var cy = this.cy();\n\n if (!cy.styleEnabled()) {\n return this;\n }\n\n var updateTransitions = false;\n var style = cy.style();\n var eles = this;\n\n if (names === undefined) {\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n style.removeAllBypasses(ele, updateTransitions);\n }\n } else {\n names = names.split(/\\s+/);\n\n for (var _i = 0; _i < eles.length; _i++) {\n var _ele2 = eles[_i];\n style.removeBypasses(_ele2, names, updateTransitions);\n }\n }\n\n this.emitAndNotify('style'); // let the renderer know we've updated style\n\n return this; // chaining\n },\n show: function show() {\n this.css('display', 'element');\n return this; // chaining\n },\n hide: function hide() {\n this.css('display', 'none');\n return this; // chaining\n },\n effectiveOpacity: function effectiveOpacity() {\n var cy = this.cy();\n\n if (!cy.styleEnabled()) {\n return 1;\n }\n\n var hasCompoundNodes = cy.hasCompoundNodes();\n var ele = this[0];\n\n if (ele) {\n var _p = ele._private;\n var parentOpacity = ele.pstyle('opacity').value;\n\n if (!hasCompoundNodes) {\n return parentOpacity;\n }\n\n var parents = !_p.data.parent ? null : ele.parents();\n\n if (parents) {\n for (var i = 0; i < parents.length; i++) {\n var parent = parents[i];\n var opacity = parent.pstyle('opacity').value;\n parentOpacity = opacity * parentOpacity;\n }\n }\n\n return parentOpacity;\n }\n },\n transparent: function transparent() {\n var cy = this.cy();\n\n if (!cy.styleEnabled()) {\n return false;\n }\n\n var ele = this[0];\n var hasCompoundNodes = ele.cy().hasCompoundNodes();\n\n if (ele) {\n if (!hasCompoundNodes) {\n return ele.pstyle('opacity').value === 0;\n } else {\n return ele.effectiveOpacity() === 0;\n }\n }\n },\n backgrounding: function backgrounding() {\n var cy = this.cy();\n\n if (!cy.styleEnabled()) {\n return false;\n }\n\n var ele = this[0];\n return ele._private.backgrounding ? true : false;\n }\n };\n\n function checkCompound(ele, parentOk) {\n var _p = ele._private;\n var parents = _p.data.parent ? ele.parents() : null;\n\n if (parents) {\n for (var i = 0; i < parents.length; i++) {\n var parent = parents[i];\n\n if (!parentOk(parent)) {\n return false;\n }\n }\n }\n\n return true;\n }\n\n function defineDerivedStateFunction(specs) {\n var ok = specs.ok;\n var edgeOkViaNode = specs.edgeOkViaNode || specs.ok;\n var parentOk = specs.parentOk || specs.ok;\n return function () {\n var cy = this.cy();\n\n if (!cy.styleEnabled()) {\n return true;\n }\n\n var ele = this[0];\n var hasCompoundNodes = cy.hasCompoundNodes();\n\n if (ele) {\n var _p = ele._private;\n\n if (!ok(ele)) {\n return false;\n }\n\n if (ele.isNode()) {\n return !hasCompoundNodes || checkCompound(ele, parentOk);\n } else {\n var src = _p.source;\n var tgt = _p.target;\n return edgeOkViaNode(src) && (!hasCompoundNodes || checkCompound(src, edgeOkViaNode)) && (src === tgt || edgeOkViaNode(tgt) && (!hasCompoundNodes || checkCompound(tgt, edgeOkViaNode)));\n }\n }\n };\n }\n\n var eleTakesUpSpace = cacheStyleFunction('eleTakesUpSpace', function (ele) {\n return ele.pstyle('display').value === 'element' && ele.width() !== 0 && (ele.isNode() ? ele.height() !== 0 : true);\n });\n elesfn$4.takesUpSpace = cachePrototypeStyleFunction('takesUpSpace', defineDerivedStateFunction({\n ok: eleTakesUpSpace\n }));\n var eleInteractive = cacheStyleFunction('eleInteractive', function (ele) {\n return ele.pstyle('events').value === 'yes' && ele.pstyle('visibility').value === 'visible' && eleTakesUpSpace(ele);\n });\n var parentInteractive = cacheStyleFunction('parentInteractive', function (parent) {\n return parent.pstyle('visibility').value === 'visible' && eleTakesUpSpace(parent);\n });\n elesfn$4.interactive = cachePrototypeStyleFunction('interactive', defineDerivedStateFunction({\n ok: eleInteractive,\n parentOk: parentInteractive,\n edgeOkViaNode: eleTakesUpSpace\n }));\n\n elesfn$4.noninteractive = function () {\n var ele = this[0];\n\n if (ele) {\n return !ele.interactive();\n }\n };\n\n var eleVisible = cacheStyleFunction('eleVisible', function (ele) {\n return ele.pstyle('visibility').value === 'visible' && ele.pstyle('opacity').pfValue !== 0 && eleTakesUpSpace(ele);\n });\n var edgeVisibleViaNode = eleTakesUpSpace;\n elesfn$4.visible = cachePrototypeStyleFunction('visible', defineDerivedStateFunction({\n ok: eleVisible,\n edgeOkViaNode: edgeVisibleViaNode\n }));\n\n elesfn$4.hidden = function () {\n var ele = this[0];\n\n if (ele) {\n return !ele.visible();\n }\n };\n\n elesfn$4.isBundledBezier = cachePrototypeStyleFunction('isBundledBezier', function () {\n if (!this.cy().styleEnabled()) {\n return false;\n }\n\n return !this.removed() && this.pstyle('curve-style').value === 'bezier' && this.takesUpSpace();\n });\n elesfn$4.bypass = elesfn$4.css = elesfn$4.style;\n elesfn$4.renderedCss = elesfn$4.renderedStyle;\n elesfn$4.removeBypass = elesfn$4.removeCss = elesfn$4.removeStyle;\n elesfn$4.pstyle = elesfn$4.parsedStyle;\n\n var elesfn$3 = {};\n\n function defineSwitchFunction(params) {\n return function () {\n var args = arguments;\n var changedEles = []; // e.g. cy.nodes().select( data, handler )\n\n if (args.length === 2) {\n var data = args[0];\n var handler = args[1];\n this.on(params.event, data, handler);\n } // e.g. cy.nodes().select( handler )\n else if (args.length === 1 && fn$6(args[0])) {\n var _handler = args[0];\n this.on(params.event, _handler);\n } // e.g. cy.nodes().select()\n // e.g. (private) cy.nodes().select(['tapselect'])\n else if (args.length === 0 || args.length === 1 && array(args[0])) {\n var addlEvents = args.length === 1 ? args[0] : null;\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n var able = !params.ableField || ele._private[params.ableField];\n var changed = ele._private[params.field] != params.value;\n\n if (params.overrideAble) {\n var overrideAble = params.overrideAble(ele);\n\n if (overrideAble !== undefined) {\n able = overrideAble;\n\n if (!overrideAble) {\n return this;\n } // to save cycles assume not able for all on override\n\n }\n }\n\n if (able) {\n ele._private[params.field] = params.value;\n\n if (changed) {\n changedEles.push(ele);\n }\n }\n }\n\n var changedColl = this.spawn(changedEles);\n changedColl.updateStyle(); // change of state => possible change of style\n\n changedColl.emit(params.event);\n\n if (addlEvents) {\n changedColl.emit(addlEvents);\n }\n }\n\n return this;\n };\n }\n\n function defineSwitchSet(params) {\n elesfn$3[params.field] = function () {\n var ele = this[0];\n\n if (ele) {\n if (params.overrideField) {\n var val = params.overrideField(ele);\n\n if (val !== undefined) {\n return val;\n }\n }\n\n return ele._private[params.field];\n }\n };\n\n elesfn$3[params.on] = defineSwitchFunction({\n event: params.on,\n field: params.field,\n ableField: params.ableField,\n overrideAble: params.overrideAble,\n value: true\n });\n elesfn$3[params.off] = defineSwitchFunction({\n event: params.off,\n field: params.field,\n ableField: params.ableField,\n overrideAble: params.overrideAble,\n value: false\n });\n }\n\n defineSwitchSet({\n field: 'locked',\n overrideField: function overrideField(ele) {\n return ele.cy().autolock() ? true : undefined;\n },\n on: 'lock',\n off: 'unlock'\n });\n defineSwitchSet({\n field: 'grabbable',\n overrideField: function overrideField(ele) {\n return ele.cy().autoungrabify() || ele.pannable() ? false : undefined;\n },\n on: 'grabify',\n off: 'ungrabify'\n });\n defineSwitchSet({\n field: 'selected',\n ableField: 'selectable',\n overrideAble: function overrideAble(ele) {\n return ele.cy().autounselectify() ? false : undefined;\n },\n on: 'select',\n off: 'unselect'\n });\n defineSwitchSet({\n field: 'selectable',\n overrideField: function overrideField(ele) {\n return ele.cy().autounselectify() ? false : undefined;\n },\n on: 'selectify',\n off: 'unselectify'\n });\n elesfn$3.deselect = elesfn$3.unselect;\n\n elesfn$3.grabbed = function () {\n var ele = this[0];\n\n if (ele) {\n return ele._private.grabbed;\n }\n };\n\n defineSwitchSet({\n field: 'active',\n on: 'activate',\n off: 'unactivate'\n });\n defineSwitchSet({\n field: 'pannable',\n on: 'panify',\n off: 'unpanify'\n });\n\n elesfn$3.inactive = function () {\n var ele = this[0];\n\n if (ele) {\n return !ele._private.active;\n }\n };\n\n var elesfn$2 = {}; // DAG functions\n ////////////////\n\n var defineDagExtremity = function defineDagExtremity(params) {\n return function dagExtremityImpl(selector) {\n var eles = this;\n var ret = [];\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n\n if (!ele.isNode()) {\n continue;\n }\n\n var disqualified = false;\n var edges = ele.connectedEdges();\n\n for (var j = 0; j < edges.length; j++) {\n var edge = edges[j];\n var src = edge.source();\n var tgt = edge.target();\n\n if (params.noIncomingEdges && tgt === ele && src !== ele || params.noOutgoingEdges && src === ele && tgt !== ele) {\n disqualified = true;\n break;\n }\n }\n\n if (!disqualified) {\n ret.push(ele);\n }\n }\n\n return this.spawn(ret, true).filter(selector);\n };\n };\n\n var defineDagOneHop = function defineDagOneHop(params) {\n return function (selector) {\n var eles = this;\n var oEles = [];\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n\n if (!ele.isNode()) {\n continue;\n }\n\n var edges = ele.connectedEdges();\n\n for (var j = 0; j < edges.length; j++) {\n var edge = edges[j];\n var src = edge.source();\n var tgt = edge.target();\n\n if (params.outgoing && src === ele) {\n oEles.push(edge);\n oEles.push(tgt);\n } else if (params.incoming && tgt === ele) {\n oEles.push(edge);\n oEles.push(src);\n }\n }\n }\n\n return this.spawn(oEles, true).filter(selector);\n };\n };\n\n var defineDagAllHops = function defineDagAllHops(params) {\n return function (selector) {\n var eles = this;\n var sEles = [];\n var sElesIds = {};\n\n for (;;) {\n var next = params.outgoing ? eles.outgoers() : eles.incomers();\n\n if (next.length === 0) {\n break;\n } // done if none left\n\n\n var newNext = false;\n\n for (var i = 0; i < next.length; i++) {\n var n = next[i];\n var nid = n.id();\n\n if (!sElesIds[nid]) {\n sElesIds[nid] = true;\n sEles.push(n);\n newNext = true;\n }\n }\n\n if (!newNext) {\n break;\n } // done if touched all outgoers already\n\n\n eles = next;\n }\n\n return this.spawn(sEles, true).filter(selector);\n };\n };\n\n elesfn$2.clearTraversalCache = function () {\n for (var i = 0; i < this.length; i++) {\n this[i]._private.traversalCache = null;\n }\n };\n\n extend(elesfn$2, {\n // get the root nodes in the DAG\n roots: defineDagExtremity({\n noIncomingEdges: true\n }),\n // get the leaf nodes in the DAG\n leaves: defineDagExtremity({\n noOutgoingEdges: true\n }),\n // normally called children in graph theory\n // these nodes =edges=> outgoing nodes\n outgoers: cache(defineDagOneHop({\n outgoing: true\n }), 'outgoers'),\n // aka DAG descendants\n successors: defineDagAllHops({\n outgoing: true\n }),\n // normally called parents in graph theory\n // these nodes <=edges= incoming nodes\n incomers: cache(defineDagOneHop({\n incoming: true\n }), 'incomers'),\n // aka DAG ancestors\n predecessors: defineDagAllHops({\n incoming: true\n })\n }); // Neighbourhood functions\n //////////////////////////\n\n extend(elesfn$2, {\n neighborhood: cache(function (selector) {\n var elements = [];\n var nodes = this.nodes();\n\n for (var i = 0; i < nodes.length; i++) {\n // for all nodes\n var node = nodes[i];\n var connectedEdges = node.connectedEdges(); // for each connected edge, add the edge and the other node\n\n for (var j = 0; j < connectedEdges.length; j++) {\n var edge = connectedEdges[j];\n var src = edge.source();\n var tgt = edge.target();\n var otherNode = node === src ? tgt : src; // need check in case of loop\n\n if (otherNode.length > 0) {\n elements.push(otherNode[0]); // add node 1 hop away\n } // add connected edge\n\n\n elements.push(edge[0]);\n }\n }\n\n return this.spawn(elements, true).filter(selector);\n }, 'neighborhood'),\n closedNeighborhood: function closedNeighborhood(selector) {\n return this.neighborhood().add(this).filter(selector);\n },\n openNeighborhood: function openNeighborhood(selector) {\n return this.neighborhood(selector);\n }\n }); // aliases\n\n elesfn$2.neighbourhood = elesfn$2.neighborhood;\n elesfn$2.closedNeighbourhood = elesfn$2.closedNeighborhood;\n elesfn$2.openNeighbourhood = elesfn$2.openNeighborhood; // Edge functions\n /////////////////\n\n extend(elesfn$2, {\n source: cache(function sourceImpl(selector) {\n var ele = this[0];\n var src;\n\n if (ele) {\n src = ele._private.source || ele.cy().collection();\n }\n\n return src && selector ? src.filter(selector) : src;\n }, 'source'),\n target: cache(function targetImpl(selector) {\n var ele = this[0];\n var tgt;\n\n if (ele) {\n tgt = ele._private.target || ele.cy().collection();\n }\n\n return tgt && selector ? tgt.filter(selector) : tgt;\n }, 'target'),\n sources: defineSourceFunction({\n attr: 'source'\n }),\n targets: defineSourceFunction({\n attr: 'target'\n })\n });\n\n function defineSourceFunction(params) {\n return function sourceImpl(selector) {\n var sources = [];\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n var src = ele._private[params.attr];\n\n if (src) {\n sources.push(src);\n }\n }\n\n return this.spawn(sources, true).filter(selector);\n };\n }\n\n extend(elesfn$2, {\n edgesWith: cache(defineEdgesWithFunction(), 'edgesWith'),\n edgesTo: cache(defineEdgesWithFunction({\n thisIsSrc: true\n }), 'edgesTo')\n });\n\n function defineEdgesWithFunction(params) {\n return function edgesWithImpl(otherNodes) {\n var elements = [];\n var cy = this._private.cy;\n var p = params || {}; // get elements if a selector is specified\n\n if (string(otherNodes)) {\n otherNodes = cy.$(otherNodes);\n }\n\n for (var h = 0; h < otherNodes.length; h++) {\n var edges = otherNodes[h]._private.edges;\n\n for (var i = 0; i < edges.length; i++) {\n var edge = edges[i];\n var edgeData = edge._private.data;\n var thisToOther = this.hasElementWithId(edgeData.source) && otherNodes.hasElementWithId(edgeData.target);\n var otherToThis = otherNodes.hasElementWithId(edgeData.source) && this.hasElementWithId(edgeData.target);\n var edgeConnectsThisAndOther = thisToOther || otherToThis;\n\n if (!edgeConnectsThisAndOther) {\n continue;\n }\n\n if (p.thisIsSrc || p.thisIsTgt) {\n if (p.thisIsSrc && !thisToOther) {\n continue;\n }\n\n if (p.thisIsTgt && !otherToThis) {\n continue;\n }\n }\n\n elements.push(edge);\n }\n }\n\n return this.spawn(elements, true);\n };\n }\n\n extend(elesfn$2, {\n connectedEdges: cache(function (selector) {\n var retEles = [];\n var eles = this;\n\n for (var i = 0; i < eles.length; i++) {\n var node = eles[i];\n\n if (!node.isNode()) {\n continue;\n }\n\n var edges = node._private.edges;\n\n for (var j = 0; j < edges.length; j++) {\n var edge = edges[j];\n retEles.push(edge);\n }\n }\n\n return this.spawn(retEles, true).filter(selector);\n }, 'connectedEdges'),\n connectedNodes: cache(function (selector) {\n var retEles = [];\n var eles = this;\n\n for (var i = 0; i < eles.length; i++) {\n var edge = eles[i];\n\n if (!edge.isEdge()) {\n continue;\n }\n\n retEles.push(edge.source()[0]);\n retEles.push(edge.target()[0]);\n }\n\n return this.spawn(retEles, true).filter(selector);\n }, 'connectedNodes'),\n parallelEdges: cache(defineParallelEdgesFunction(), 'parallelEdges'),\n codirectedEdges: cache(defineParallelEdgesFunction({\n codirected: true\n }), 'codirectedEdges')\n });\n\n function defineParallelEdgesFunction(params) {\n var defaults = {\n codirected: false\n };\n params = extend({}, defaults, params);\n return function parallelEdgesImpl(selector) {\n // micro-optimised for renderer\n var elements = [];\n var edges = this.edges();\n var p = params; // look at all the edges in the collection\n\n for (var i = 0; i < edges.length; i++) {\n var edge1 = edges[i];\n var edge1_p = edge1._private;\n var src1 = edge1_p.source;\n var srcid1 = src1._private.data.id;\n var tgtid1 = edge1_p.data.target;\n var srcEdges1 = src1._private.edges; // look at edges connected to the src node of this edge\n\n for (var j = 0; j < srcEdges1.length; j++) {\n var edge2 = srcEdges1[j];\n var edge2data = edge2._private.data;\n var tgtid2 = edge2data.target;\n var srcid2 = edge2data.source;\n var codirected = tgtid2 === tgtid1 && srcid2 === srcid1;\n var oppdirected = srcid1 === tgtid2 && tgtid1 === srcid2;\n\n if (p.codirected && codirected || !p.codirected && (codirected || oppdirected)) {\n elements.push(edge2);\n }\n }\n }\n\n return this.spawn(elements, true).filter(selector);\n };\n } // Misc functions\n /////////////////\n\n\n extend(elesfn$2, {\n components: function components(root) {\n var self = this;\n var cy = self.cy();\n var visited = cy.collection();\n var unvisited = root == null ? self.nodes() : root.nodes();\n var components = [];\n\n if (root != null && unvisited.empty()) {\n // root may contain only edges\n unvisited = root.sources(); // doesn't matter which node to use (undirected), so just use the source sides\n }\n\n var visitInComponent = function visitInComponent(node, component) {\n visited.merge(node);\n unvisited.unmerge(node);\n component.merge(node);\n };\n\n if (unvisited.empty()) {\n return self.spawn();\n }\n\n var _loop = function _loop() {\n // each iteration yields a component\n var cmpt = cy.collection();\n components.push(cmpt);\n var root = unvisited[0];\n visitInComponent(root, cmpt);\n self.bfs({\n directed: false,\n roots: root,\n visit: function visit(v) {\n return visitInComponent(v, cmpt);\n }\n });\n cmpt.forEach(function (node) {\n node.connectedEdges().forEach(function (e) {\n // connectedEdges() usually cached\n if (self.has(e) && cmpt.has(e.source()) && cmpt.has(e.target())) {\n // has() is cheap\n cmpt.merge(e); // forEach() only considers nodes -- sets N at call time\n }\n });\n });\n };\n\n do {\n _loop();\n } while (unvisited.length > 0);\n\n return components;\n },\n component: function component() {\n var ele = this[0];\n return ele.cy().mutableElements().components(ele)[0];\n }\n });\n elesfn$2.componentsOf = elesfn$2.components;\n\n var Collection = function Collection(cy, elements) {\n var unique = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n var removed = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n\n if (cy === undefined) {\n error('A collection must have a reference to the core');\n return;\n }\n\n var map = new Map$2();\n var createdElements = false;\n\n if (!elements) {\n elements = [];\n } else if (elements.length > 0 && plainObject(elements[0]) && !element(elements[0])) {\n createdElements = true; // make elements from json and restore all at once later\n\n var eles = [];\n var elesIds = new Set$1();\n\n for (var i = 0, l = elements.length; i < l; i++) {\n var json = elements[i];\n\n if (json.data == null) {\n json.data = {};\n }\n\n var _data = json.data; // make sure newly created elements have valid ids\n\n if (_data.id == null) {\n _data.id = uuid();\n } else if (cy.hasElementWithId(_data.id) || elesIds.has(_data.id)) {\n continue; // can't create element if prior id already exists\n }\n\n var ele = new Element(cy, json, false);\n eles.push(ele);\n elesIds.add(_data.id);\n }\n\n elements = eles;\n }\n\n this.length = 0;\n\n for (var _i = 0, _l = elements.length; _i < _l; _i++) {\n var element$1 = elements[_i][0]; // [0] in case elements is an array of collections, rather than array of elements\n\n if (element$1 == null) {\n continue;\n }\n\n var id = element$1._private.data.id;\n\n if (!unique || !map.has(id)) {\n if (unique) {\n map.set(id, {\n index: this.length,\n ele: element$1\n });\n }\n\n this[this.length] = element$1;\n this.length++;\n }\n }\n\n this._private = {\n eles: this,\n cy: cy,\n\n get map() {\n if (this.lazyMap == null) {\n this.rebuildMap();\n }\n\n return this.lazyMap;\n },\n\n set map(m) {\n this.lazyMap = m;\n },\n\n rebuildMap: function rebuildMap() {\n var m = this.lazyMap = new Map$2();\n var eles = this.eles;\n\n for (var _i2 = 0; _i2 < eles.length; _i2++) {\n var _ele = eles[_i2];\n m.set(_ele.id(), {\n index: _i2,\n ele: _ele\n });\n }\n }\n };\n\n if (unique) {\n this._private.map = map;\n } // restore the elements if we created them from json\n\n\n if (createdElements && !removed) {\n this.restore();\n }\n }; // Functions\n ////////////////////////////////////////////////////////////////////////////////////////////////////\n // keep the prototypes in sync (an element has the same functions as a collection)\n // and use elefn and elesfn as shorthands to the prototypes\n\n\n var elesfn$1 = Element.prototype = Collection.prototype = Object.create(Array.prototype);\n\n elesfn$1.instanceString = function () {\n return 'collection';\n };\n\n elesfn$1.spawn = function (eles, unique) {\n return new Collection(this.cy(), eles, unique);\n };\n\n elesfn$1.spawnSelf = function () {\n return this.spawn(this);\n };\n\n elesfn$1.cy = function () {\n return this._private.cy;\n };\n\n elesfn$1.renderer = function () {\n return this._private.cy.renderer();\n };\n\n elesfn$1.element = function () {\n return this[0];\n };\n\n elesfn$1.collection = function () {\n if (collection(this)) {\n return this;\n } else {\n // an element\n return new Collection(this._private.cy, [this]);\n }\n };\n\n elesfn$1.unique = function () {\n return new Collection(this._private.cy, this, true);\n };\n\n elesfn$1.hasElementWithId = function (id) {\n id = '' + id; // id must be string\n\n return this._private.map.has(id);\n };\n\n elesfn$1.getElementById = function (id) {\n id = '' + id; // id must be string\n\n var cy = this._private.cy;\n\n var entry = this._private.map.get(id);\n\n return entry ? entry.ele : new Collection(cy); // get ele or empty collection\n };\n\n elesfn$1.$id = elesfn$1.getElementById;\n\n elesfn$1.poolIndex = function () {\n var cy = this._private.cy;\n var eles = cy._private.elements;\n var id = this[0]._private.data.id;\n return eles._private.map.get(id).index;\n };\n\n elesfn$1.indexOf = function (ele) {\n var id = ele[0]._private.data.id;\n return this._private.map.get(id).index;\n };\n\n elesfn$1.indexOfId = function (id) {\n id = '' + id; // id must be string\n\n return this._private.map.get(id).index;\n };\n\n elesfn$1.json = function (obj) {\n var ele = this.element();\n var cy = this.cy();\n\n if (ele == null && obj) {\n return this;\n } // can't set to no eles\n\n\n if (ele == null) {\n return undefined;\n } // can't get from no eles\n\n\n var p = ele._private;\n\n if (plainObject(obj)) {\n // set\n cy.startBatch();\n\n if (obj.data) {\n ele.data(obj.data);\n var _data2 = p.data;\n\n if (ele.isEdge()) {\n // source and target are immutable via data()\n var move = false;\n var spec = {};\n var src = obj.data.source;\n var tgt = obj.data.target;\n\n if (src != null && src != _data2.source) {\n spec.source = '' + src; // id must be string\n\n move = true;\n }\n\n if (tgt != null && tgt != _data2.target) {\n spec.target = '' + tgt; // id must be string\n\n move = true;\n }\n\n if (move) {\n ele = ele.move(spec);\n }\n } else {\n // parent is immutable via data()\n var newParentValSpecd = ('parent' in obj.data);\n var parent = obj.data.parent;\n\n if (newParentValSpecd && (parent != null || _data2.parent != null) && parent != _data2.parent) {\n if (parent === undefined) {\n // can't set undefined imperatively, so use null\n parent = null;\n }\n\n if (parent != null) {\n parent = '' + parent; // id must be string\n }\n\n ele = ele.move({\n parent: parent\n });\n }\n }\n }\n\n if (obj.position) {\n ele.position(obj.position);\n } // ignore group -- immutable\n\n\n var checkSwitch = function checkSwitch(k, trueFnName, falseFnName) {\n var obj_k = obj[k];\n\n if (obj_k != null && obj_k !== p[k]) {\n if (obj_k) {\n ele[trueFnName]();\n } else {\n ele[falseFnName]();\n }\n }\n };\n\n checkSwitch('removed', 'remove', 'restore');\n checkSwitch('selected', 'select', 'unselect');\n checkSwitch('selectable', 'selectify', 'unselectify');\n checkSwitch('locked', 'lock', 'unlock');\n checkSwitch('grabbable', 'grabify', 'ungrabify');\n checkSwitch('pannable', 'panify', 'unpanify');\n\n if (obj.classes != null) {\n ele.classes(obj.classes);\n }\n\n cy.endBatch();\n return this;\n } else if (obj === undefined) {\n // get\n var json = {\n data: copy(p.data),\n position: copy(p.position),\n group: p.group,\n removed: p.removed,\n selected: p.selected,\n selectable: p.selectable,\n locked: p.locked,\n grabbable: p.grabbable,\n pannable: p.pannable,\n classes: null\n };\n json.classes = '';\n var i = 0;\n p.classes.forEach(function (cls) {\n return json.classes += i++ === 0 ? cls : ' ' + cls;\n });\n return json;\n }\n };\n\n elesfn$1.jsons = function () {\n var jsons = [];\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n var json = ele.json();\n jsons.push(json);\n }\n\n return jsons;\n };\n\n elesfn$1.clone = function () {\n var cy = this.cy();\n var elesArr = [];\n\n for (var i = 0; i < this.length; i++) {\n var ele = this[i];\n var json = ele.json();\n var clone = new Element(cy, json, false); // NB no restore\n\n elesArr.push(clone);\n }\n\n return new Collection(cy, elesArr);\n };\n\n elesfn$1.copy = elesfn$1.clone;\n\n elesfn$1.restore = function () {\n var notifyRenderer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n var addToPool = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n var self = this;\n var cy = self.cy();\n var cy_p = cy._private; // create arrays of nodes and edges, since we need to\n // restore the nodes first\n\n var nodes = [];\n var edges = [];\n var elements;\n\n for (var _i3 = 0, l = self.length; _i3 < l; _i3++) {\n var ele = self[_i3];\n\n if (addToPool && !ele.removed()) {\n // don't need to handle this ele\n continue;\n } // keep nodes first in the array and edges after\n\n\n if (ele.isNode()) {\n // put to front of array if node\n nodes.push(ele);\n } else {\n // put to end of array if edge\n edges.push(ele);\n }\n }\n\n elements = nodes.concat(edges);\n var i;\n\n var removeFromElements = function removeFromElements() {\n elements.splice(i, 1);\n i--;\n }; // now, restore each element\n\n\n for (i = 0; i < elements.length; i++) {\n var _ele2 = elements[i];\n var _private = _ele2._private;\n var _data3 = _private.data; // the traversal cache should start fresh when ele is added\n\n _ele2.clearTraversalCache(); // set id and validate\n\n\n if (!addToPool && !_private.removed) ; else if (_data3.id === undefined) {\n _data3.id = uuid();\n } else if (number$1(_data3.id)) {\n _data3.id = '' + _data3.id; // now it's a string\n } else if (emptyString(_data3.id) || !string(_data3.id)) {\n error('Can not create element with invalid string ID `' + _data3.id + '`'); // can't create element if it has empty string as id or non-string id\n\n removeFromElements();\n continue;\n } else if (cy.hasElementWithId(_data3.id)) {\n error('Can not create second element with ID `' + _data3.id + '`'); // can't create element if one already has that id\n\n removeFromElements();\n continue;\n }\n\n var id = _data3.id; // id is finalised, now let's keep a ref\n\n if (_ele2.isNode()) {\n // extra checks for nodes\n var pos = _private.position; // make sure the nodes have a defined position\n\n if (pos.x == null) {\n pos.x = 0;\n }\n\n if (pos.y == null) {\n pos.y = 0;\n }\n }\n\n if (_ele2.isEdge()) {\n // extra checks for edges\n var edge = _ele2;\n var fields = ['source', 'target'];\n var fieldsLength = fields.length;\n var badSourceOrTarget = false;\n\n for (var j = 0; j < fieldsLength; j++) {\n var field = fields[j];\n var val = _data3[field];\n\n if (number$1(val)) {\n val = _data3[field] = '' + _data3[field]; // now string\n }\n\n if (val == null || val === '') {\n // can't create if source or target is not defined properly\n error('Can not create edge `' + id + '` with unspecified ' + field);\n badSourceOrTarget = true;\n } else if (!cy.hasElementWithId(val)) {\n // can't create edge if one of its nodes doesn't exist\n error('Can not create edge `' + id + '` with nonexistant ' + field + ' `' + val + '`');\n badSourceOrTarget = true;\n }\n }\n\n if (badSourceOrTarget) {\n removeFromElements();\n continue;\n } // can't create this\n\n\n var src = cy.getElementById(_data3.source);\n var tgt = cy.getElementById(_data3.target); // only one edge in node if loop\n\n if (src.same(tgt)) {\n src._private.edges.push(edge);\n } else {\n src._private.edges.push(edge);\n\n tgt._private.edges.push(edge);\n }\n\n edge._private.source = src;\n edge._private.target = tgt;\n } // if is edge\n // create mock ids / indexes maps for element so it can be used like collections\n\n\n _private.map = new Map$2();\n\n _private.map.set(id, {\n ele: _ele2,\n index: 0\n });\n\n _private.removed = false;\n\n if (addToPool) {\n cy.addToPool(_ele2);\n }\n } // for each element\n // do compound node sanity checks\n\n\n for (var _i4 = 0; _i4 < nodes.length; _i4++) {\n // each node\n var node = nodes[_i4];\n var _data4 = node._private.data;\n\n if (number$1(_data4.parent)) {\n // then automake string\n _data4.parent = '' + _data4.parent;\n }\n\n var parentId = _data4.parent;\n var specifiedParent = parentId != null;\n\n if (specifiedParent || node._private.parent) {\n var parent = node._private.parent ? cy.collection().merge(node._private.parent) : cy.getElementById(parentId);\n\n if (parent.empty()) {\n // non-existant parent; just remove it\n _data4.parent = undefined;\n } else if (parent[0].removed()) {\n warn('Node added with missing parent, reference to parent removed');\n _data4.parent = undefined;\n node._private.parent = null;\n } else {\n var selfAsParent = false;\n var ancestor = parent;\n\n while (!ancestor.empty()) {\n if (node.same(ancestor)) {\n // mark self as parent and remove from data\n selfAsParent = true;\n _data4.parent = undefined; // remove parent reference\n // exit or we loop forever\n\n break;\n }\n\n ancestor = ancestor.parent();\n }\n\n if (!selfAsParent) {\n // connect with children\n parent[0]._private.children.push(node);\n\n node._private.parent = parent[0]; // let the core know we have a compound graph\n\n cy_p.hasCompoundNodes = true;\n }\n } // else\n\n } // if specified parent\n\n } // for each node\n\n\n if (elements.length > 0) {\n var restored = elements.length === self.length ? self : new Collection(cy, elements);\n\n for (var _i5 = 0; _i5 < restored.length; _i5++) {\n var _ele3 = restored[_i5];\n\n if (_ele3.isNode()) {\n continue;\n } // adding an edge invalidates the traversal caches for the parallel edges\n\n\n _ele3.parallelEdges().clearTraversalCache(); // adding an edge invalidates the traversal cache for the connected nodes\n\n\n _ele3.source().clearTraversalCache();\n\n _ele3.target().clearTraversalCache();\n }\n\n var toUpdateStyle;\n\n if (cy_p.hasCompoundNodes) {\n toUpdateStyle = cy.collection().merge(restored).merge(restored.connectedNodes()).merge(restored.parent());\n } else {\n toUpdateStyle = restored;\n }\n\n toUpdateStyle.dirtyCompoundBoundsCache().dirtyBoundingBoxCache().updateStyle(notifyRenderer);\n\n if (notifyRenderer) {\n restored.emitAndNotify('add');\n } else if (addToPool) {\n restored.emit('add');\n }\n }\n\n return self; // chainability\n };\n\n elesfn$1.removed = function () {\n var ele = this[0];\n return ele && ele._private.removed;\n };\n\n elesfn$1.inside = function () {\n var ele = this[0];\n return ele && !ele._private.removed;\n };\n\n elesfn$1.remove = function () {\n var notifyRenderer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n var removeFromPool = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n var self = this;\n var elesToRemove = [];\n var elesToRemoveIds = {};\n var cy = self._private.cy; // add connected edges\n\n function addConnectedEdges(node) {\n var edges = node._private.edges;\n\n for (var i = 0; i < edges.length; i++) {\n add(edges[i]);\n }\n } // add descendant nodes\n\n\n function addChildren(node) {\n var children = node._private.children;\n\n for (var i = 0; i < children.length; i++) {\n add(children[i]);\n }\n }\n\n function add(ele) {\n var alreadyAdded = elesToRemoveIds[ele.id()];\n\n if (removeFromPool && ele.removed() || alreadyAdded) {\n return;\n } else {\n elesToRemoveIds[ele.id()] = true;\n }\n\n if (ele.isNode()) {\n elesToRemove.push(ele); // nodes are removed last\n\n addConnectedEdges(ele);\n addChildren(ele);\n } else {\n elesToRemove.unshift(ele); // edges are removed first\n }\n } // make the list of elements to remove\n // (may be removing more than specified due to connected edges etc)\n\n\n for (var i = 0, l = self.length; i < l; i++) {\n var ele = self[i];\n add(ele);\n }\n\n function removeEdgeRef(node, edge) {\n var connectedEdges = node._private.edges;\n removeFromArray(connectedEdges, edge); // removing an edges invalidates the traversal cache for its nodes\n\n node.clearTraversalCache();\n }\n\n function removeParallelRef(pllEdge) {\n // removing an edge invalidates the traversal caches for the parallel edges\n pllEdge.clearTraversalCache();\n }\n\n var alteredParents = [];\n alteredParents.ids = {};\n\n function removeChildRef(parent, ele) {\n ele = ele[0];\n parent = parent[0];\n var children = parent._private.children;\n var pid = parent.id();\n removeFromArray(children, ele); // remove parent => child ref\n\n ele._private.parent = null; // remove child => parent ref\n\n if (!alteredParents.ids[pid]) {\n alteredParents.ids[pid] = true;\n alteredParents.push(parent);\n }\n }\n\n self.dirtyCompoundBoundsCache();\n\n if (removeFromPool) {\n cy.removeFromPool(elesToRemove); // remove from core pool\n }\n\n for (var _i6 = 0; _i6 < elesToRemove.length; _i6++) {\n var _ele4 = elesToRemove[_i6];\n\n if (_ele4.isEdge()) {\n // remove references to this edge in its connected nodes\n var src = _ele4.source()[0];\n\n var tgt = _ele4.target()[0];\n\n removeEdgeRef(src, _ele4);\n removeEdgeRef(tgt, _ele4);\n\n var pllEdges = _ele4.parallelEdges();\n\n for (var j = 0; j < pllEdges.length; j++) {\n var pllEdge = pllEdges[j];\n removeParallelRef(pllEdge);\n\n if (pllEdge.isBundledBezier()) {\n pllEdge.dirtyBoundingBoxCache();\n }\n }\n } else {\n // remove reference to parent\n var parent = _ele4.parent();\n\n if (parent.length !== 0) {\n removeChildRef(parent, _ele4);\n }\n }\n\n if (removeFromPool) {\n // mark as removed\n _ele4._private.removed = true;\n }\n } // check to see if we have a compound graph or not\n\n\n var elesStillInside = cy._private.elements;\n cy._private.hasCompoundNodes = false;\n\n for (var _i7 = 0; _i7 < elesStillInside.length; _i7++) {\n var _ele5 = elesStillInside[_i7];\n\n if (_ele5.isParent()) {\n cy._private.hasCompoundNodes = true;\n break;\n }\n }\n\n var removedElements = new Collection(this.cy(), elesToRemove);\n\n if (removedElements.size() > 0) {\n // must manually notify since trigger won't do this automatically once removed\n if (notifyRenderer) {\n removedElements.emitAndNotify('remove');\n } else if (removeFromPool) {\n removedElements.emit('remove');\n }\n } // the parents who were modified by the removal need their style updated\n\n\n for (var _i8 = 0; _i8 < alteredParents.length; _i8++) {\n var _ele6 = alteredParents[_i8];\n\n if (!removeFromPool || !_ele6.removed()) {\n _ele6.updateStyle();\n }\n }\n\n return removedElements;\n };\n\n elesfn$1.move = function (struct) {\n var cy = this._private.cy;\n var eles = this; // just clean up refs, caches, etc. in the same way as when removing and then restoring\n // (our calls to remove/restore do not remove from the graph or make events)\n\n var notifyRenderer = false;\n var modifyPool = false;\n\n var toString = function toString(id) {\n return id == null ? id : '' + id;\n }; // id must be string\n\n\n if (struct.source !== undefined || struct.target !== undefined) {\n var srcId = toString(struct.source);\n var tgtId = toString(struct.target);\n var srcExists = srcId != null && cy.hasElementWithId(srcId);\n var tgtExists = tgtId != null && cy.hasElementWithId(tgtId);\n\n if (srcExists || tgtExists) {\n cy.batch(function () {\n // avoid duplicate style updates\n eles.remove(notifyRenderer, modifyPool); // clean up refs etc.\n\n eles.emitAndNotify('moveout');\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var _data5 = ele._private.data;\n\n if (ele.isEdge()) {\n if (srcExists) {\n _data5.source = srcId;\n }\n\n if (tgtExists) {\n _data5.target = tgtId;\n }\n }\n }\n\n eles.restore(notifyRenderer, modifyPool); // make new refs, style, etc.\n });\n eles.emitAndNotify('move');\n }\n } else if (struct.parent !== undefined) {\n // move node to new parent\n var parentId = toString(struct.parent);\n var parentExists = parentId === null || cy.hasElementWithId(parentId);\n\n if (parentExists) {\n var pidToAssign = parentId === null ? undefined : parentId;\n cy.batch(function () {\n // avoid duplicate style updates\n var updated = eles.remove(notifyRenderer, modifyPool); // clean up refs etc.\n\n updated.emitAndNotify('moveout');\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var _data6 = ele._private.data;\n\n if (ele.isNode()) {\n _data6.parent = pidToAssign;\n }\n }\n\n updated.restore(notifyRenderer, modifyPool); // make new refs, style, etc.\n });\n eles.emitAndNotify('move');\n }\n }\n\n return this;\n };\n\n [elesfn$j, elesfn$i, elesfn$h, elesfn$g, elesfn$f, data, elesfn$d, dimensions, elesfn$9, elesfn$8, elesfn$7, elesfn$6, elesfn$5, elesfn$4, elesfn$3, elesfn$2].forEach(function (props) {\n extend(elesfn$1, props);\n });\n\n var corefn$9 = {\n add: function add(opts) {\n var elements;\n var cy = this; // add the elements\n\n if (elementOrCollection(opts)) {\n var eles = opts;\n\n if (eles._private.cy === cy) {\n // same instance => just restore\n elements = eles.restore();\n } else {\n // otherwise, copy from json\n var jsons = [];\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n jsons.push(ele.json());\n }\n\n elements = new Collection(cy, jsons);\n }\n } // specify an array of options\n else if (array(opts)) {\n var _jsons = opts;\n elements = new Collection(cy, _jsons);\n } // specify via opts.nodes and opts.edges\n else if (plainObject(opts) && (array(opts.nodes) || array(opts.edges))) {\n var elesByGroup = opts;\n var _jsons2 = [];\n var grs = ['nodes', 'edges'];\n\n for (var _i = 0, il = grs.length; _i < il; _i++) {\n var group = grs[_i];\n var elesArray = elesByGroup[group];\n\n if (array(elesArray)) {\n for (var j = 0, jl = elesArray.length; j < jl; j++) {\n var json = extend({\n group: group\n }, elesArray[j]);\n\n _jsons2.push(json);\n }\n }\n }\n\n elements = new Collection(cy, _jsons2);\n } // specify options for one element\n else {\n var _json = opts;\n elements = new Element(cy, _json).collection();\n }\n\n return elements;\n },\n remove: function remove(collection) {\n if (elementOrCollection(collection)) ; else if (string(collection)) {\n var selector = collection;\n collection = this.$(selector);\n }\n\n return collection.remove();\n }\n };\n\n /* global Float32Array */\n\n /*! Bezier curve function generator. Copyright Gaetan Renaudeau. MIT License: http://en.wikipedia.org/wiki/MIT_License */\n function generateCubicBezier(mX1, mY1, mX2, mY2) {\n var NEWTON_ITERATIONS = 4,\n NEWTON_MIN_SLOPE = 0.001,\n SUBDIVISION_PRECISION = 0.0000001,\n SUBDIVISION_MAX_ITERATIONS = 10,\n kSplineTableSize = 11,\n kSampleStepSize = 1.0 / (kSplineTableSize - 1.0),\n float32ArraySupported = typeof Float32Array !== 'undefined';\n /* Must contain four arguments. */\n\n if (arguments.length !== 4) {\n return false;\n }\n /* Arguments must be numbers. */\n\n\n for (var i = 0; i < 4; ++i) {\n if (typeof arguments[i] !== \"number\" || isNaN(arguments[i]) || !isFinite(arguments[i])) {\n return false;\n }\n }\n /* X values must be in the [0, 1] range. */\n\n\n mX1 = Math.min(mX1, 1);\n mX2 = Math.min(mX2, 1);\n mX1 = Math.max(mX1, 0);\n mX2 = Math.max(mX2, 0);\n var mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);\n\n function A(aA1, aA2) {\n return 1.0 - 3.0 * aA2 + 3.0 * aA1;\n }\n\n function B(aA1, aA2) {\n return 3.0 * aA2 - 6.0 * aA1;\n }\n\n function C(aA1) {\n return 3.0 * aA1;\n }\n\n function calcBezier(aT, aA1, aA2) {\n return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;\n }\n\n function getSlope(aT, aA1, aA2) {\n return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);\n }\n\n function newtonRaphsonIterate(aX, aGuessT) {\n for (var _i = 0; _i < NEWTON_ITERATIONS; ++_i) {\n var currentSlope = getSlope(aGuessT, mX1, mX2);\n\n if (currentSlope === 0.0) {\n return aGuessT;\n }\n\n var currentX = calcBezier(aGuessT, mX1, mX2) - aX;\n aGuessT -= currentX / currentSlope;\n }\n\n return aGuessT;\n }\n\n function calcSampleValues() {\n for (var _i2 = 0; _i2 < kSplineTableSize; ++_i2) {\n mSampleValues[_i2] = calcBezier(_i2 * kSampleStepSize, mX1, mX2);\n }\n }\n\n function binarySubdivide(aX, aA, aB) {\n var currentX,\n currentT,\n i = 0;\n\n do {\n currentT = aA + (aB - aA) / 2.0;\n currentX = calcBezier(currentT, mX1, mX2) - aX;\n\n if (currentX > 0.0) {\n aB = currentT;\n } else {\n aA = currentT;\n }\n } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);\n\n return currentT;\n }\n\n function getTForX(aX) {\n var intervalStart = 0.0,\n currentSample = 1,\n lastSample = kSplineTableSize - 1;\n\n for (; currentSample !== lastSample && mSampleValues[currentSample] <= aX; ++currentSample) {\n intervalStart += kSampleStepSize;\n }\n\n --currentSample;\n var dist = (aX - mSampleValues[currentSample]) / (mSampleValues[currentSample + 1] - mSampleValues[currentSample]),\n guessForT = intervalStart + dist * kSampleStepSize,\n initialSlope = getSlope(guessForT, mX1, mX2);\n\n if (initialSlope >= NEWTON_MIN_SLOPE) {\n return newtonRaphsonIterate(aX, guessForT);\n } else if (initialSlope === 0.0) {\n return guessForT;\n } else {\n return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize);\n }\n }\n\n var _precomputed = false;\n\n function precompute() {\n _precomputed = true;\n\n if (mX1 !== mY1 || mX2 !== mY2) {\n calcSampleValues();\n }\n }\n\n var f = function f(aX) {\n if (!_precomputed) {\n precompute();\n }\n\n if (mX1 === mY1 && mX2 === mY2) {\n return aX;\n }\n\n if (aX === 0) {\n return 0;\n }\n\n if (aX === 1) {\n return 1;\n }\n\n return calcBezier(getTForX(aX), mY1, mY2);\n };\n\n f.getControlPoints = function () {\n return [{\n x: mX1,\n y: mY1\n }, {\n x: mX2,\n y: mY2\n }];\n };\n\n var str = \"generateBezier(\" + [mX1, mY1, mX2, mY2] + \")\";\n\n f.toString = function () {\n return str;\n };\n\n return f;\n }\n\n /*! Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License */\n\n /* Given a tension, friction, and duration, a simulation at 60FPS will first run without a defined duration in order to calculate the full path. A second pass\n then adjusts the time delta -- using the relation between actual time and duration -- to calculate the path for the duration-constrained animation. */\n var generateSpringRK4 = function () {\n function springAccelerationForState(state) {\n return -state.tension * state.x - state.friction * state.v;\n }\n\n function springEvaluateStateWithDerivative(initialState, dt, derivative) {\n var state = {\n x: initialState.x + derivative.dx * dt,\n v: initialState.v + derivative.dv * dt,\n tension: initialState.tension,\n friction: initialState.friction\n };\n return {\n dx: state.v,\n dv: springAccelerationForState(state)\n };\n }\n\n function springIntegrateState(state, dt) {\n var a = {\n dx: state.v,\n dv: springAccelerationForState(state)\n },\n b = springEvaluateStateWithDerivative(state, dt * 0.5, a),\n c = springEvaluateStateWithDerivative(state, dt * 0.5, b),\n d = springEvaluateStateWithDerivative(state, dt, c),\n dxdt = 1.0 / 6.0 * (a.dx + 2.0 * (b.dx + c.dx) + d.dx),\n dvdt = 1.0 / 6.0 * (a.dv + 2.0 * (b.dv + c.dv) + d.dv);\n state.x = state.x + dxdt * dt;\n state.v = state.v + dvdt * dt;\n return state;\n }\n\n return function springRK4Factory(tension, friction, duration) {\n var initState = {\n x: -1,\n v: 0,\n tension: null,\n friction: null\n },\n path = [0],\n time_lapsed = 0,\n tolerance = 1 / 10000,\n DT = 16 / 1000,\n have_duration,\n dt,\n last_state;\n tension = parseFloat(tension) || 500;\n friction = parseFloat(friction) || 20;\n duration = duration || null;\n initState.tension = tension;\n initState.friction = friction;\n have_duration = duration !== null;\n /* Calculate the actual time it takes for this animation to complete with the provided conditions. */\n\n if (have_duration) {\n /* Run the simulation without a duration. */\n time_lapsed = springRK4Factory(tension, friction);\n /* Compute the adjusted time delta. */\n\n dt = time_lapsed / duration * DT;\n } else {\n dt = DT;\n }\n\n for (;;) {\n /* Next/step function .*/\n last_state = springIntegrateState(last_state || initState, dt);\n /* Store the position. */\n\n path.push(1 + last_state.x);\n time_lapsed += 16;\n /* If the change threshold is reached, break. */\n\n if (!(Math.abs(last_state.x) > tolerance && Math.abs(last_state.v) > tolerance)) {\n break;\n }\n }\n /* If duration is not defined, return the actual time required for completing this animation. Otherwise, return a closure that holds the\n computed path and returns a snapshot of the position according to a given percentComplete. */\n\n\n return !have_duration ? time_lapsed : function (percentComplete) {\n return path[percentComplete * (path.length - 1) | 0];\n };\n };\n }();\n\n var cubicBezier = function cubicBezier(t1, p1, t2, p2) {\n var bezier = generateCubicBezier(t1, p1, t2, p2);\n return function (start, end, percent) {\n return start + (end - start) * bezier(percent);\n };\n };\n\n var easings = {\n 'linear': function linear(start, end, percent) {\n return start + (end - start) * percent;\n },\n // default easings\n 'ease': cubicBezier(0.25, 0.1, 0.25, 1),\n 'ease-in': cubicBezier(0.42, 0, 1, 1),\n 'ease-out': cubicBezier(0, 0, 0.58, 1),\n 'ease-in-out': cubicBezier(0.42, 0, 0.58, 1),\n // sine\n 'ease-in-sine': cubicBezier(0.47, 0, 0.745, 0.715),\n 'ease-out-sine': cubicBezier(0.39, 0.575, 0.565, 1),\n 'ease-in-out-sine': cubicBezier(0.445, 0.05, 0.55, 0.95),\n // quad\n 'ease-in-quad': cubicBezier(0.55, 0.085, 0.68, 0.53),\n 'ease-out-quad': cubicBezier(0.25, 0.46, 0.45, 0.94),\n 'ease-in-out-quad': cubicBezier(0.455, 0.03, 0.515, 0.955),\n // cubic\n 'ease-in-cubic': cubicBezier(0.55, 0.055, 0.675, 0.19),\n 'ease-out-cubic': cubicBezier(0.215, 0.61, 0.355, 1),\n 'ease-in-out-cubic': cubicBezier(0.645, 0.045, 0.355, 1),\n // quart\n 'ease-in-quart': cubicBezier(0.895, 0.03, 0.685, 0.22),\n 'ease-out-quart': cubicBezier(0.165, 0.84, 0.44, 1),\n 'ease-in-out-quart': cubicBezier(0.77, 0, 0.175, 1),\n // quint\n 'ease-in-quint': cubicBezier(0.755, 0.05, 0.855, 0.06),\n 'ease-out-quint': cubicBezier(0.23, 1, 0.32, 1),\n 'ease-in-out-quint': cubicBezier(0.86, 0, 0.07, 1),\n // expo\n 'ease-in-expo': cubicBezier(0.95, 0.05, 0.795, 0.035),\n 'ease-out-expo': cubicBezier(0.19, 1, 0.22, 1),\n 'ease-in-out-expo': cubicBezier(1, 0, 0, 1),\n // circ\n 'ease-in-circ': cubicBezier(0.6, 0.04, 0.98, 0.335),\n 'ease-out-circ': cubicBezier(0.075, 0.82, 0.165, 1),\n 'ease-in-out-circ': cubicBezier(0.785, 0.135, 0.15, 0.86),\n // user param easings...\n 'spring': function spring(tension, friction, duration) {\n if (duration === 0) {\n // can't get a spring w/ duration 0\n return easings.linear; // duration 0 => jump to end so impl doesn't matter\n }\n\n var spring = generateSpringRK4(tension, friction, duration);\n return function (start, end, percent) {\n return start + (end - start) * spring(percent);\n };\n },\n 'cubic-bezier': cubicBezier\n };\n\n function getEasedValue(type, start, end, percent, easingFn) {\n if (percent === 1) {\n return end;\n }\n\n if (start === end) {\n return end;\n }\n\n var val = easingFn(start, end, percent);\n\n if (type == null) {\n return val;\n }\n\n if (type.roundValue || type.color) {\n val = Math.round(val);\n }\n\n if (type.min !== undefined) {\n val = Math.max(val, type.min);\n }\n\n if (type.max !== undefined) {\n val = Math.min(val, type.max);\n }\n\n return val;\n }\n\n function getValue(prop, spec) {\n if (prop.pfValue != null || prop.value != null) {\n if (prop.pfValue != null && (spec == null || spec.type.units !== '%')) {\n return prop.pfValue;\n } else {\n return prop.value;\n }\n } else {\n return prop;\n }\n }\n\n function ease(startProp, endProp, percent, easingFn, propSpec) {\n var type = propSpec != null ? propSpec.type : null;\n\n if (percent < 0) {\n percent = 0;\n } else if (percent > 1) {\n percent = 1;\n }\n\n var start = getValue(startProp, propSpec);\n var end = getValue(endProp, propSpec);\n\n if (number$1(start) && number$1(end)) {\n return getEasedValue(type, start, end, percent, easingFn);\n } else if (array(start) && array(end)) {\n var easedArr = [];\n\n for (var i = 0; i < end.length; i++) {\n var si = start[i];\n var ei = end[i];\n\n if (si != null && ei != null) {\n var val = getEasedValue(type, si, ei, percent, easingFn);\n easedArr.push(val);\n } else {\n easedArr.push(ei);\n }\n }\n\n return easedArr;\n }\n\n return undefined;\n }\n\n function step$1(self, ani, now, isCore) {\n var isEles = !isCore;\n var _p = self._private;\n var ani_p = ani._private;\n var pEasing = ani_p.easing;\n var startTime = ani_p.startTime;\n var cy = isCore ? self : self.cy();\n var style = cy.style();\n\n if (!ani_p.easingImpl) {\n if (pEasing == null) {\n // use default\n ani_p.easingImpl = easings['linear'];\n } else {\n // then define w/ name\n var easingVals;\n\n if (string(pEasing)) {\n var easingProp = style.parse('transition-timing-function', pEasing);\n easingVals = easingProp.value;\n } else {\n // then assume preparsed array\n easingVals = pEasing;\n }\n\n var name, args;\n\n if (string(easingVals)) {\n name = easingVals;\n args = [];\n } else {\n name = easingVals[1];\n args = easingVals.slice(2).map(function (n) {\n return +n;\n });\n }\n\n if (args.length > 0) {\n // create with args\n if (name === 'spring') {\n args.push(ani_p.duration); // need duration to generate spring\n }\n\n ani_p.easingImpl = easings[name].apply(null, args);\n } else {\n // static impl by name\n ani_p.easingImpl = easings[name];\n }\n }\n }\n\n var easing = ani_p.easingImpl;\n var percent;\n\n if (ani_p.duration === 0) {\n percent = 1;\n } else {\n percent = (now - startTime) / ani_p.duration;\n }\n\n if (ani_p.applying) {\n percent = ani_p.progress;\n }\n\n if (percent < 0) {\n percent = 0;\n } else if (percent > 1) {\n percent = 1;\n }\n\n if (ani_p.delay == null) {\n // then update\n var startPos = ani_p.startPosition;\n var endPos = ani_p.position;\n\n if (endPos && isEles && !self.locked()) {\n var newPos = {};\n\n if (valid(startPos.x, endPos.x)) {\n newPos.x = ease(startPos.x, endPos.x, percent, easing);\n }\n\n if (valid(startPos.y, endPos.y)) {\n newPos.y = ease(startPos.y, endPos.y, percent, easing);\n }\n\n self.position(newPos);\n }\n\n var startPan = ani_p.startPan;\n var endPan = ani_p.pan;\n var pan = _p.pan;\n var animatingPan = endPan != null && isCore;\n\n if (animatingPan) {\n if (valid(startPan.x, endPan.x)) {\n pan.x = ease(startPan.x, endPan.x, percent, easing);\n }\n\n if (valid(startPan.y, endPan.y)) {\n pan.y = ease(startPan.y, endPan.y, percent, easing);\n }\n\n self.emit('pan');\n }\n\n var startZoom = ani_p.startZoom;\n var endZoom = ani_p.zoom;\n var animatingZoom = endZoom != null && isCore;\n\n if (animatingZoom) {\n if (valid(startZoom, endZoom)) {\n _p.zoom = bound(_p.minZoom, ease(startZoom, endZoom, percent, easing), _p.maxZoom);\n }\n\n self.emit('zoom');\n }\n\n if (animatingPan || animatingZoom) {\n self.emit('viewport');\n }\n\n var props = ani_p.style;\n\n if (props && props.length > 0 && isEles) {\n for (var i = 0; i < props.length; i++) {\n var prop = props[i];\n var _name = prop.name;\n var end = prop;\n var start = ani_p.startStyle[_name];\n var propSpec = style.properties[start.name];\n var easedVal = ease(start, end, percent, easing, propSpec);\n style.overrideBypass(self, _name, easedVal);\n } // for props\n\n\n self.emit('style');\n } // if\n\n }\n\n ani_p.progress = percent;\n return percent;\n }\n\n function valid(start, end) {\n if (start == null || end == null) {\n return false;\n }\n\n if (number$1(start) && number$1(end)) {\n return true;\n } else if (start && end) {\n return true;\n }\n\n return false;\n }\n\n function startAnimation(self, ani, now, isCore) {\n var ani_p = ani._private;\n ani_p.started = true;\n ani_p.startTime = now - ani_p.progress * ani_p.duration;\n }\n\n function stepAll(now, cy) {\n var eles = cy._private.aniEles;\n var doneEles = [];\n\n function stepOne(ele, isCore) {\n var _p = ele._private;\n var current = _p.animation.current;\n var queue = _p.animation.queue;\n var ranAnis = false; // if nothing currently animating, get something from the queue\n\n if (current.length === 0) {\n var next = queue.shift();\n\n if (next) {\n current.push(next);\n }\n }\n\n var callbacks = function callbacks(_callbacks) {\n for (var j = _callbacks.length - 1; j >= 0; j--) {\n var cb = _callbacks[j];\n cb();\n }\n\n _callbacks.splice(0, _callbacks.length);\n }; // step and remove if done\n\n\n for (var i = current.length - 1; i >= 0; i--) {\n var ani = current[i];\n var ani_p = ani._private;\n\n if (ani_p.stopped) {\n current.splice(i, 1);\n ani_p.hooked = false;\n ani_p.playing = false;\n ani_p.started = false;\n callbacks(ani_p.frames);\n continue;\n }\n\n if (!ani_p.playing && !ani_p.applying) {\n continue;\n } // an apply() while playing shouldn't do anything\n\n\n if (ani_p.playing && ani_p.applying) {\n ani_p.applying = false;\n }\n\n if (!ani_p.started) {\n startAnimation(ele, ani, now);\n }\n\n step$1(ele, ani, now, isCore);\n\n if (ani_p.applying) {\n ani_p.applying = false;\n }\n\n callbacks(ani_p.frames);\n\n if (ani_p.step != null) {\n ani_p.step(now);\n }\n\n if (ani.completed()) {\n current.splice(i, 1);\n ani_p.hooked = false;\n ani_p.playing = false;\n ani_p.started = false;\n callbacks(ani_p.completes);\n }\n\n ranAnis = true;\n }\n\n if (!isCore && current.length === 0 && queue.length === 0) {\n doneEles.push(ele);\n }\n\n return ranAnis;\n } // stepElement\n // handle all eles\n\n\n var ranEleAni = false;\n\n for (var e = 0; e < eles.length; e++) {\n var ele = eles[e];\n var handledThisEle = stepOne(ele);\n ranEleAni = ranEleAni || handledThisEle;\n } // each element\n\n\n var ranCoreAni = stepOne(cy, true); // notify renderer\n\n if (ranEleAni || ranCoreAni) {\n if (eles.length > 0) {\n cy.notify('draw', eles);\n } else {\n cy.notify('draw');\n }\n } // remove elements from list of currently animating if its queues are empty\n\n\n eles.unmerge(doneEles);\n cy.emit('step');\n } // stepAll\n\n var corefn$8 = {\n // pull in animation functions\n animate: define.animate(),\n animation: define.animation(),\n animated: define.animated(),\n clearQueue: define.clearQueue(),\n delay: define.delay(),\n delayAnimation: define.delayAnimation(),\n stop: define.stop(),\n addToAnimationPool: function addToAnimationPool(eles) {\n var cy = this;\n\n if (!cy.styleEnabled()) {\n return;\n } // save cycles when no style used\n\n\n cy._private.aniEles.merge(eles);\n },\n stopAnimationLoop: function stopAnimationLoop() {\n this._private.animationsRunning = false;\n },\n startAnimationLoop: function startAnimationLoop() {\n var cy = this;\n cy._private.animationsRunning = true;\n\n if (!cy.styleEnabled()) {\n return;\n } // save cycles when no style used\n // NB the animation loop will exec in headless environments if style enabled\n // and explicit cy.destroy() is necessary to stop the loop\n\n\n function headlessStep() {\n if (!cy._private.animationsRunning) {\n return;\n }\n\n requestAnimationFrame(function animationStep(now) {\n stepAll(now, cy);\n headlessStep();\n });\n }\n\n var renderer = cy.renderer();\n\n if (renderer && renderer.beforeRender) {\n // let the renderer schedule animations\n renderer.beforeRender(function rendererAnimationStep(willDraw, now) {\n stepAll(now, cy);\n }, renderer.beforeRenderPriorities.animations);\n } else {\n // manage the animation loop ourselves\n headlessStep(); // first call\n }\n }\n };\n\n var emitterOptions = {\n qualifierCompare: function qualifierCompare(selector1, selector2) {\n if (selector1 == null || selector2 == null) {\n return selector1 == null && selector2 == null;\n } else {\n return selector1.sameText(selector2);\n }\n },\n eventMatches: function eventMatches(cy, listener, eventObj) {\n var selector = listener.qualifier;\n\n if (selector != null) {\n return cy !== eventObj.target && element(eventObj.target) && selector.matches(eventObj.target);\n }\n\n return true;\n },\n addEventFields: function addEventFields(cy, evt) {\n evt.cy = cy;\n evt.target = cy;\n },\n callbackContext: function callbackContext(cy, listener, eventObj) {\n return listener.qualifier != null ? eventObj.target : cy;\n }\n };\n\n var argSelector = function argSelector(arg) {\n if (string(arg)) {\n return new Selector(arg);\n } else {\n return arg;\n }\n };\n\n var elesfn = {\n createEmitter: function createEmitter() {\n var _p = this._private;\n\n if (!_p.emitter) {\n _p.emitter = new Emitter(emitterOptions, this);\n }\n\n return this;\n },\n emitter: function emitter() {\n return this._private.emitter;\n },\n on: function on(events, selector, callback) {\n this.emitter().on(events, argSelector(selector), callback);\n return this;\n },\n removeListener: function removeListener(events, selector, callback) {\n this.emitter().removeListener(events, argSelector(selector), callback);\n return this;\n },\n removeAllListeners: function removeAllListeners() {\n this.emitter().removeAllListeners();\n return this;\n },\n one: function one(events, selector, callback) {\n this.emitter().one(events, argSelector(selector), callback);\n return this;\n },\n once: function once(events, selector, callback) {\n this.emitter().one(events, argSelector(selector), callback);\n return this;\n },\n emit: function emit(events, extraParams) {\n this.emitter().emit(events, extraParams);\n return this;\n },\n emitAndNotify: function emitAndNotify(event, eles) {\n this.emit(event);\n this.notify(event, eles);\n return this;\n }\n };\n define.eventAliasesOn(elesfn);\n\n var corefn$7 = {\n png: function png(options) {\n var renderer = this._private.renderer;\n options = options || {};\n return renderer.png(options);\n },\n jpg: function jpg(options) {\n var renderer = this._private.renderer;\n options = options || {};\n options.bg = options.bg || '#fff';\n return renderer.jpg(options);\n }\n };\n corefn$7.jpeg = corefn$7.jpg;\n\n var corefn$6 = {\n layout: function layout(options) {\n var cy = this;\n\n if (options == null) {\n error('Layout options must be specified to make a layout');\n return;\n }\n\n if (options.name == null) {\n error('A `name` must be specified to make a layout');\n return;\n }\n\n var name = options.name;\n var Layout = cy.extension('layout', name);\n\n if (Layout == null) {\n error('No such layout `' + name + '` found. Did you forget to import it and `cytoscape.use()` it?');\n return;\n }\n\n var eles;\n\n if (string(options.eles)) {\n eles = cy.$(options.eles);\n } else {\n eles = options.eles != null ? options.eles : cy.$();\n }\n\n var layout = new Layout(extend({}, options, {\n cy: cy,\n eles: eles\n }));\n return layout;\n }\n };\n corefn$6.createLayout = corefn$6.makeLayout = corefn$6.layout;\n\n var corefn$5 = {\n notify: function notify(eventName, eventEles) {\n var _p = this._private;\n\n if (this.batching()) {\n _p.batchNotifications = _p.batchNotifications || {};\n var eles = _p.batchNotifications[eventName] = _p.batchNotifications[eventName] || this.collection();\n\n if (eventEles != null) {\n eles.merge(eventEles);\n }\n\n return; // notifications are disabled during batching\n }\n\n if (!_p.notificationsEnabled) {\n return;\n } // exit on disabled\n\n\n var renderer = this.renderer(); // exit if destroy() called on core or renderer in between frames #1499 #1528\n\n if (this.destroyed() || !renderer) {\n return;\n }\n\n renderer.notify(eventName, eventEles);\n },\n notifications: function notifications(bool) {\n var p = this._private;\n\n if (bool === undefined) {\n return p.notificationsEnabled;\n } else {\n p.notificationsEnabled = bool ? true : false;\n }\n\n return this;\n },\n noNotifications: function noNotifications(callback) {\n this.notifications(false);\n callback();\n this.notifications(true);\n },\n batching: function batching() {\n return this._private.batchCount > 0;\n },\n startBatch: function startBatch() {\n var _p = this._private;\n\n if (_p.batchCount == null) {\n _p.batchCount = 0;\n }\n\n if (_p.batchCount === 0) {\n _p.batchStyleEles = this.collection();\n _p.batchNotifications = {};\n }\n\n _p.batchCount++;\n return this;\n },\n endBatch: function endBatch() {\n var _p = this._private;\n\n if (_p.batchCount === 0) {\n return this;\n }\n\n _p.batchCount--;\n\n if (_p.batchCount === 0) {\n // update style for dirty eles\n _p.batchStyleEles.updateStyle();\n\n var renderer = this.renderer(); // notify the renderer of queued eles and event types\n\n Object.keys(_p.batchNotifications).forEach(function (eventName) {\n var eles = _p.batchNotifications[eventName];\n\n if (eles.empty()) {\n renderer.notify(eventName);\n } else {\n renderer.notify(eventName, eles);\n }\n });\n }\n\n return this;\n },\n batch: function batch(callback) {\n this.startBatch();\n callback();\n this.endBatch();\n return this;\n },\n // for backwards compatibility\n batchData: function batchData(map) {\n var cy = this;\n return this.batch(function () {\n var ids = Object.keys(map);\n\n for (var i = 0; i < ids.length; i++) {\n var id = ids[i];\n var data = map[id];\n var ele = cy.getElementById(id);\n ele.data(data);\n }\n });\n }\n };\n\n var rendererDefaults = defaults$g({\n hideEdgesOnViewport: false,\n textureOnViewport: false,\n motionBlur: false,\n motionBlurOpacity: 0.05,\n pixelRatio: undefined,\n desktopTapThreshold: 4,\n touchTapThreshold: 8,\n wheelSensitivity: 1,\n debug: false,\n showFps: false\n });\n var corefn$4 = {\n renderTo: function renderTo(context, zoom, pan, pxRatio) {\n var r = this._private.renderer;\n r.renderTo(context, zoom, pan, pxRatio);\n return this;\n },\n renderer: function renderer() {\n return this._private.renderer;\n },\n forceRender: function forceRender() {\n this.notify('draw');\n return this;\n },\n resize: function resize() {\n this.invalidateSize();\n this.emitAndNotify('resize');\n return this;\n },\n initRenderer: function initRenderer(options) {\n var cy = this;\n var RendererProto = cy.extension('renderer', options.name);\n\n if (RendererProto == null) {\n error(\"Can not initialise: No such renderer `\".concat(options.name, \"` found. Did you forget to import it and `cytoscape.use()` it?\"));\n return;\n }\n\n if (options.wheelSensitivity !== undefined) {\n warn(\"You have set a custom wheel sensitivity. This will make your app zoom unnaturally when using mainstream mice. You should change this value from the default only if you can guarantee that all your users will use the same hardware and OS configuration as your current machine.\");\n }\n\n var rOpts = rendererDefaults(options);\n rOpts.cy = cy;\n cy._private.renderer = new RendererProto(rOpts);\n this.notify('init');\n },\n destroyRenderer: function destroyRenderer() {\n var cy = this;\n cy.notify('destroy'); // destroy the renderer\n\n var domEle = cy.container();\n\n if (domEle) {\n domEle._cyreg = null;\n\n while (domEle.childNodes.length > 0) {\n domEle.removeChild(domEle.childNodes[0]);\n }\n }\n\n cy._private.renderer = null; // to be extra safe, remove the ref\n\n cy.mutableElements().forEach(function (ele) {\n var _p = ele._private;\n _p.rscratch = {};\n _p.rstyle = {};\n _p.animation.current = [];\n _p.animation.queue = [];\n });\n },\n onRender: function onRender(fn) {\n return this.on('render', fn);\n },\n offRender: function offRender(fn) {\n return this.off('render', fn);\n }\n };\n corefn$4.invalidateDimensions = corefn$4.resize;\n\n var corefn$3 = {\n // get a collection\n // - empty collection on no args\n // - collection of elements in the graph on selector arg\n // - guarantee a returned collection when elements or collection specified\n collection: function collection(eles, opts) {\n if (string(eles)) {\n return this.$(eles);\n } else if (elementOrCollection(eles)) {\n return eles.collection();\n } else if (array(eles)) {\n if (!opts) {\n opts = {};\n }\n\n return new Collection(this, eles, opts.unique, opts.removed);\n }\n\n return new Collection(this);\n },\n nodes: function nodes(selector) {\n var nodes = this.$(function (ele) {\n return ele.isNode();\n });\n\n if (selector) {\n return nodes.filter(selector);\n }\n\n return nodes;\n },\n edges: function edges(selector) {\n var edges = this.$(function (ele) {\n return ele.isEdge();\n });\n\n if (selector) {\n return edges.filter(selector);\n }\n\n return edges;\n },\n // search the graph like jQuery\n $: function $(selector) {\n var eles = this._private.elements;\n\n if (selector) {\n return eles.filter(selector);\n } else {\n return eles.spawnSelf();\n }\n },\n mutableElements: function mutableElements() {\n return this._private.elements;\n }\n }; // aliases\n\n corefn$3.elements = corefn$3.filter = corefn$3.$;\n\n var styfn$8 = {}; // keys for style blocks, e.g. ttfftt\n\n var TRUE = 't';\n var FALSE = 'f'; // (potentially expensive calculation)\n // apply the style to the element based on\n // - its bypass\n // - what selectors match it\n\n styfn$8.apply = function (eles) {\n var self = this;\n var _p = self._private;\n var cy = _p.cy;\n var updatedEles = cy.collection();\n\n for (var ie = 0; ie < eles.length; ie++) {\n var ele = eles[ie];\n var cxtMeta = self.getContextMeta(ele);\n\n if (cxtMeta.empty) {\n continue;\n }\n\n var cxtStyle = self.getContextStyle(cxtMeta);\n var app = self.applyContextStyle(cxtMeta, cxtStyle, ele);\n\n if (ele._private.appliedInitStyle) {\n self.updateTransitions(ele, app.diffProps);\n } else {\n ele._private.appliedInitStyle = true;\n }\n\n var hintsDiff = self.updateStyleHints(ele);\n\n if (hintsDiff) {\n updatedEles.push(ele);\n }\n } // for elements\n\n\n return updatedEles;\n };\n\n styfn$8.getPropertiesDiff = function (oldCxtKey, newCxtKey) {\n var self = this;\n var cache = self._private.propDiffs = self._private.propDiffs || {};\n var dualCxtKey = oldCxtKey + '-' + newCxtKey;\n var cachedVal = cache[dualCxtKey];\n\n if (cachedVal) {\n return cachedVal;\n }\n\n var diffProps = [];\n var addedProp = {};\n\n for (var i = 0; i < self.length; i++) {\n var cxt = self[i];\n var oldHasCxt = oldCxtKey[i] === TRUE;\n var newHasCxt = newCxtKey[i] === TRUE;\n var cxtHasDiffed = oldHasCxt !== newHasCxt;\n var cxtHasMappedProps = cxt.mappedProperties.length > 0;\n\n if (cxtHasDiffed || newHasCxt && cxtHasMappedProps) {\n var props = void 0;\n\n if (cxtHasDiffed && cxtHasMappedProps) {\n props = cxt.properties; // suffices b/c mappedProperties is a subset of properties\n } else if (cxtHasDiffed) {\n props = cxt.properties; // need to check them all\n } else if (cxtHasMappedProps) {\n props = cxt.mappedProperties; // only need to check mapped\n }\n\n for (var j = 0; j < props.length; j++) {\n var prop = props[j];\n var name = prop.name; // if a later context overrides this property, then the fact that this context has switched/diffed doesn't matter\n // (semi expensive check since it makes this function O(n^2) on context length, but worth it since overall result\n // is cached)\n\n var laterCxtOverrides = false;\n\n for (var k = i + 1; k < self.length; k++) {\n var laterCxt = self[k];\n var hasLaterCxt = newCxtKey[k] === TRUE;\n\n if (!hasLaterCxt) {\n continue;\n } // can't override unless the context is active\n\n\n laterCxtOverrides = laterCxt.properties[prop.name] != null;\n\n if (laterCxtOverrides) {\n break;\n } // exit early as long as one later context overrides\n\n }\n\n if (!addedProp[name] && !laterCxtOverrides) {\n addedProp[name] = true;\n diffProps.push(name);\n }\n } // for props\n\n } // if\n\n } // for contexts\n\n\n cache[dualCxtKey] = diffProps;\n return diffProps;\n };\n\n styfn$8.getContextMeta = function (ele) {\n var self = this;\n var cxtKey = '';\n var diffProps;\n var prevKey = ele._private.styleCxtKey || ''; // get the cxt key\n\n for (var i = 0; i < self.length; i++) {\n var context = self[i];\n var contextSelectorMatches = context.selector && context.selector.matches(ele); // NB: context.selector may be null for 'core'\n\n if (contextSelectorMatches) {\n cxtKey += TRUE;\n } else {\n cxtKey += FALSE;\n }\n } // for context\n\n\n diffProps = self.getPropertiesDiff(prevKey, cxtKey);\n ele._private.styleCxtKey = cxtKey;\n return {\n key: cxtKey,\n diffPropNames: diffProps,\n empty: diffProps.length === 0\n };\n }; // gets a computed ele style object based on matched contexts\n\n\n styfn$8.getContextStyle = function (cxtMeta) {\n var cxtKey = cxtMeta.key;\n var self = this;\n var cxtStyles = this._private.contextStyles = this._private.contextStyles || {}; // if already computed style, returned cached copy\n\n if (cxtStyles[cxtKey]) {\n return cxtStyles[cxtKey];\n }\n\n var style = {\n _private: {\n key: cxtKey\n }\n };\n\n for (var i = 0; i < self.length; i++) {\n var cxt = self[i];\n var hasCxt = cxtKey[i] === TRUE;\n\n if (!hasCxt) {\n continue;\n }\n\n for (var j = 0; j < cxt.properties.length; j++) {\n var prop = cxt.properties[j];\n style[prop.name] = prop;\n }\n }\n\n cxtStyles[cxtKey] = style;\n return style;\n };\n\n styfn$8.applyContextStyle = function (cxtMeta, cxtStyle, ele) {\n var self = this;\n var diffProps = cxtMeta.diffPropNames;\n var retDiffProps = {};\n var types = self.types;\n\n for (var i = 0; i < diffProps.length; i++) {\n var diffPropName = diffProps[i];\n var cxtProp = cxtStyle[diffPropName];\n var eleProp = ele.pstyle(diffPropName);\n\n if (!cxtProp) {\n // no context prop means delete\n if (!eleProp) {\n continue; // no existing prop means nothing needs to be removed\n // nb affects initial application on mapped values like control-point-distances\n } else if (eleProp.bypass) {\n cxtProp = {\n name: diffPropName,\n deleteBypassed: true\n };\n } else {\n cxtProp = {\n name: diffPropName,\n \"delete\": true\n };\n }\n } // save cycles when the context prop doesn't need to be applied\n\n\n if (eleProp === cxtProp) {\n continue;\n } // save cycles when a mapped context prop doesn't need to be applied\n\n\n if (cxtProp.mapped === types.fn // context prop is function mapper\n && eleProp != null // some props can be null even by default (e.g. a prop that overrides another one)\n && eleProp.mapping != null // ele prop is a concrete value from from a mapper\n && eleProp.mapping.value === cxtProp.value // the current prop on the ele is a flat prop value for the function mapper\n ) {\n // NB don't write to cxtProp, as it's shared among eles (stored in stylesheet)\n var mapping = eleProp.mapping; // can write to mapping, as it's a per-ele copy\n\n var fnValue = mapping.fnValue = cxtProp.value(ele); // temporarily cache the value in case of a miss\n\n if (fnValue === mapping.prevFnValue) {\n continue;\n }\n }\n\n var retDiffProp = retDiffProps[diffPropName] = {\n prev: eleProp\n };\n self.applyParsedProperty(ele, cxtProp);\n retDiffProp.next = ele.pstyle(diffPropName);\n\n if (retDiffProp.next && retDiffProp.next.bypass) {\n retDiffProp.next = retDiffProp.next.bypassed;\n }\n }\n\n return {\n diffProps: retDiffProps\n };\n };\n\n styfn$8.updateStyleHints = function (ele) {\n var _p = ele._private;\n var self = this;\n var propNames = self.propertyGroupNames;\n var propGrKeys = self.propertyGroupKeys;\n\n var propHash = function propHash(ele, propNames, seedKey) {\n return self.getPropertiesHash(ele, propNames, seedKey);\n };\n\n var oldStyleKey = _p.styleKey;\n\n if (ele.removed()) {\n return false;\n }\n\n var isNode = _p.group === 'nodes'; // get the style key hashes per prop group\n // but lazily -- only use non-default prop values to reduce the number of hashes\n //\n\n var overriddenStyles = ele._private.style;\n propNames = Object.keys(overriddenStyles);\n\n for (var i = 0; i < propGrKeys.length; i++) {\n var grKey = propGrKeys[i];\n _p.styleKeys[grKey] = [DEFAULT_HASH_SEED, DEFAULT_HASH_SEED_ALT];\n }\n\n var updateGrKey1 = function updateGrKey1(val, grKey) {\n return _p.styleKeys[grKey][0] = hashInt(val, _p.styleKeys[grKey][0]);\n };\n\n var updateGrKey2 = function updateGrKey2(val, grKey) {\n return _p.styleKeys[grKey][1] = hashIntAlt(val, _p.styleKeys[grKey][1]);\n };\n\n var updateGrKey = function updateGrKey(val, grKey) {\n updateGrKey1(val, grKey);\n updateGrKey2(val, grKey);\n };\n\n var updateGrKeyWStr = function updateGrKeyWStr(strVal, grKey) {\n for (var j = 0; j < strVal.length; j++) {\n var ch = strVal.charCodeAt(j);\n updateGrKey1(ch, grKey);\n updateGrKey2(ch, grKey);\n }\n }; // - hashing works on 32 bit ints b/c we use bitwise ops\n // - small numbers get cut off (e.g. 0.123 is seen as 0 by the hashing function)\n // - raise up small numbers so more significant digits are seen by hashing\n // - make small numbers larger than a normal value to avoid collisions\n // - works in practice and it's relatively cheap\n\n\n var N = 2000000000;\n\n var cleanNum = function cleanNum(val) {\n return -128 < val && val < 128 && Math.floor(val) !== val ? N - (val * 1024 | 0) : val;\n };\n\n for (var _i = 0; _i < propNames.length; _i++) {\n var name = propNames[_i];\n var parsedProp = overriddenStyles[name];\n\n if (parsedProp == null) {\n continue;\n }\n\n var propInfo = this.properties[name];\n var type = propInfo.type;\n var _grKey = propInfo.groupKey;\n var normalizedNumberVal = void 0;\n\n if (propInfo.hashOverride != null) {\n normalizedNumberVal = propInfo.hashOverride(ele, parsedProp);\n } else if (parsedProp.pfValue != null) {\n normalizedNumberVal = parsedProp.pfValue;\n } // might not be a number if it allows enums\n\n\n var numberVal = propInfo.enums == null ? parsedProp.value : null;\n var haveNormNum = normalizedNumberVal != null;\n var haveUnitedNum = numberVal != null;\n var haveNum = haveNormNum || haveUnitedNum;\n var units = parsedProp.units; // numbers are cheaper to hash than strings\n // 1 hash op vs n hash ops (for length n string)\n\n if (type.number && haveNum && !type.multiple) {\n var v = haveNormNum ? normalizedNumberVal : numberVal;\n updateGrKey(cleanNum(v), _grKey);\n\n if (!haveNormNum && units != null) {\n updateGrKeyWStr(units, _grKey);\n }\n } else {\n updateGrKeyWStr(parsedProp.strValue, _grKey);\n }\n } // overall style key\n //\n\n\n var hash = [DEFAULT_HASH_SEED, DEFAULT_HASH_SEED_ALT];\n\n for (var _i2 = 0; _i2 < propGrKeys.length; _i2++) {\n var _grKey2 = propGrKeys[_i2];\n var grHash = _p.styleKeys[_grKey2];\n hash[0] = hashInt(grHash[0], hash[0]);\n hash[1] = hashIntAlt(grHash[1], hash[1]);\n }\n\n _p.styleKey = combineHashes(hash[0], hash[1]); // label dims\n //\n\n var sk = _p.styleKeys;\n _p.labelDimsKey = combineHashesArray(sk.labelDimensions);\n var labelKeys = propHash(ele, ['label'], sk.labelDimensions);\n _p.labelKey = combineHashesArray(labelKeys);\n _p.labelStyleKey = combineHashesArray(hashArrays(sk.commonLabel, labelKeys));\n\n if (!isNode) {\n var sourceLabelKeys = propHash(ele, ['source-label'], sk.labelDimensions);\n _p.sourceLabelKey = combineHashesArray(sourceLabelKeys);\n _p.sourceLabelStyleKey = combineHashesArray(hashArrays(sk.commonLabel, sourceLabelKeys));\n var targetLabelKeys = propHash(ele, ['target-label'], sk.labelDimensions);\n _p.targetLabelKey = combineHashesArray(targetLabelKeys);\n _p.targetLabelStyleKey = combineHashesArray(hashArrays(sk.commonLabel, targetLabelKeys));\n } // node\n //\n\n\n if (isNode) {\n var _p$styleKeys = _p.styleKeys,\n nodeBody = _p$styleKeys.nodeBody,\n nodeBorder = _p$styleKeys.nodeBorder,\n backgroundImage = _p$styleKeys.backgroundImage,\n compound = _p$styleKeys.compound,\n pie = _p$styleKeys.pie;\n var nodeKeys = [nodeBody, nodeBorder, backgroundImage, compound, pie].filter(function (k) {\n return k != null;\n }).reduce(hashArrays, [DEFAULT_HASH_SEED, DEFAULT_HASH_SEED_ALT]);\n _p.nodeKey = combineHashesArray(nodeKeys);\n _p.hasPie = pie != null && pie[0] !== DEFAULT_HASH_SEED && pie[1] !== DEFAULT_HASH_SEED_ALT;\n }\n\n return oldStyleKey !== _p.styleKey;\n };\n\n styfn$8.clearStyleHints = function (ele) {\n var _p = ele._private;\n _p.styleCxtKey = '';\n _p.styleKeys = {};\n _p.styleKey = null;\n _p.labelKey = null;\n _p.labelStyleKey = null;\n _p.sourceLabelKey = null;\n _p.sourceLabelStyleKey = null;\n _p.targetLabelKey = null;\n _p.targetLabelStyleKey = null;\n _p.nodeKey = null;\n _p.hasPie = null;\n }; // apply a property to the style (for internal use)\n // returns whether application was successful\n //\n // now, this function flattens the property, and here's how:\n //\n // for parsedProp:{ bypass: true, deleteBypass: true }\n // no property is generated, instead the bypass property in the\n // element's style is replaced by what's pointed to by the `bypassed`\n // field in the bypass property (i.e. restoring the property the\n // bypass was overriding)\n //\n // for parsedProp:{ mapped: truthy }\n // the generated flattenedProp:{ mapping: prop }\n //\n // for parsedProp:{ bypass: true }\n // the generated flattenedProp:{ bypassed: parsedProp }\n\n\n styfn$8.applyParsedProperty = function (ele, parsedProp) {\n var self = this;\n var prop = parsedProp;\n var style = ele._private.style;\n var flatProp;\n var types = self.types;\n var type = self.properties[prop.name].type;\n var propIsBypass = prop.bypass;\n var origProp = style[prop.name];\n var origPropIsBypass = origProp && origProp.bypass;\n var _p = ele._private;\n var flatPropMapping = 'mapping';\n\n var getVal = function getVal(p) {\n if (p == null) {\n return null;\n } else if (p.pfValue != null) {\n return p.pfValue;\n } else {\n return p.value;\n }\n };\n\n var checkTriggers = function checkTriggers() {\n var fromVal = getVal(origProp);\n var toVal = getVal(prop);\n self.checkTriggers(ele, prop.name, fromVal, toVal);\n };\n\n if (prop && prop.name.substr(0, 3) === 'pie') {\n warn('The pie style properties are deprecated. Create charts using background images instead.');\n } // edge sanity checks to prevent the client from making serious mistakes\n\n\n if (parsedProp.name === 'curve-style' && ele.isEdge() && ( // loops must be bundled beziers\n parsedProp.value !== 'bezier' && ele.isLoop() || // edges connected to compound nodes can not be haystacks\n parsedProp.value === 'haystack' && (ele.source().isParent() || ele.target().isParent()))) {\n prop = parsedProp = this.parse(parsedProp.name, 'bezier', propIsBypass);\n }\n\n if (prop[\"delete\"]) {\n // delete the property and use the default value on falsey value\n style[prop.name] = undefined;\n checkTriggers();\n return true;\n }\n\n if (prop.deleteBypassed) {\n // delete the property that the\n if (!origProp) {\n checkTriggers();\n return true; // can't delete if no prop\n } else if (origProp.bypass) {\n // delete bypassed\n origProp.bypassed = undefined;\n checkTriggers();\n return true;\n } else {\n return false; // we're unsuccessful deleting the bypassed\n }\n } // check if we need to delete the current bypass\n\n\n if (prop.deleteBypass) {\n // then this property is just here to indicate we need to delete\n if (!origProp) {\n checkTriggers();\n return true; // property is already not defined\n } else if (origProp.bypass) {\n // then replace the bypass property with the original\n // because the bypassed property was already applied (and therefore parsed), we can just replace it (no reapplying necessary)\n style[prop.name] = origProp.bypassed;\n checkTriggers();\n return true;\n } else {\n return false; // we're unsuccessful deleting the bypass\n }\n }\n\n var printMappingErr = function printMappingErr() {\n warn('Do not assign mappings to elements without corresponding data (i.e. ele `' + ele.id() + '` has no mapping for property `' + prop.name + '` with data field `' + prop.field + '`); try a `[' + prop.field + ']` selector to limit scope to elements with `' + prop.field + '` defined');\n }; // put the property in the style objects\n\n\n switch (prop.mapped) {\n // flatten the property if mapped\n case types.mapData:\n {\n // flatten the field (e.g. data.foo.bar)\n var fields = prop.field.split('.');\n var fieldVal = _p.data;\n\n for (var i = 0; i < fields.length && fieldVal; i++) {\n var field = fields[i];\n fieldVal = fieldVal[field];\n }\n\n if (fieldVal == null) {\n printMappingErr();\n return false;\n }\n\n var percent;\n\n if (!number$1(fieldVal)) {\n // then don't apply and fall back on the existing style\n warn('Do not use continuous mappers without specifying numeric data (i.e. `' + prop.field + ': ' + fieldVal + '` for `' + ele.id() + '` is non-numeric)');\n return false;\n } else {\n var fieldWidth = prop.fieldMax - prop.fieldMin;\n\n if (fieldWidth === 0) {\n // safety check -- not strictly necessary as no props of zero range should be passed here\n percent = 0;\n } else {\n percent = (fieldVal - prop.fieldMin) / fieldWidth;\n }\n } // make sure to bound percent value\n\n\n if (percent < 0) {\n percent = 0;\n } else if (percent > 1) {\n percent = 1;\n }\n\n if (type.color) {\n var r1 = prop.valueMin[0];\n var r2 = prop.valueMax[0];\n var g1 = prop.valueMin[1];\n var g2 = prop.valueMax[1];\n var b1 = prop.valueMin[2];\n var b2 = prop.valueMax[2];\n var a1 = prop.valueMin[3] == null ? 1 : prop.valueMin[3];\n var a2 = prop.valueMax[3] == null ? 1 : prop.valueMax[3];\n var clr = [Math.round(r1 + (r2 - r1) * percent), Math.round(g1 + (g2 - g1) * percent), Math.round(b1 + (b2 - b1) * percent), Math.round(a1 + (a2 - a1) * percent)];\n flatProp = {\n // colours are simple, so just create the flat property instead of expensive string parsing\n bypass: prop.bypass,\n // we're a bypass if the mapping property is a bypass\n name: prop.name,\n value: clr,\n strValue: 'rgb(' + clr[0] + ', ' + clr[1] + ', ' + clr[2] + ')'\n };\n } else if (type.number) {\n var calcValue = prop.valueMin + (prop.valueMax - prop.valueMin) * percent;\n flatProp = this.parse(prop.name, calcValue, prop.bypass, flatPropMapping);\n } else {\n return false; // can only map to colours and numbers\n }\n\n if (!flatProp) {\n // if we can't flatten the property, then don't apply the property and fall back on the existing style\n printMappingErr();\n return false;\n }\n\n flatProp.mapping = prop; // keep a reference to the mapping\n\n prop = flatProp; // the flattened (mapped) property is the one we want\n\n break;\n }\n // direct mapping\n\n case types.data:\n {\n // flatten the field (e.g. data.foo.bar)\n var _fields = prop.field.split('.');\n\n var _fieldVal = _p.data;\n\n for (var _i3 = 0; _i3 < _fields.length && _fieldVal; _i3++) {\n var _field = _fields[_i3];\n _fieldVal = _fieldVal[_field];\n }\n\n if (_fieldVal != null) {\n flatProp = this.parse(prop.name, _fieldVal, prop.bypass, flatPropMapping);\n }\n\n if (!flatProp) {\n // if we can't flatten the property, then don't apply and fall back on the existing style\n printMappingErr();\n return false;\n }\n\n flatProp.mapping = prop; // keep a reference to the mapping\n\n prop = flatProp; // the flattened (mapped) property is the one we want\n\n break;\n }\n\n case types.fn:\n {\n var fn = prop.value;\n var fnRetVal = prop.fnValue != null ? prop.fnValue : fn(ele); // check for cached value before calling function\n\n prop.prevFnValue = fnRetVal;\n\n if (fnRetVal == null) {\n warn('Custom function mappers may not return null (i.e. `' + prop.name + '` for ele `' + ele.id() + '` is null)');\n return false;\n }\n\n flatProp = this.parse(prop.name, fnRetVal, prop.bypass, flatPropMapping);\n\n if (!flatProp) {\n warn('Custom function mappers may not return invalid values for the property type (i.e. `' + prop.name + '` for ele `' + ele.id() + '` is invalid)');\n return false;\n }\n\n flatProp.mapping = copy(prop); // keep a reference to the mapping\n\n prop = flatProp; // the flattened (mapped) property is the one we want\n\n break;\n }\n\n case undefined:\n break;\n // just set the property\n\n default:\n return false;\n // not a valid mapping\n } // if the property is a bypass property, then link the resultant property to the original one\n\n\n if (propIsBypass) {\n if (origPropIsBypass) {\n // then this bypass overrides the existing one\n prop.bypassed = origProp.bypassed; // steal bypassed prop from old bypass\n } else {\n // then link the orig prop to the new bypass\n prop.bypassed = origProp;\n }\n\n style[prop.name] = prop; // and set\n } else {\n // prop is not bypass\n if (origPropIsBypass) {\n // then keep the orig prop (since it's a bypass) and link to the new prop\n origProp.bypassed = prop;\n } else {\n // then just replace the old prop with the new one\n style[prop.name] = prop;\n }\n }\n\n checkTriggers();\n return true;\n };\n\n styfn$8.cleanElements = function (eles, keepBypasses) {\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n this.clearStyleHints(ele);\n ele.dirtyCompoundBoundsCache();\n ele.dirtyBoundingBoxCache();\n\n if (!keepBypasses) {\n ele._private.style = {};\n } else {\n var style = ele._private.style;\n var propNames = Object.keys(style);\n\n for (var j = 0; j < propNames.length; j++) {\n var propName = propNames[j];\n var eleProp = style[propName];\n\n if (eleProp != null) {\n if (eleProp.bypass) {\n eleProp.bypassed = null;\n } else {\n style[propName] = null;\n }\n }\n }\n }\n }\n }; // updates the visual style for all elements (useful for manual style modification after init)\n\n\n styfn$8.update = function () {\n var cy = this._private.cy;\n var eles = cy.mutableElements();\n eles.updateStyle();\n }; // diffProps : { name => { prev, next } }\n\n\n styfn$8.updateTransitions = function (ele, diffProps) {\n var self = this;\n var _p = ele._private;\n var props = ele.pstyle('transition-property').value;\n var duration = ele.pstyle('transition-duration').pfValue;\n var delay = ele.pstyle('transition-delay').pfValue;\n\n if (props.length > 0 && duration > 0) {\n var style = {}; // build up the style to animate towards\n\n var anyPrev = false;\n\n for (var i = 0; i < props.length; i++) {\n var prop = props[i];\n var styProp = ele.pstyle(prop);\n var diffProp = diffProps[prop];\n\n if (!diffProp) {\n continue;\n }\n\n var prevProp = diffProp.prev;\n var fromProp = prevProp;\n var toProp = diffProp.next != null ? diffProp.next : styProp;\n var diff = false;\n var initVal = void 0;\n var initDt = 0.000001; // delta time % value for initVal (allows animating out of init zero opacity)\n\n if (!fromProp) {\n continue;\n } // consider px values\n\n\n if (number$1(fromProp.pfValue) && number$1(toProp.pfValue)) {\n diff = toProp.pfValue - fromProp.pfValue; // nonzero is truthy\n\n initVal = fromProp.pfValue + initDt * diff; // consider numerical values\n } else if (number$1(fromProp.value) && number$1(toProp.value)) {\n diff = toProp.value - fromProp.value; // nonzero is truthy\n\n initVal = fromProp.value + initDt * diff; // consider colour values\n } else if (array(fromProp.value) && array(toProp.value)) {\n diff = fromProp.value[0] !== toProp.value[0] || fromProp.value[1] !== toProp.value[1] || fromProp.value[2] !== toProp.value[2];\n initVal = fromProp.strValue;\n } // the previous value is good for an animation only if it's different\n\n\n if (diff) {\n style[prop] = toProp.strValue; // to val\n\n this.applyBypass(ele, prop, initVal); // from val\n\n anyPrev = true;\n }\n } // end if props allow ani\n // can't transition if there's nothing previous to transition from\n\n\n if (!anyPrev) {\n return;\n }\n\n _p.transitioning = true;\n new Promise$1(function (resolve) {\n if (delay > 0) {\n ele.delayAnimation(delay).play().promise().then(resolve);\n } else {\n resolve();\n }\n }).then(function () {\n return ele.animation({\n style: style,\n duration: duration,\n easing: ele.pstyle('transition-timing-function').value,\n queue: false\n }).play().promise();\n }).then(function () {\n // if( !isBypass ){\n self.removeBypasses(ele, props);\n ele.emitAndNotify('style'); // }\n\n _p.transitioning = false;\n });\n } else if (_p.transitioning) {\n this.removeBypasses(ele, props);\n ele.emitAndNotify('style');\n _p.transitioning = false;\n }\n };\n\n styfn$8.checkTrigger = function (ele, name, fromValue, toValue, getTrigger, onTrigger) {\n var prop = this.properties[name];\n var triggerCheck = getTrigger(prop);\n\n if (triggerCheck != null && triggerCheck(fromValue, toValue)) {\n onTrigger(prop);\n }\n };\n\n styfn$8.checkZOrderTrigger = function (ele, name, fromValue, toValue) {\n var _this = this;\n\n this.checkTrigger(ele, name, fromValue, toValue, function (prop) {\n return prop.triggersZOrder;\n }, function () {\n _this._private.cy.notify('zorder', ele);\n });\n };\n\n styfn$8.checkBoundsTrigger = function (ele, name, fromValue, toValue) {\n this.checkTrigger(ele, name, fromValue, toValue, function (prop) {\n return prop.triggersBounds;\n }, function (prop) {\n ele.dirtyCompoundBoundsCache();\n ele.dirtyBoundingBoxCache(); // if the prop change makes the bb of pll bezier edges invalid,\n // then dirty the pll edge bb cache as well\n\n if ( // only for beziers -- so performance of other edges isn't affected\n prop.triggersBoundsOfParallelBeziers && (name === 'curve-style' && (fromValue === 'bezier' || toValue === 'bezier') || name === 'display' && (fromValue === 'none' || toValue === 'none'))) {\n ele.parallelEdges().forEach(function (pllEdge) {\n if (pllEdge.isBundledBezier()) {\n pllEdge.dirtyBoundingBoxCache();\n }\n });\n }\n });\n };\n\n styfn$8.checkTriggers = function (ele, name, fromValue, toValue) {\n ele.dirtyStyleCache();\n this.checkZOrderTrigger(ele, name, fromValue, toValue);\n this.checkBoundsTrigger(ele, name, fromValue, toValue);\n };\n\n var styfn$7 = {}; // bypasses are applied to an existing style on an element, and just tacked on temporarily\n // returns true iff application was successful for at least 1 specified property\n\n styfn$7.applyBypass = function (eles, name, value, updateTransitions) {\n var self = this;\n var props = [];\n var isBypass = true; // put all the properties (can specify one or many) in an array after parsing them\n\n if (name === '*' || name === '**') {\n // apply to all property names\n if (value !== undefined) {\n for (var i = 0; i < self.properties.length; i++) {\n var prop = self.properties[i];\n var _name = prop.name;\n var parsedProp = this.parse(_name, value, true);\n\n if (parsedProp) {\n props.push(parsedProp);\n }\n }\n }\n } else if (string(name)) {\n // then parse the single property\n var _parsedProp = this.parse(name, value, true);\n\n if (_parsedProp) {\n props.push(_parsedProp);\n }\n } else if (plainObject(name)) {\n // then parse each property\n var specifiedProps = name;\n updateTransitions = value;\n var names = Object.keys(specifiedProps);\n\n for (var _i = 0; _i < names.length; _i++) {\n var _name2 = names[_i];\n var _value = specifiedProps[_name2];\n\n if (_value === undefined) {\n // try camel case name too\n _value = specifiedProps[dash2camel(_name2)];\n }\n\n if (_value !== undefined) {\n var _parsedProp2 = this.parse(_name2, _value, true);\n\n if (_parsedProp2) {\n props.push(_parsedProp2);\n }\n }\n }\n } else {\n // can't do anything without well defined properties\n return false;\n } // we've failed if there are no valid properties\n\n\n if (props.length === 0) {\n return false;\n } // now, apply the bypass properties on the elements\n\n\n var ret = false; // return true if at least one succesful bypass applied\n\n for (var _i2 = 0; _i2 < eles.length; _i2++) {\n // for each ele\n var ele = eles[_i2];\n var diffProps = {};\n var diffProp = void 0;\n\n for (var j = 0; j < props.length; j++) {\n // for each prop\n var _prop = props[j];\n\n if (updateTransitions) {\n var prevProp = ele.pstyle(_prop.name);\n diffProp = diffProps[_prop.name] = {\n prev: prevProp\n };\n }\n\n ret = this.applyParsedProperty(ele, copy(_prop)) || ret;\n\n if (updateTransitions) {\n diffProp.next = ele.pstyle(_prop.name);\n }\n } // for props\n\n\n if (ret) {\n this.updateStyleHints(ele);\n }\n\n if (updateTransitions) {\n this.updateTransitions(ele, diffProps, isBypass);\n }\n } // for eles\n\n\n return ret;\n }; // only useful in specific cases like animation\n\n\n styfn$7.overrideBypass = function (eles, name, value) {\n name = camel2dash(name);\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var prop = ele._private.style[name];\n var type = this.properties[name].type;\n var isColor = type.color;\n var isMulti = type.mutiple;\n var oldValue = !prop ? null : prop.pfValue != null ? prop.pfValue : prop.value;\n\n if (!prop || !prop.bypass) {\n // need a bypass if one doesn't exist\n this.applyBypass(ele, name, value);\n } else {\n prop.value = value;\n\n if (prop.pfValue != null) {\n prop.pfValue = value;\n }\n\n if (isColor) {\n prop.strValue = 'rgb(' + value.join(',') + ')';\n } else if (isMulti) {\n prop.strValue = value.join(' ');\n } else {\n prop.strValue = '' + value;\n }\n\n this.updateStyleHints(ele);\n }\n\n this.checkTriggers(ele, name, oldValue, value);\n }\n };\n\n styfn$7.removeAllBypasses = function (eles, updateTransitions) {\n return this.removeBypasses(eles, this.propertyNames, updateTransitions);\n };\n\n styfn$7.removeBypasses = function (eles, props, updateTransitions) {\n var isBypass = true;\n\n for (var j = 0; j < eles.length; j++) {\n var ele = eles[j];\n var diffProps = {};\n\n for (var i = 0; i < props.length; i++) {\n var name = props[i];\n var prop = this.properties[name];\n var prevProp = ele.pstyle(prop.name);\n\n if (!prevProp || !prevProp.bypass) {\n // if a bypass doesn't exist for the prop, nothing needs to be removed\n continue;\n }\n\n var value = ''; // empty => remove bypass\n\n var parsedProp = this.parse(name, value, true);\n var diffProp = diffProps[prop.name] = {\n prev: prevProp\n };\n this.applyParsedProperty(ele, parsedProp);\n diffProp.next = ele.pstyle(prop.name);\n } // for props\n\n\n this.updateStyleHints(ele);\n\n if (updateTransitions) {\n this.updateTransitions(ele, diffProps, isBypass);\n }\n } // for eles\n\n };\n\n var styfn$6 = {}; // gets what an em size corresponds to in pixels relative to a dom element\n\n styfn$6.getEmSizeInPixels = function () {\n var px = this.containerCss('font-size');\n\n if (px != null) {\n return parseFloat(px);\n } else {\n return 1; // for headless\n }\n }; // gets css property from the core container\n\n\n styfn$6.containerCss = function (propName) {\n var cy = this._private.cy;\n var domElement = cy.container();\n var containerWindow = cy.window();\n\n if (containerWindow && domElement && containerWindow.getComputedStyle) {\n return containerWindow.getComputedStyle(domElement).getPropertyValue(propName);\n }\n };\n\n var styfn$5 = {}; // gets the rendered style for an element\n\n styfn$5.getRenderedStyle = function (ele, prop) {\n if (prop) {\n return this.getStylePropertyValue(ele, prop, true);\n } else {\n return this.getRawStyle(ele, true);\n }\n }; // gets the raw style for an element\n\n\n styfn$5.getRawStyle = function (ele, isRenderedVal) {\n var self = this;\n ele = ele[0]; // insure it's an element\n\n if (ele) {\n var rstyle = {};\n\n for (var i = 0; i < self.properties.length; i++) {\n var prop = self.properties[i];\n var val = self.getStylePropertyValue(ele, prop.name, isRenderedVal);\n\n if (val != null) {\n rstyle[prop.name] = val;\n rstyle[dash2camel(prop.name)] = val;\n }\n }\n\n return rstyle;\n }\n };\n\n styfn$5.getIndexedStyle = function (ele, property, subproperty, index) {\n var pstyle = ele.pstyle(property)[subproperty][index];\n return pstyle != null ? pstyle : ele.cy().style().getDefaultProperty(property)[subproperty][0];\n };\n\n styfn$5.getStylePropertyValue = function (ele, propName, isRenderedVal) {\n var self = this;\n ele = ele[0]; // insure it's an element\n\n if (ele) {\n var prop = self.properties[propName];\n\n if (prop.alias) {\n prop = prop.pointsTo;\n }\n\n var type = prop.type;\n var styleProp = ele.pstyle(prop.name);\n\n if (styleProp) {\n var value = styleProp.value,\n units = styleProp.units,\n strValue = styleProp.strValue;\n\n if (isRenderedVal && type.number && value != null && number$1(value)) {\n var zoom = ele.cy().zoom();\n\n var getRenderedValue = function getRenderedValue(val) {\n return val * zoom;\n };\n\n var getValueStringWithUnits = function getValueStringWithUnits(val, units) {\n return getRenderedValue(val) + units;\n };\n\n var isArrayValue = array(value);\n var haveUnits = isArrayValue ? units.every(function (u) {\n return u != null;\n }) : units != null;\n\n if (haveUnits) {\n if (isArrayValue) {\n return value.map(function (v, i) {\n return getValueStringWithUnits(v, units[i]);\n }).join(' ');\n } else {\n return getValueStringWithUnits(value, units);\n }\n } else {\n if (isArrayValue) {\n return value.map(function (v) {\n return string(v) ? v : '' + getRenderedValue(v);\n }).join(' ');\n } else {\n return '' + getRenderedValue(value);\n }\n }\n } else if (strValue != null) {\n return strValue;\n }\n }\n\n return null;\n }\n };\n\n styfn$5.getAnimationStartStyle = function (ele, aniProps) {\n var rstyle = {};\n\n for (var i = 0; i < aniProps.length; i++) {\n var aniProp = aniProps[i];\n var name = aniProp.name;\n var styleProp = ele.pstyle(name);\n\n if (styleProp !== undefined) {\n // then make a prop of it\n if (plainObject(styleProp)) {\n styleProp = this.parse(name, styleProp.strValue);\n } else {\n styleProp = this.parse(name, styleProp);\n }\n }\n\n if (styleProp) {\n rstyle[name] = styleProp;\n }\n }\n\n return rstyle;\n };\n\n styfn$5.getPropsList = function (propsObj) {\n var self = this;\n var rstyle = [];\n var style = propsObj;\n var props = self.properties;\n\n if (style) {\n var names = Object.keys(style);\n\n for (var i = 0; i < names.length; i++) {\n var name = names[i];\n var val = style[name];\n var prop = props[name] || props[camel2dash(name)];\n var styleProp = this.parse(prop.name, val);\n\n if (styleProp) {\n rstyle.push(styleProp);\n }\n }\n }\n\n return rstyle;\n };\n\n styfn$5.getNonDefaultPropertiesHash = function (ele, propNames, seed) {\n var hash = seed.slice();\n var name, val, strVal, chVal;\n var i, j;\n\n for (i = 0; i < propNames.length; i++) {\n name = propNames[i];\n val = ele.pstyle(name, false);\n\n if (val == null) {\n continue;\n } else if (val.pfValue != null) {\n hash[0] = hashInt(chVal, hash[0]);\n hash[1] = hashIntAlt(chVal, hash[1]);\n } else {\n strVal = val.strValue;\n\n for (j = 0; j < strVal.length; j++) {\n chVal = strVal.charCodeAt(j);\n hash[0] = hashInt(chVal, hash[0]);\n hash[1] = hashIntAlt(chVal, hash[1]);\n }\n }\n }\n\n return hash;\n };\n\n styfn$5.getPropertiesHash = styfn$5.getNonDefaultPropertiesHash;\n\n var styfn$4 = {};\n\n styfn$4.appendFromJson = function (json) {\n var style = this;\n\n for (var i = 0; i < json.length; i++) {\n var context = json[i];\n var selector = context.selector;\n var props = context.style || context.css;\n var names = Object.keys(props);\n style.selector(selector); // apply selector\n\n for (var j = 0; j < names.length; j++) {\n var name = names[j];\n var value = props[name];\n style.css(name, value); // apply property\n }\n }\n\n return style;\n }; // accessible cy.style() function\n\n\n styfn$4.fromJson = function (json) {\n var style = this;\n style.resetToDefault();\n style.appendFromJson(json);\n return style;\n }; // get json from cy.style() api\n\n\n styfn$4.json = function () {\n var json = [];\n\n for (var i = this.defaultLength; i < this.length; i++) {\n var cxt = this[i];\n var selector = cxt.selector;\n var props = cxt.properties;\n var css = {};\n\n for (var j = 0; j < props.length; j++) {\n var prop = props[j];\n css[prop.name] = prop.strValue;\n }\n\n json.push({\n selector: !selector ? 'core' : selector.toString(),\n style: css\n });\n }\n\n return json;\n };\n\n var styfn$3 = {};\n\n styfn$3.appendFromString = function (string) {\n var self = this;\n var style = this;\n var remaining = '' + string;\n var selAndBlockStr;\n var blockRem;\n var propAndValStr; // remove comments from the style string\n\n remaining = remaining.replace(/[/][*](\\s|.)+?[*][/]/g, '');\n\n function removeSelAndBlockFromRemaining() {\n // remove the parsed selector and block from the remaining text to parse\n if (remaining.length > selAndBlockStr.length) {\n remaining = remaining.substr(selAndBlockStr.length);\n } else {\n remaining = '';\n }\n }\n\n function removePropAndValFromRem() {\n // remove the parsed property and value from the remaining block text to parse\n if (blockRem.length > propAndValStr.length) {\n blockRem = blockRem.substr(propAndValStr.length);\n } else {\n blockRem = '';\n }\n }\n\n for (;;) {\n var nothingLeftToParse = remaining.match(/^\\s*$/);\n\n if (nothingLeftToParse) {\n break;\n }\n\n var selAndBlock = remaining.match(/^\\s*((?:.|\\s)+?)\\s*\\{((?:.|\\s)+?)\\}/);\n\n if (!selAndBlock) {\n warn('Halting stylesheet parsing: String stylesheet contains more to parse but no selector and block found in: ' + remaining);\n break;\n }\n\n selAndBlockStr = selAndBlock[0]; // parse the selector\n\n var selectorStr = selAndBlock[1];\n\n if (selectorStr !== 'core') {\n var selector = new Selector(selectorStr);\n\n if (selector.invalid) {\n warn('Skipping parsing of block: Invalid selector found in string stylesheet: ' + selectorStr); // skip this selector and block\n\n removeSelAndBlockFromRemaining();\n continue;\n }\n } // parse the block of properties and values\n\n\n var blockStr = selAndBlock[2];\n var invalidBlock = false;\n blockRem = blockStr;\n var props = [];\n\n for (;;) {\n var _nothingLeftToParse = blockRem.match(/^\\s*$/);\n\n if (_nothingLeftToParse) {\n break;\n }\n\n var propAndVal = blockRem.match(/^\\s*(.+?)\\s*:\\s*(.+?)(?:\\s*;|\\s*$)/);\n\n if (!propAndVal) {\n warn('Skipping parsing of block: Invalid formatting of style property and value definitions found in:' + blockStr);\n invalidBlock = true;\n break;\n }\n\n propAndValStr = propAndVal[0];\n var propStr = propAndVal[1];\n var valStr = propAndVal[2];\n var prop = self.properties[propStr];\n\n if (!prop) {\n warn('Skipping property: Invalid property name in: ' + propAndValStr); // skip this property in the block\n\n removePropAndValFromRem();\n continue;\n }\n\n var parsedProp = style.parse(propStr, valStr);\n\n if (!parsedProp) {\n warn('Skipping property: Invalid property definition in: ' + propAndValStr); // skip this property in the block\n\n removePropAndValFromRem();\n continue;\n }\n\n props.push({\n name: propStr,\n val: valStr\n });\n removePropAndValFromRem();\n }\n\n if (invalidBlock) {\n removeSelAndBlockFromRemaining();\n break;\n } // put the parsed block in the style\n\n\n style.selector(selectorStr);\n\n for (var i = 0; i < props.length; i++) {\n var _prop = props[i];\n style.css(_prop.name, _prop.val);\n }\n\n removeSelAndBlockFromRemaining();\n }\n\n return style;\n };\n\n styfn$3.fromString = function (string) {\n var style = this;\n style.resetToDefault();\n style.appendFromString(string);\n return style;\n };\n\n var styfn$2 = {};\n\n (function () {\n var number$1 = number;\n var rgba = rgbaNoBackRefs;\n var hsla = hslaNoBackRefs;\n var hex3$1 = hex3;\n var hex6$1 = hex6;\n\n var data = function data(prefix) {\n return '^' + prefix + '\\\\s*\\\\(\\\\s*([\\\\w\\\\.]+)\\\\s*\\\\)$';\n };\n\n var mapData = function mapData(prefix) {\n var mapArg = number$1 + '|\\\\w+|' + rgba + '|' + hsla + '|' + hex3$1 + '|' + hex6$1;\n return '^' + prefix + '\\\\s*\\\\(([\\\\w\\\\.]+)\\\\s*\\\\,\\\\s*(' + number$1 + ')\\\\s*\\\\,\\\\s*(' + number$1 + ')\\\\s*,\\\\s*(' + mapArg + ')\\\\s*\\\\,\\\\s*(' + mapArg + ')\\\\)$';\n };\n\n var urlRegexes = ['^url\\\\s*\\\\(\\\\s*[\\'\"]?(.+?)[\\'\"]?\\\\s*\\\\)$', '^(none)$', '^(.+)$']; // each visual style property has a type and needs to be validated according to it\n\n styfn$2.types = {\n time: {\n number: true,\n min: 0,\n units: 's|ms',\n implicitUnits: 'ms'\n },\n percent: {\n number: true,\n min: 0,\n max: 100,\n units: '%',\n implicitUnits: '%'\n },\n percentages: {\n number: true,\n min: 0,\n max: 100,\n units: '%',\n implicitUnits: '%',\n multiple: true\n },\n zeroOneNumber: {\n number: true,\n min: 0,\n max: 1,\n unitless: true\n },\n zeroOneNumbers: {\n number: true,\n min: 0,\n max: 1,\n unitless: true,\n multiple: true\n },\n nOneOneNumber: {\n number: true,\n min: -1,\n max: 1,\n unitless: true\n },\n nonNegativeInt: {\n number: true,\n min: 0,\n integer: true,\n unitless: true\n },\n position: {\n enums: ['parent', 'origin']\n },\n nodeSize: {\n number: true,\n min: 0,\n enums: ['label']\n },\n number: {\n number: true,\n unitless: true\n },\n numbers: {\n number: true,\n unitless: true,\n multiple: true\n },\n positiveNumber: {\n number: true,\n unitless: true,\n min: 0,\n strictMin: true\n },\n size: {\n number: true,\n min: 0\n },\n bidirectionalSize: {\n number: true\n },\n // allows negative\n bidirectionalSizeMaybePercent: {\n number: true,\n allowPercent: true\n },\n // allows negative\n bidirectionalSizes: {\n number: true,\n multiple: true\n },\n // allows negative\n sizeMaybePercent: {\n number: true,\n min: 0,\n allowPercent: true\n },\n axisDirection: {\n enums: ['horizontal', 'leftward', 'rightward', 'vertical', 'upward', 'downward', 'auto']\n },\n paddingRelativeTo: {\n enums: ['width', 'height', 'average', 'min', 'max']\n },\n bgWH: {\n number: true,\n min: 0,\n allowPercent: true,\n enums: ['auto'],\n multiple: true\n },\n bgPos: {\n number: true,\n allowPercent: true,\n multiple: true\n },\n bgRelativeTo: {\n enums: ['inner', 'include-padding'],\n multiple: true\n },\n bgRepeat: {\n enums: ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'],\n multiple: true\n },\n bgFit: {\n enums: ['none', 'contain', 'cover'],\n multiple: true\n },\n bgCrossOrigin: {\n enums: ['anonymous', 'use-credentials', 'null'],\n multiple: true\n },\n bgClip: {\n enums: ['none', 'node'],\n multiple: true\n },\n bgContainment: {\n enums: ['inside', 'over'],\n multiple: true\n },\n color: {\n color: true\n },\n colors: {\n color: true,\n multiple: true\n },\n fill: {\n enums: ['solid', 'linear-gradient', 'radial-gradient']\n },\n bool: {\n enums: ['yes', 'no']\n },\n bools: {\n enums: ['yes', 'no'],\n multiple: true\n },\n lineStyle: {\n enums: ['solid', 'dotted', 'dashed']\n },\n lineCap: {\n enums: ['butt', 'round', 'square']\n },\n borderStyle: {\n enums: ['solid', 'dotted', 'dashed', 'double']\n },\n curveStyle: {\n enums: ['bezier', 'unbundled-bezier', 'haystack', 'segments', 'straight', 'straight-triangle', 'taxi']\n },\n fontFamily: {\n regex: '^([\\\\w- \\\\\"]+(?:\\\\s*,\\\\s*[\\\\w- \\\\\"]+)*)$'\n },\n fontStyle: {\n enums: ['italic', 'normal', 'oblique']\n },\n fontWeight: {\n enums: ['normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '800', '900', 100, 200, 300, 400, 500, 600, 700, 800, 900]\n },\n textDecoration: {\n enums: ['none', 'underline', 'overline', 'line-through']\n },\n textTransform: {\n enums: ['none', 'uppercase', 'lowercase']\n },\n textWrap: {\n enums: ['none', 'wrap', 'ellipsis']\n },\n textOverflowWrap: {\n enums: ['whitespace', 'anywhere']\n },\n textBackgroundShape: {\n enums: ['rectangle', 'roundrectangle', 'round-rectangle']\n },\n nodeShape: {\n enums: ['rectangle', 'roundrectangle', 'round-rectangle', 'cutrectangle', 'cut-rectangle', 'bottomroundrectangle', 'bottom-round-rectangle', 'barrel', 'ellipse', 'triangle', 'round-triangle', 'square', 'pentagon', 'round-pentagon', 'hexagon', 'round-hexagon', 'concavehexagon', 'concave-hexagon', 'heptagon', 'round-heptagon', 'octagon', 'round-octagon', 'tag', 'round-tag', 'star', 'diamond', 'round-diamond', 'vee', 'rhomboid', 'right-rhomboid', 'polygon']\n },\n overlayShape: {\n enums: ['roundrectangle', 'round-rectangle', 'ellipse']\n },\n compoundIncludeLabels: {\n enums: ['include', 'exclude']\n },\n arrowShape: {\n enums: ['tee', 'triangle', 'triangle-tee', 'circle-triangle', 'triangle-cross', 'triangle-backcurve', 'vee', 'square', 'circle', 'diamond', 'chevron', 'none']\n },\n arrowFill: {\n enums: ['filled', 'hollow']\n },\n display: {\n enums: ['element', 'none']\n },\n visibility: {\n enums: ['hidden', 'visible']\n },\n zCompoundDepth: {\n enums: ['bottom', 'orphan', 'auto', 'top']\n },\n zIndexCompare: {\n enums: ['auto', 'manual']\n },\n valign: {\n enums: ['top', 'center', 'bottom']\n },\n halign: {\n enums: ['left', 'center', 'right']\n },\n justification: {\n enums: ['left', 'center', 'right', 'auto']\n },\n text: {\n string: true\n },\n data: {\n mapping: true,\n regex: data('data')\n },\n layoutData: {\n mapping: true,\n regex: data('layoutData')\n },\n scratch: {\n mapping: true,\n regex: data('scratch')\n },\n mapData: {\n mapping: true,\n regex: mapData('mapData')\n },\n mapLayoutData: {\n mapping: true,\n regex: mapData('mapLayoutData')\n },\n mapScratch: {\n mapping: true,\n regex: mapData('mapScratch')\n },\n fn: {\n mapping: true,\n fn: true\n },\n url: {\n regexes: urlRegexes,\n singleRegexMatchValue: true\n },\n urls: {\n regexes: urlRegexes,\n singleRegexMatchValue: true,\n multiple: true\n },\n propList: {\n propList: true\n },\n angle: {\n number: true,\n units: 'deg|rad',\n implicitUnits: 'rad'\n },\n textRotation: {\n number: true,\n units: 'deg|rad',\n implicitUnits: 'rad',\n enums: ['none', 'autorotate']\n },\n polygonPointList: {\n number: true,\n multiple: true,\n evenMultiple: true,\n min: -1,\n max: 1,\n unitless: true\n },\n edgeDistances: {\n enums: ['intersection', 'node-position']\n },\n edgeEndpoint: {\n number: true,\n multiple: true,\n units: '%|px|em|deg|rad',\n implicitUnits: 'px',\n enums: ['inside-to-node', 'outside-to-node', 'outside-to-node-or-label', 'outside-to-line', 'outside-to-line-or-label'],\n singleEnum: true,\n validate: function validate(valArr, unitsArr) {\n switch (valArr.length) {\n case 2:\n // can be % or px only\n return unitsArr[0] !== 'deg' && unitsArr[0] !== 'rad' && unitsArr[1] !== 'deg' && unitsArr[1] !== 'rad';\n\n case 1:\n // can be enum, deg, or rad only\n return string(valArr[0]) || unitsArr[0] === 'deg' || unitsArr[0] === 'rad';\n\n default:\n return false;\n }\n }\n },\n easing: {\n regexes: ['^(spring)\\\\s*\\\\(\\\\s*(' + number$1 + ')\\\\s*,\\\\s*(' + number$1 + ')\\\\s*\\\\)$', '^(cubic-bezier)\\\\s*\\\\(\\\\s*(' + number$1 + ')\\\\s*,\\\\s*(' + number$1 + ')\\\\s*,\\\\s*(' + number$1 + ')\\\\s*,\\\\s*(' + number$1 + ')\\\\s*\\\\)$'],\n enums: ['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'ease-in-sine', 'ease-out-sine', 'ease-in-out-sine', 'ease-in-quad', 'ease-out-quad', 'ease-in-out-quad', 'ease-in-cubic', 'ease-out-cubic', 'ease-in-out-cubic', 'ease-in-quart', 'ease-out-quart', 'ease-in-out-quart', 'ease-in-quint', 'ease-out-quint', 'ease-in-out-quint', 'ease-in-expo', 'ease-out-expo', 'ease-in-out-expo', 'ease-in-circ', 'ease-out-circ', 'ease-in-out-circ']\n },\n gradientDirection: {\n enums: ['to-bottom', 'to-top', 'to-left', 'to-right', 'to-bottom-right', 'to-bottom-left', 'to-top-right', 'to-top-left', 'to-right-bottom', 'to-left-bottom', 'to-right-top', 'to-left-top' // different order\n ]\n },\n boundsExpansion: {\n number: true,\n multiple: true,\n min: 0,\n validate: function validate(valArr) {\n var length = valArr.length;\n return length === 1 || length === 2 || length === 4;\n }\n }\n };\n var diff = {\n zeroNonZero: function zeroNonZero(val1, val2) {\n if ((val1 == null || val2 == null) && val1 !== val2) {\n return true; // null cases could represent any value\n }\n\n if (val1 == 0 && val2 != 0) {\n return true;\n } else if (val1 != 0 && val2 == 0) {\n return true;\n } else {\n return false;\n }\n },\n any: function any(val1, val2) {\n return val1 != val2;\n },\n emptyNonEmpty: function emptyNonEmpty(str1, str2) {\n var empty1 = emptyString(str1);\n var empty2 = emptyString(str2);\n return empty1 && !empty2 || !empty1 && empty2;\n }\n }; // define visual style properties\n //\n // - n.b. adding a new group of props may require updates to updateStyleHints()\n // - adding new props to an existing group gets handled automatically\n\n var t = styfn$2.types;\n var mainLabel = [{\n name: 'label',\n type: t.text,\n triggersBounds: diff.any,\n triggersZOrder: diff.emptyNonEmpty\n }, {\n name: 'text-rotation',\n type: t.textRotation,\n triggersBounds: diff.any\n }, {\n name: 'text-margin-x',\n type: t.bidirectionalSize,\n triggersBounds: diff.any\n }, {\n name: 'text-margin-y',\n type: t.bidirectionalSize,\n triggersBounds: diff.any\n }];\n var sourceLabel = [{\n name: 'source-label',\n type: t.text,\n triggersBounds: diff.any\n }, {\n name: 'source-text-rotation',\n type: t.textRotation,\n triggersBounds: diff.any\n }, {\n name: 'source-text-margin-x',\n type: t.bidirectionalSize,\n triggersBounds: diff.any\n }, {\n name: 'source-text-margin-y',\n type: t.bidirectionalSize,\n triggersBounds: diff.any\n }, {\n name: 'source-text-offset',\n type: t.size,\n triggersBounds: diff.any\n }];\n var targetLabel = [{\n name: 'target-label',\n type: t.text,\n triggersBounds: diff.any\n }, {\n name: 'target-text-rotation',\n type: t.textRotation,\n triggersBounds: diff.any\n }, {\n name: 'target-text-margin-x',\n type: t.bidirectionalSize,\n triggersBounds: diff.any\n }, {\n name: 'target-text-margin-y',\n type: t.bidirectionalSize,\n triggersBounds: diff.any\n }, {\n name: 'target-text-offset',\n type: t.size,\n triggersBounds: diff.any\n }];\n var labelDimensions = [{\n name: 'font-family',\n type: t.fontFamily,\n triggersBounds: diff.any\n }, {\n name: 'font-style',\n type: t.fontStyle,\n triggersBounds: diff.any\n }, {\n name: 'font-weight',\n type: t.fontWeight,\n triggersBounds: diff.any\n }, {\n name: 'font-size',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'text-transform',\n type: t.textTransform,\n triggersBounds: diff.any\n }, {\n name: 'text-wrap',\n type: t.textWrap,\n triggersBounds: diff.any\n }, {\n name: 'text-overflow-wrap',\n type: t.textOverflowWrap,\n triggersBounds: diff.any\n }, {\n name: 'text-max-width',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'text-outline-width',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'line-height',\n type: t.positiveNumber,\n triggersBounds: diff.any\n }];\n var commonLabel = [{\n name: 'text-valign',\n type: t.valign,\n triggersBounds: diff.any\n }, {\n name: 'text-halign',\n type: t.halign,\n triggersBounds: diff.any\n }, {\n name: 'color',\n type: t.color\n }, {\n name: 'text-outline-color',\n type: t.color\n }, {\n name: 'text-outline-opacity',\n type: t.zeroOneNumber\n }, {\n name: 'text-background-color',\n type: t.color\n }, {\n name: 'text-background-opacity',\n type: t.zeroOneNumber\n }, {\n name: 'text-background-padding',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'text-border-opacity',\n type: t.zeroOneNumber\n }, {\n name: 'text-border-color',\n type: t.color\n }, {\n name: 'text-border-width',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'text-border-style',\n type: t.borderStyle,\n triggersBounds: diff.any\n }, {\n name: 'text-background-shape',\n type: t.textBackgroundShape,\n triggersBounds: diff.any\n }, {\n name: 'text-justification',\n type: t.justification\n }];\n var behavior = [{\n name: 'events',\n type: t.bool\n }, {\n name: 'text-events',\n type: t.bool\n }];\n var visibility = [{\n name: 'display',\n type: t.display,\n triggersZOrder: diff.any,\n triggersBounds: diff.any,\n triggersBoundsOfParallelBeziers: true\n }, {\n name: 'visibility',\n type: t.visibility,\n triggersZOrder: diff.any\n }, {\n name: 'opacity',\n type: t.zeroOneNumber,\n triggersZOrder: diff.zeroNonZero\n }, {\n name: 'text-opacity',\n type: t.zeroOneNumber\n }, {\n name: 'min-zoomed-font-size',\n type: t.size\n }, {\n name: 'z-compound-depth',\n type: t.zCompoundDepth,\n triggersZOrder: diff.any\n }, {\n name: 'z-index-compare',\n type: t.zIndexCompare,\n triggersZOrder: diff.any\n }, {\n name: 'z-index',\n type: t.nonNegativeInt,\n triggersZOrder: diff.any\n }];\n var overlay = [{\n name: 'overlay-padding',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'overlay-color',\n type: t.color\n }, {\n name: 'overlay-opacity',\n type: t.zeroOneNumber,\n triggersBounds: diff.zeroNonZero\n }, {\n name: 'overlay-shape',\n type: t.overlayShape,\n triggersBounds: diff.any\n }];\n var underlay = [{\n name: 'underlay-padding',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'underlay-color',\n type: t.color\n }, {\n name: 'underlay-opacity',\n type: t.zeroOneNumber,\n triggersBounds: diff.zeroNonZero\n }, {\n name: 'underlay-shape',\n type: t.overlayShape,\n triggersBounds: diff.any\n }];\n var transition = [{\n name: 'transition-property',\n type: t.propList\n }, {\n name: 'transition-duration',\n type: t.time\n }, {\n name: 'transition-delay',\n type: t.time\n }, {\n name: 'transition-timing-function',\n type: t.easing\n }];\n\n var nodeSizeHashOverride = function nodeSizeHashOverride(ele, parsedProp) {\n if (parsedProp.value === 'label') {\n return -ele.poolIndex(); // no hash key hits is using label size (hitrate for perf probably low anyway)\n } else {\n return parsedProp.pfValue;\n }\n };\n\n var nodeBody = [{\n name: 'height',\n type: t.nodeSize,\n triggersBounds: diff.any,\n hashOverride: nodeSizeHashOverride\n }, {\n name: 'width',\n type: t.nodeSize,\n triggersBounds: diff.any,\n hashOverride: nodeSizeHashOverride\n }, {\n name: 'shape',\n type: t.nodeShape,\n triggersBounds: diff.any\n }, {\n name: 'shape-polygon-points',\n type: t.polygonPointList,\n triggersBounds: diff.any\n }, {\n name: 'background-color',\n type: t.color\n }, {\n name: 'background-fill',\n type: t.fill\n }, {\n name: 'background-opacity',\n type: t.zeroOneNumber\n }, {\n name: 'background-blacken',\n type: t.nOneOneNumber\n }, {\n name: 'background-gradient-stop-colors',\n type: t.colors\n }, {\n name: 'background-gradient-stop-positions',\n type: t.percentages\n }, {\n name: 'background-gradient-direction',\n type: t.gradientDirection\n }, {\n name: 'padding',\n type: t.sizeMaybePercent,\n triggersBounds: diff.any\n }, {\n name: 'padding-relative-to',\n type: t.paddingRelativeTo,\n triggersBounds: diff.any\n }, {\n name: 'bounds-expansion',\n type: t.boundsExpansion,\n triggersBounds: diff.any\n }];\n var nodeBorder = [{\n name: 'border-color',\n type: t.color\n }, {\n name: 'border-opacity',\n type: t.zeroOneNumber\n }, {\n name: 'border-width',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'border-style',\n type: t.borderStyle\n }];\n var backgroundImage = [{\n name: 'background-image',\n type: t.urls\n }, {\n name: 'background-image-crossorigin',\n type: t.bgCrossOrigin\n }, {\n name: 'background-image-opacity',\n type: t.zeroOneNumbers\n }, {\n name: 'background-image-containment',\n type: t.bgContainment\n }, {\n name: 'background-image-smoothing',\n type: t.bools\n }, {\n name: 'background-position-x',\n type: t.bgPos\n }, {\n name: 'background-position-y',\n type: t.bgPos\n }, {\n name: 'background-width-relative-to',\n type: t.bgRelativeTo\n }, {\n name: 'background-height-relative-to',\n type: t.bgRelativeTo\n }, {\n name: 'background-repeat',\n type: t.bgRepeat\n }, {\n name: 'background-fit',\n type: t.bgFit\n }, {\n name: 'background-clip',\n type: t.bgClip\n }, {\n name: 'background-width',\n type: t.bgWH\n }, {\n name: 'background-height',\n type: t.bgWH\n }, {\n name: 'background-offset-x',\n type: t.bgPos\n }, {\n name: 'background-offset-y',\n type: t.bgPos\n }];\n var compound = [{\n name: 'position',\n type: t.position,\n triggersBounds: diff.any\n }, {\n name: 'compound-sizing-wrt-labels',\n type: t.compoundIncludeLabels,\n triggersBounds: diff.any\n }, {\n name: 'min-width',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'min-width-bias-left',\n type: t.sizeMaybePercent,\n triggersBounds: diff.any\n }, {\n name: 'min-width-bias-right',\n type: t.sizeMaybePercent,\n triggersBounds: diff.any\n }, {\n name: 'min-height',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'min-height-bias-top',\n type: t.sizeMaybePercent,\n triggersBounds: diff.any\n }, {\n name: 'min-height-bias-bottom',\n type: t.sizeMaybePercent,\n triggersBounds: diff.any\n }];\n var edgeLine = [{\n name: 'line-style',\n type: t.lineStyle\n }, {\n name: 'line-color',\n type: t.color\n }, {\n name: 'line-fill',\n type: t.fill\n }, {\n name: 'line-cap',\n type: t.lineCap\n }, {\n name: 'line-opacity',\n type: t.zeroOneNumber\n }, {\n name: 'line-dash-pattern',\n type: t.numbers\n }, {\n name: 'line-dash-offset',\n type: t.number\n }, {\n name: 'line-gradient-stop-colors',\n type: t.colors\n }, {\n name: 'line-gradient-stop-positions',\n type: t.percentages\n }, {\n name: 'curve-style',\n type: t.curveStyle,\n triggersBounds: diff.any,\n triggersBoundsOfParallelBeziers: true\n }, {\n name: 'haystack-radius',\n type: t.zeroOneNumber,\n triggersBounds: diff.any\n }, {\n name: 'source-endpoint',\n type: t.edgeEndpoint,\n triggersBounds: diff.any\n }, {\n name: 'target-endpoint',\n type: t.edgeEndpoint,\n triggersBounds: diff.any\n }, {\n name: 'control-point-step-size',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'control-point-distances',\n type: t.bidirectionalSizes,\n triggersBounds: diff.any\n }, {\n name: 'control-point-weights',\n type: t.numbers,\n triggersBounds: diff.any\n }, {\n name: 'segment-distances',\n type: t.bidirectionalSizes,\n triggersBounds: diff.any\n }, {\n name: 'segment-weights',\n type: t.numbers,\n triggersBounds: diff.any\n }, {\n name: 'taxi-turn',\n type: t.bidirectionalSizeMaybePercent,\n triggersBounds: diff.any\n }, {\n name: 'taxi-turn-min-distance',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'taxi-direction',\n type: t.axisDirection,\n triggersBounds: diff.any\n }, {\n name: 'edge-distances',\n type: t.edgeDistances,\n triggersBounds: diff.any\n }, {\n name: 'arrow-scale',\n type: t.positiveNumber,\n triggersBounds: diff.any\n }, {\n name: 'loop-direction',\n type: t.angle,\n triggersBounds: diff.any\n }, {\n name: 'loop-sweep',\n type: t.angle,\n triggersBounds: diff.any\n }, {\n name: 'source-distance-from-node',\n type: t.size,\n triggersBounds: diff.any\n }, {\n name: 'target-distance-from-node',\n type: t.size,\n triggersBounds: diff.any\n }];\n var ghost = [{\n name: 'ghost',\n type: t.bool,\n triggersBounds: diff.any\n }, {\n name: 'ghost-offset-x',\n type: t.bidirectionalSize,\n triggersBounds: diff.any\n }, {\n name: 'ghost-offset-y',\n type: t.bidirectionalSize,\n triggersBounds: diff.any\n }, {\n name: 'ghost-opacity',\n type: t.zeroOneNumber\n }];\n var core = [{\n name: 'selection-box-color',\n type: t.color\n }, {\n name: 'selection-box-opacity',\n type: t.zeroOneNumber\n }, {\n name: 'selection-box-border-color',\n type: t.color\n }, {\n name: 'selection-box-border-width',\n type: t.size\n }, {\n name: 'active-bg-color',\n type: t.color\n }, {\n name: 'active-bg-opacity',\n type: t.zeroOneNumber\n }, {\n name: 'active-bg-size',\n type: t.size\n }, {\n name: 'outside-texture-bg-color',\n type: t.color\n }, {\n name: 'outside-texture-bg-opacity',\n type: t.zeroOneNumber\n }]; // pie backgrounds for nodes\n\n var pie = [];\n styfn$2.pieBackgroundN = 16; // because the pie properties are numbered, give access to a constant N (for renderer use)\n\n pie.push({\n name: 'pie-size',\n type: t.sizeMaybePercent\n });\n\n for (var i = 1; i <= styfn$2.pieBackgroundN; i++) {\n pie.push({\n name: 'pie-' + i + '-background-color',\n type: t.color\n });\n pie.push({\n name: 'pie-' + i + '-background-size',\n type: t.percent\n });\n pie.push({\n name: 'pie-' + i + '-background-opacity',\n type: t.zeroOneNumber\n });\n } // edge arrows\n\n\n var edgeArrow = [];\n var arrowPrefixes = styfn$2.arrowPrefixes = ['source', 'mid-source', 'target', 'mid-target'];\n [{\n name: 'arrow-shape',\n type: t.arrowShape,\n triggersBounds: diff.any\n }, {\n name: 'arrow-color',\n type: t.color\n }, {\n name: 'arrow-fill',\n type: t.arrowFill\n }].forEach(function (prop) {\n arrowPrefixes.forEach(function (prefix) {\n var name = prefix + '-' + prop.name;\n var type = prop.type,\n triggersBounds = prop.triggersBounds;\n edgeArrow.push({\n name: name,\n type: type,\n triggersBounds: triggersBounds\n });\n });\n }, {});\n var props = styfn$2.properties = [].concat(behavior, transition, visibility, overlay, underlay, ghost, commonLabel, labelDimensions, mainLabel, sourceLabel, targetLabel, nodeBody, nodeBorder, backgroundImage, pie, compound, edgeLine, edgeArrow, core);\n var propGroups = styfn$2.propertyGroups = {\n // common to all eles\n behavior: behavior,\n transition: transition,\n visibility: visibility,\n overlay: overlay,\n underlay: underlay,\n ghost: ghost,\n // labels\n commonLabel: commonLabel,\n labelDimensions: labelDimensions,\n mainLabel: mainLabel,\n sourceLabel: sourceLabel,\n targetLabel: targetLabel,\n // node props\n nodeBody: nodeBody,\n nodeBorder: nodeBorder,\n backgroundImage: backgroundImage,\n pie: pie,\n compound: compound,\n // edge props\n edgeLine: edgeLine,\n edgeArrow: edgeArrow,\n core: core\n };\n var propGroupNames = styfn$2.propertyGroupNames = {};\n var propGroupKeys = styfn$2.propertyGroupKeys = Object.keys(propGroups);\n propGroupKeys.forEach(function (key) {\n propGroupNames[key] = propGroups[key].map(function (prop) {\n return prop.name;\n });\n propGroups[key].forEach(function (prop) {\n return prop.groupKey = key;\n });\n }); // define aliases\n\n var aliases = styfn$2.aliases = [{\n name: 'content',\n pointsTo: 'label'\n }, {\n name: 'control-point-distance',\n pointsTo: 'control-point-distances'\n }, {\n name: 'control-point-weight',\n pointsTo: 'control-point-weights'\n }, {\n name: 'edge-text-rotation',\n pointsTo: 'text-rotation'\n }, {\n name: 'padding-left',\n pointsTo: 'padding'\n }, {\n name: 'padding-right',\n pointsTo: 'padding'\n }, {\n name: 'padding-top',\n pointsTo: 'padding'\n }, {\n name: 'padding-bottom',\n pointsTo: 'padding'\n }]; // list of property names\n\n styfn$2.propertyNames = props.map(function (p) {\n return p.name;\n }); // allow access of properties by name ( e.g. style.properties.height )\n\n for (var _i = 0; _i < props.length; _i++) {\n var prop = props[_i];\n props[prop.name] = prop; // allow lookup by name\n } // map aliases\n\n\n for (var _i2 = 0; _i2 < aliases.length; _i2++) {\n var alias = aliases[_i2];\n var pointsToProp = props[alias.pointsTo];\n var aliasProp = {\n name: alias.name,\n alias: true,\n pointsTo: pointsToProp\n }; // add alias prop for parsing\n\n props.push(aliasProp);\n props[alias.name] = aliasProp; // allow lookup by name\n }\n })();\n\n styfn$2.getDefaultProperty = function (name) {\n return this.getDefaultProperties()[name];\n };\n\n styfn$2.getDefaultProperties = function () {\n var _p = this._private;\n\n if (_p.defaultProperties != null) {\n return _p.defaultProperties;\n }\n\n var rawProps = extend({\n // core props\n 'selection-box-color': '#ddd',\n 'selection-box-opacity': 0.65,\n 'selection-box-border-color': '#aaa',\n 'selection-box-border-width': 1,\n 'active-bg-color': 'black',\n 'active-bg-opacity': 0.15,\n 'active-bg-size': 30,\n 'outside-texture-bg-color': '#000',\n 'outside-texture-bg-opacity': 0.125,\n // common node/edge props\n 'events': 'yes',\n 'text-events': 'no',\n 'text-valign': 'top',\n 'text-halign': 'center',\n 'text-justification': 'auto',\n 'line-height': 1,\n 'color': '#000',\n 'text-outline-color': '#000',\n 'text-outline-width': 0,\n 'text-outline-opacity': 1,\n 'text-opacity': 1,\n 'text-decoration': 'none',\n 'text-transform': 'none',\n 'text-wrap': 'none',\n 'text-overflow-wrap': 'whitespace',\n 'text-max-width': 9999,\n 'text-background-color': '#000',\n 'text-background-opacity': 0,\n 'text-background-shape': 'rectangle',\n 'text-background-padding': 0,\n 'text-border-opacity': 0,\n 'text-border-width': 0,\n 'text-border-style': 'solid',\n 'text-border-color': '#000',\n 'font-family': 'Helvetica Neue, Helvetica, sans-serif',\n 'font-style': 'normal',\n 'font-weight': 'normal',\n 'font-size': 16,\n 'min-zoomed-font-size': 0,\n 'text-rotation': 'none',\n 'source-text-rotation': 'none',\n 'target-text-rotation': 'none',\n 'visibility': 'visible',\n 'display': 'element',\n 'opacity': 1,\n 'z-compound-depth': 'auto',\n 'z-index-compare': 'auto',\n 'z-index': 0,\n 'label': '',\n 'text-margin-x': 0,\n 'text-margin-y': 0,\n 'source-label': '',\n 'source-text-offset': 0,\n 'source-text-margin-x': 0,\n 'source-text-margin-y': 0,\n 'target-label': '',\n 'target-text-offset': 0,\n 'target-text-margin-x': 0,\n 'target-text-margin-y': 0,\n 'overlay-opacity': 0,\n 'overlay-color': '#000',\n 'overlay-padding': 10,\n 'overlay-shape': 'round-rectangle',\n 'underlay-opacity': 0,\n 'underlay-color': '#000',\n 'underlay-padding': 10,\n 'underlay-shape': 'round-rectangle',\n 'transition-property': 'none',\n 'transition-duration': 0,\n 'transition-delay': 0,\n 'transition-timing-function': 'linear',\n // node props\n 'background-blacken': 0,\n 'background-color': '#999',\n 'background-fill': 'solid',\n 'background-opacity': 1,\n 'background-image': 'none',\n 'background-image-crossorigin': 'anonymous',\n 'background-image-opacity': 1,\n 'background-image-containment': 'inside',\n 'background-image-smoothing': 'yes',\n 'background-position-x': '50%',\n 'background-position-y': '50%',\n 'background-offset-x': 0,\n 'background-offset-y': 0,\n 'background-width-relative-to': 'include-padding',\n 'background-height-relative-to': 'include-padding',\n 'background-repeat': 'no-repeat',\n 'background-fit': 'none',\n 'background-clip': 'node',\n 'background-width': 'auto',\n 'background-height': 'auto',\n 'border-color': '#000',\n 'border-opacity': 1,\n 'border-width': 0,\n 'border-style': 'solid',\n 'height': 30,\n 'width': 30,\n 'shape': 'ellipse',\n 'shape-polygon-points': '-1, -1, 1, -1, 1, 1, -1, 1',\n 'bounds-expansion': 0,\n // node gradient\n 'background-gradient-direction': 'to-bottom',\n 'background-gradient-stop-colors': '#999',\n 'background-gradient-stop-positions': '0%',\n // ghost props\n 'ghost': 'no',\n 'ghost-offset-y': 0,\n 'ghost-offset-x': 0,\n 'ghost-opacity': 0,\n // compound props\n 'padding': 0,\n 'padding-relative-to': 'width',\n 'position': 'origin',\n 'compound-sizing-wrt-labels': 'include',\n 'min-width': 0,\n 'min-width-bias-left': 0,\n 'min-width-bias-right': 0,\n 'min-height': 0,\n 'min-height-bias-top': 0,\n 'min-height-bias-bottom': 0\n }, {\n // node pie bg\n 'pie-size': '100%'\n }, [{\n name: 'pie-{{i}}-background-color',\n value: 'black'\n }, {\n name: 'pie-{{i}}-background-size',\n value: '0%'\n }, {\n name: 'pie-{{i}}-background-opacity',\n value: 1\n }].reduce(function (css, prop) {\n for (var i = 1; i <= styfn$2.pieBackgroundN; i++) {\n var name = prop.name.replace('{{i}}', i);\n var val = prop.value;\n css[name] = val;\n }\n\n return css;\n }, {}), {\n // edge props\n 'line-style': 'solid',\n 'line-color': '#999',\n 'line-fill': 'solid',\n 'line-cap': 'butt',\n 'line-opacity': 1,\n 'line-gradient-stop-colors': '#999',\n 'line-gradient-stop-positions': '0%',\n 'control-point-step-size': 40,\n 'control-point-weights': 0.5,\n 'segment-weights': 0.5,\n 'segment-distances': 20,\n 'taxi-turn': '50%',\n 'taxi-turn-min-distance': 10,\n 'taxi-direction': 'auto',\n 'edge-distances': 'intersection',\n 'curve-style': 'haystack',\n 'haystack-radius': 0,\n 'arrow-scale': 1,\n 'loop-direction': '-45deg',\n 'loop-sweep': '-90deg',\n 'source-distance-from-node': 0,\n 'target-distance-from-node': 0,\n 'source-endpoint': 'outside-to-node',\n 'target-endpoint': 'outside-to-node',\n 'line-dash-pattern': [6, 3],\n 'line-dash-offset': 0\n }, [{\n name: 'arrow-shape',\n value: 'none'\n }, {\n name: 'arrow-color',\n value: '#999'\n }, {\n name: 'arrow-fill',\n value: 'filled'\n }].reduce(function (css, prop) {\n styfn$2.arrowPrefixes.forEach(function (prefix) {\n var name = prefix + '-' + prop.name;\n var val = prop.value;\n css[name] = val;\n });\n return css;\n }, {}));\n var parsedProps = {};\n\n for (var i = 0; i < this.properties.length; i++) {\n var prop = this.properties[i];\n\n if (prop.pointsTo) {\n continue;\n }\n\n var name = prop.name;\n var val = rawProps[name];\n var parsedProp = this.parse(name, val);\n parsedProps[name] = parsedProp;\n }\n\n _p.defaultProperties = parsedProps;\n return _p.defaultProperties;\n };\n\n styfn$2.addDefaultStylesheet = function () {\n this.selector(':parent').css({\n 'shape': 'rectangle',\n 'padding': 10,\n 'background-color': '#eee',\n 'border-color': '#ccc',\n 'border-width': 1\n }).selector('edge').css({\n 'width': 3\n }).selector(':loop').css({\n 'curve-style': 'bezier'\n }).selector('edge:compound').css({\n 'curve-style': 'bezier',\n 'source-endpoint': 'outside-to-line',\n 'target-endpoint': 'outside-to-line'\n }).selector(':selected').css({\n 'background-color': '#0169D9',\n 'line-color': '#0169D9',\n 'source-arrow-color': '#0169D9',\n 'target-arrow-color': '#0169D9',\n 'mid-source-arrow-color': '#0169D9',\n 'mid-target-arrow-color': '#0169D9'\n }).selector(':parent:selected').css({\n 'background-color': '#CCE1F9',\n 'border-color': '#aec8e5'\n }).selector(':active').css({\n 'overlay-color': 'black',\n 'overlay-padding': 10,\n 'overlay-opacity': 0.25\n });\n this.defaultLength = this.length;\n };\n\n var styfn$1 = {}; // a caching layer for property parsing\n\n styfn$1.parse = function (name, value, propIsBypass, propIsFlat) {\n var self = this; // function values can't be cached in all cases, and there isn't much benefit of caching them anyway\n\n if (fn$6(value)) {\n return self.parseImplWarn(name, value, propIsBypass, propIsFlat);\n }\n\n var flatKey = propIsFlat === 'mapping' || propIsFlat === true || propIsFlat === false || propIsFlat == null ? 'dontcare' : propIsFlat;\n var bypassKey = propIsBypass ? 't' : 'f';\n var valueKey = '' + value;\n var argHash = hashStrings(name, valueKey, bypassKey, flatKey);\n var propCache = self.propCache = self.propCache || [];\n var ret;\n\n if (!(ret = propCache[argHash])) {\n ret = propCache[argHash] = self.parseImplWarn(name, value, propIsBypass, propIsFlat);\n } // - bypasses can't be shared b/c the value can be changed by animations or otherwise overridden\n // - mappings can't be shared b/c mappings are per-element\n\n\n if (propIsBypass || propIsFlat === 'mapping') {\n // need a copy since props are mutated later in their lifecycles\n ret = copy(ret);\n\n if (ret) {\n ret.value = copy(ret.value); // because it could be an array, e.g. colour\n }\n }\n\n return ret;\n };\n\n styfn$1.parseImplWarn = function (name, value, propIsBypass, propIsFlat) {\n var prop = this.parseImpl(name, value, propIsBypass, propIsFlat);\n\n if (!prop && value != null) {\n warn(\"The style property `\".concat(name, \": \").concat(value, \"` is invalid\"));\n }\n\n if (prop && (prop.name === 'width' || prop.name === 'height') && value === 'label') {\n warn('The style value of `label` is deprecated for `' + prop.name + '`');\n }\n\n return prop;\n }; // parse a property; return null on invalid; return parsed property otherwise\n // fields :\n // - name : the name of the property\n // - value : the parsed, native-typed value of the property\n // - strValue : a string value that represents the property value in valid css\n // - bypass : true iff the property is a bypass property\n\n\n styfn$1.parseImpl = function (name, value, propIsBypass, propIsFlat) {\n var self = this;\n name = camel2dash(name); // make sure the property name is in dash form (e.g. 'property-name' not 'propertyName')\n\n var property = self.properties[name];\n var passedValue = value;\n var types = self.types;\n\n if (!property) {\n return null;\n } // return null on property of unknown name\n\n\n if (value === undefined) {\n return null;\n } // can't assign undefined\n // the property may be an alias\n\n\n if (property.alias) {\n property = property.pointsTo;\n name = property.name;\n }\n\n var valueIsString = string(value);\n\n if (valueIsString) {\n // trim the value to make parsing easier\n value = value.trim();\n }\n\n var type = property.type;\n\n if (!type) {\n return null;\n } // no type, no luck\n // check if bypass is null or empty string (i.e. indication to delete bypass property)\n\n\n if (propIsBypass && (value === '' || value === null)) {\n return {\n name: name,\n value: value,\n bypass: true,\n deleteBypass: true\n };\n } // check if value is a function used as a mapper\n\n\n if (fn$6(value)) {\n return {\n name: name,\n value: value,\n strValue: 'fn',\n mapped: types.fn,\n bypass: propIsBypass\n };\n } // check if value is mapped\n\n\n var data, mapData;\n\n if (!valueIsString || propIsFlat || value.length < 7 || value[1] !== 'a') ; else if (value.length >= 7 && value[0] === 'd' && (data = new RegExp(types.data.regex).exec(value))) {\n if (propIsBypass) {\n return false;\n } // mappers not allowed in bypass\n\n\n var mapped = types.data;\n return {\n name: name,\n value: data,\n strValue: '' + value,\n mapped: mapped,\n field: data[1],\n bypass: propIsBypass\n };\n } else if (value.length >= 10 && value[0] === 'm' && (mapData = new RegExp(types.mapData.regex).exec(value))) {\n if (propIsBypass) {\n return false;\n } // mappers not allowed in bypass\n\n\n if (type.multiple) {\n return false;\n } // impossible to map to num\n\n\n var _mapped = types.mapData; // we can map only if the type is a colour or a number\n\n if (!(type.color || type.number)) {\n return false;\n }\n\n var valueMin = this.parse(name, mapData[4]); // parse to validate\n\n if (!valueMin || valueMin.mapped) {\n return false;\n } // can't be invalid or mapped\n\n\n var valueMax = this.parse(name, mapData[5]); // parse to validate\n\n if (!valueMax || valueMax.mapped) {\n return false;\n } // can't be invalid or mapped\n // check if valueMin and valueMax are the same\n\n\n if (valueMin.pfValue === valueMax.pfValue || valueMin.strValue === valueMax.strValue) {\n warn('`' + name + ': ' + value + '` is not a valid mapper because the output range is zero; converting to `' + name + ': ' + valueMin.strValue + '`');\n return this.parse(name, valueMin.strValue); // can't make much of a mapper without a range\n } else if (type.color) {\n var c1 = valueMin.value;\n var c2 = valueMax.value;\n var same = c1[0] === c2[0] // red\n && c1[1] === c2[1] // green\n && c1[2] === c2[2] // blue\n && ( // optional alpha\n c1[3] === c2[3] // same alpha outright\n || (c1[3] == null || c1[3] === 1 // full opacity for colour 1?\n ) && (c2[3] == null || c2[3] === 1) // full opacity for colour 2?\n );\n\n if (same) {\n return false;\n } // can't make a mapper without a range\n\n }\n\n return {\n name: name,\n value: mapData,\n strValue: '' + value,\n mapped: _mapped,\n field: mapData[1],\n fieldMin: parseFloat(mapData[2]),\n // min & max are numeric\n fieldMax: parseFloat(mapData[3]),\n valueMin: valueMin.value,\n valueMax: valueMax.value,\n bypass: propIsBypass\n };\n }\n\n if (type.multiple && propIsFlat !== 'multiple') {\n var vals;\n\n if (valueIsString) {\n vals = value.split(/\\s+/);\n } else if (array(value)) {\n vals = value;\n } else {\n vals = [value];\n }\n\n if (type.evenMultiple && vals.length % 2 !== 0) {\n return null;\n }\n\n var valArr = [];\n var unitsArr = [];\n var pfValArr = [];\n var strVal = '';\n var hasEnum = false;\n\n for (var i = 0; i < vals.length; i++) {\n var p = self.parse(name, vals[i], propIsBypass, 'multiple');\n hasEnum = hasEnum || string(p.value);\n valArr.push(p.value);\n pfValArr.push(p.pfValue != null ? p.pfValue : p.value);\n unitsArr.push(p.units);\n strVal += (i > 0 ? ' ' : '') + p.strValue;\n }\n\n if (type.validate && !type.validate(valArr, unitsArr)) {\n return null;\n }\n\n if (type.singleEnum && hasEnum) {\n if (valArr.length === 1 && string(valArr[0])) {\n return {\n name: name,\n value: valArr[0],\n strValue: valArr[0],\n bypass: propIsBypass\n };\n } else {\n return null;\n }\n }\n\n return {\n name: name,\n value: valArr,\n pfValue: pfValArr,\n strValue: strVal,\n bypass: propIsBypass,\n units: unitsArr\n };\n } // several types also allow enums\n\n\n var checkEnums = function checkEnums() {\n for (var _i = 0; _i < type.enums.length; _i++) {\n var en = type.enums[_i];\n\n if (en === value) {\n return {\n name: name,\n value: value,\n strValue: '' + value,\n bypass: propIsBypass\n };\n }\n }\n\n return null;\n }; // check the type and return the appropriate object\n\n\n if (type.number) {\n var units;\n var implicitUnits = 'px'; // not set => px\n\n if (type.units) {\n // use specified units if set\n units = type.units;\n }\n\n if (type.implicitUnits) {\n implicitUnits = type.implicitUnits;\n }\n\n if (!type.unitless) {\n if (valueIsString) {\n var unitsRegex = 'px|em' + (type.allowPercent ? '|\\\\%' : '');\n\n if (units) {\n unitsRegex = units;\n } // only allow explicit units if so set\n\n\n var match = value.match('^(' + number + ')(' + unitsRegex + ')?' + '$');\n\n if (match) {\n value = match[1];\n units = match[2] || implicitUnits;\n }\n } else if (!units || type.implicitUnits) {\n units = implicitUnits; // implicitly px if unspecified\n }\n }\n\n value = parseFloat(value); // if not a number and enums not allowed, then the value is invalid\n\n if (isNaN(value) && type.enums === undefined) {\n return null;\n } // check if this number type also accepts special keywords in place of numbers\n // (i.e. `left`, `auto`, etc)\n\n\n if (isNaN(value) && type.enums !== undefined) {\n value = passedValue;\n return checkEnums();\n } // check if value must be an integer\n\n\n if (type.integer && !integer(value)) {\n return null;\n } // check value is within range\n\n\n if (type.min !== undefined && (value < type.min || type.strictMin && value === type.min) || type.max !== undefined && (value > type.max || type.strictMax && value === type.max)) {\n return null;\n }\n\n var ret = {\n name: name,\n value: value,\n strValue: '' + value + (units ? units : ''),\n units: units,\n bypass: propIsBypass\n }; // normalise value in pixels\n\n if (type.unitless || units !== 'px' && units !== 'em') {\n ret.pfValue = value;\n } else {\n ret.pfValue = units === 'px' || !units ? value : this.getEmSizeInPixels() * value;\n } // normalise value in ms\n\n\n if (units === 'ms' || units === 's') {\n ret.pfValue = units === 'ms' ? value : 1000 * value;\n } // normalise value in rad\n\n\n if (units === 'deg' || units === 'rad') {\n ret.pfValue = units === 'rad' ? value : deg2rad(value);\n } // normalize value in %\n\n\n if (units === '%') {\n ret.pfValue = value / 100;\n }\n\n return ret;\n } else if (type.propList) {\n var props = [];\n var propsStr = '' + value;\n\n if (propsStr === 'none') ; else {\n // go over each prop\n var propsSplit = propsStr.split(/\\s*,\\s*|\\s+/);\n\n for (var _i2 = 0; _i2 < propsSplit.length; _i2++) {\n var propName = propsSplit[_i2].trim();\n\n if (self.properties[propName]) {\n props.push(propName);\n } else {\n warn('`' + propName + '` is not a valid property name');\n }\n }\n\n if (props.length === 0) {\n return null;\n }\n }\n\n return {\n name: name,\n value: props,\n strValue: props.length === 0 ? 'none' : props.join(' '),\n bypass: propIsBypass\n };\n } else if (type.color) {\n var tuple = color2tuple(value);\n\n if (!tuple) {\n return null;\n }\n\n return {\n name: name,\n value: tuple,\n pfValue: tuple,\n strValue: 'rgb(' + tuple[0] + ',' + tuple[1] + ',' + tuple[2] + ')',\n // n.b. no spaces b/c of multiple support\n bypass: propIsBypass\n };\n } else if (type.regex || type.regexes) {\n // first check enums\n if (type.enums) {\n var enumProp = checkEnums();\n\n if (enumProp) {\n return enumProp;\n }\n }\n\n var regexes = type.regexes ? type.regexes : [type.regex];\n\n for (var _i3 = 0; _i3 < regexes.length; _i3++) {\n var regex = new RegExp(regexes[_i3]); // make a regex from the type string\n\n var m = regex.exec(value);\n\n if (m) {\n // regex matches\n return {\n name: name,\n value: type.singleRegexMatchValue ? m[1] : m,\n strValue: '' + value,\n bypass: propIsBypass\n };\n }\n }\n\n return null; // didn't match any\n } else if (type.string) {\n // just return\n return {\n name: name,\n value: '' + value,\n strValue: '' + value,\n bypass: propIsBypass\n };\n } else if (type.enums) {\n // check enums last because it's a combo type in others\n return checkEnums();\n } else {\n return null; // not a type we can handle\n }\n };\n\n var Style = function Style(cy) {\n if (!(this instanceof Style)) {\n return new Style(cy);\n }\n\n if (!core(cy)) {\n error('A style must have a core reference');\n return;\n }\n\n this._private = {\n cy: cy,\n coreStyle: {}\n };\n this.length = 0;\n this.resetToDefault();\n };\n\n var styfn = Style.prototype;\n\n styfn.instanceString = function () {\n return 'style';\n }; // remove all contexts\n\n\n styfn.clear = function () {\n var _p = this._private;\n var cy = _p.cy;\n var eles = cy.elements();\n\n for (var i = 0; i < this.length; i++) {\n this[i] = undefined;\n }\n\n this.length = 0;\n _p.contextStyles = {};\n _p.propDiffs = {};\n this.cleanElements(eles, true);\n eles.forEach(function (ele) {\n var ele_p = ele[0]._private;\n ele_p.styleDirty = true;\n ele_p.appliedInitStyle = false;\n });\n return this; // chaining\n };\n\n styfn.resetToDefault = function () {\n this.clear();\n this.addDefaultStylesheet();\n return this;\n }; // builds a style object for the 'core' selector\n\n\n styfn.core = function (propName) {\n return this._private.coreStyle[propName] || this.getDefaultProperty(propName);\n }; // create a new context from the specified selector string and switch to that context\n\n\n styfn.selector = function (selectorStr) {\n // 'core' is a special case and does not need a selector\n var selector = selectorStr === 'core' ? null : new Selector(selectorStr);\n var i = this.length++; // new context means new index\n\n this[i] = {\n selector: selector,\n properties: [],\n mappedProperties: [],\n index: i\n };\n return this; // chaining\n }; // add one or many css rules to the current context\n\n\n styfn.css = function () {\n var self = this;\n var args = arguments;\n\n if (args.length === 1) {\n var map = args[0];\n\n for (var i = 0; i < self.properties.length; i++) {\n var prop = self.properties[i];\n var mapVal = map[prop.name];\n\n if (mapVal === undefined) {\n mapVal = map[dash2camel(prop.name)];\n }\n\n if (mapVal !== undefined) {\n this.cssRule(prop.name, mapVal);\n }\n }\n } else if (args.length === 2) {\n this.cssRule(args[0], args[1]);\n } // do nothing if args are invalid\n\n\n return this; // chaining\n };\n\n styfn.style = styfn.css; // add a single css rule to the current context\n\n styfn.cssRule = function (name, value) {\n // name-value pair\n var property = this.parse(name, value); // add property to current context if valid\n\n if (property) {\n var i = this.length - 1;\n this[i].properties.push(property);\n this[i].properties[property.name] = property; // allow access by name as well\n\n if (property.name.match(/pie-(\\d+)-background-size/) && property.value) {\n this._private.hasPie = true;\n }\n\n if (property.mapped) {\n this[i].mappedProperties.push(property);\n } // add to core style if necessary\n\n\n var currentSelectorIsCore = !this[i].selector;\n\n if (currentSelectorIsCore) {\n this._private.coreStyle[property.name] = property;\n }\n }\n\n return this; // chaining\n };\n\n styfn.append = function (style) {\n if (stylesheet(style)) {\n style.appendToStyle(this);\n } else if (array(style)) {\n this.appendFromJson(style);\n } else if (string(style)) {\n this.appendFromString(style);\n } // you probably wouldn't want to append a Style, since you'd duplicate the default parts\n\n\n return this;\n }; // static function\n\n\n Style.fromJson = function (cy, json) {\n var style = new Style(cy);\n style.fromJson(json);\n return style;\n };\n\n Style.fromString = function (cy, string) {\n return new Style(cy).fromString(string);\n };\n\n [styfn$8, styfn$7, styfn$6, styfn$5, styfn$4, styfn$3, styfn$2, styfn$1].forEach(function (props) {\n extend(styfn, props);\n });\n Style.types = styfn.types;\n Style.properties = styfn.properties;\n Style.propertyGroups = styfn.propertyGroups;\n Style.propertyGroupNames = styfn.propertyGroupNames;\n Style.propertyGroupKeys = styfn.propertyGroupKeys;\n\n var corefn$2 = {\n style: function style(newStyle) {\n if (newStyle) {\n var s = this.setStyle(newStyle);\n s.update();\n }\n\n return this._private.style;\n },\n setStyle: function setStyle(style) {\n var _p = this._private;\n\n if (stylesheet(style)) {\n _p.style = style.generateStyle(this);\n } else if (array(style)) {\n _p.style = Style.fromJson(this, style);\n } else if (string(style)) {\n _p.style = Style.fromString(this, style);\n } else {\n _p.style = Style(this);\n }\n\n return _p.style;\n },\n // e.g. cy.data() changed => recalc ele mappers\n updateStyle: function updateStyle() {\n this.mutableElements().updateStyle(); // just send to all eles\n }\n };\n\n var defaultSelectionType = 'single';\n var corefn$1 = {\n autolock: function autolock(bool) {\n if (bool !== undefined) {\n this._private.autolock = bool ? true : false;\n } else {\n return this._private.autolock;\n }\n\n return this; // chaining\n },\n autoungrabify: function autoungrabify(bool) {\n if (bool !== undefined) {\n this._private.autoungrabify = bool ? true : false;\n } else {\n return this._private.autoungrabify;\n }\n\n return this; // chaining\n },\n autounselectify: function autounselectify(bool) {\n if (bool !== undefined) {\n this._private.autounselectify = bool ? true : false;\n } else {\n return this._private.autounselectify;\n }\n\n return this; // chaining\n },\n selectionType: function selectionType(selType) {\n var _p = this._private;\n\n if (_p.selectionType == null) {\n _p.selectionType = defaultSelectionType;\n }\n\n if (selType !== undefined) {\n if (selType === 'additive' || selType === 'single') {\n _p.selectionType = selType;\n }\n } else {\n return _p.selectionType;\n }\n\n return this;\n },\n panningEnabled: function panningEnabled(bool) {\n if (bool !== undefined) {\n this._private.panningEnabled = bool ? true : false;\n } else {\n return this._private.panningEnabled;\n }\n\n return this; // chaining\n },\n userPanningEnabled: function userPanningEnabled(bool) {\n if (bool !== undefined) {\n this._private.userPanningEnabled = bool ? true : false;\n } else {\n return this._private.userPanningEnabled;\n }\n\n return this; // chaining\n },\n zoomingEnabled: function zoomingEnabled(bool) {\n if (bool !== undefined) {\n this._private.zoomingEnabled = bool ? true : false;\n } else {\n return this._private.zoomingEnabled;\n }\n\n return this; // chaining\n },\n userZoomingEnabled: function userZoomingEnabled(bool) {\n if (bool !== undefined) {\n this._private.userZoomingEnabled = bool ? true : false;\n } else {\n return this._private.userZoomingEnabled;\n }\n\n return this; // chaining\n },\n boxSelectionEnabled: function boxSelectionEnabled(bool) {\n if (bool !== undefined) {\n this._private.boxSelectionEnabled = bool ? true : false;\n } else {\n return this._private.boxSelectionEnabled;\n }\n\n return this; // chaining\n },\n pan: function pan() {\n var args = arguments;\n var pan = this._private.pan;\n var dim, val, dims, x, y;\n\n switch (args.length) {\n case 0:\n // .pan()\n return pan;\n\n case 1:\n if (string(args[0])) {\n // .pan('x')\n dim = args[0];\n return pan[dim];\n } else if (plainObject(args[0])) {\n // .pan({ x: 0, y: 100 })\n if (!this._private.panningEnabled) {\n return this;\n }\n\n dims = args[0];\n x = dims.x;\n y = dims.y;\n\n if (number$1(x)) {\n pan.x = x;\n }\n\n if (number$1(y)) {\n pan.y = y;\n }\n\n this.emit('pan viewport');\n }\n\n break;\n\n case 2:\n // .pan('x', 100)\n if (!this._private.panningEnabled) {\n return this;\n }\n\n dim = args[0];\n val = args[1];\n\n if ((dim === 'x' || dim === 'y') && number$1(val)) {\n pan[dim] = val;\n }\n\n this.emit('pan viewport');\n break;\n // invalid\n }\n\n this.notify('viewport');\n return this; // chaining\n },\n panBy: function panBy(arg0, arg1) {\n var args = arguments;\n var pan = this._private.pan;\n var dim, val, dims, x, y;\n\n if (!this._private.panningEnabled) {\n return this;\n }\n\n switch (args.length) {\n case 1:\n if (plainObject(arg0)) {\n // .panBy({ x: 0, y: 100 })\n dims = args[0];\n x = dims.x;\n y = dims.y;\n\n if (number$1(x)) {\n pan.x += x;\n }\n\n if (number$1(y)) {\n pan.y += y;\n }\n\n this.emit('pan viewport');\n }\n\n break;\n\n case 2:\n // .panBy('x', 100)\n dim = arg0;\n val = arg1;\n\n if ((dim === 'x' || dim === 'y') && number$1(val)) {\n pan[dim] += val;\n }\n\n this.emit('pan viewport');\n break;\n // invalid\n }\n\n this.notify('viewport');\n return this; // chaining\n },\n fit: function fit(elements, padding) {\n var viewportState = this.getFitViewport(elements, padding);\n\n if (viewportState) {\n var _p = this._private;\n _p.zoom = viewportState.zoom;\n _p.pan = viewportState.pan;\n this.emit('pan zoom viewport');\n this.notify('viewport');\n }\n\n return this; // chaining\n },\n getFitViewport: function getFitViewport(elements, padding) {\n if (number$1(elements) && padding === undefined) {\n // elements is optional\n padding = elements;\n elements = undefined;\n }\n\n if (!this._private.panningEnabled || !this._private.zoomingEnabled) {\n return;\n }\n\n var bb;\n\n if (string(elements)) {\n var sel = elements;\n elements = this.$(sel);\n } else if (boundingBox(elements)) {\n // assume bb\n var bbe = elements;\n bb = {\n x1: bbe.x1,\n y1: bbe.y1,\n x2: bbe.x2,\n y2: bbe.y2\n };\n bb.w = bb.x2 - bb.x1;\n bb.h = bb.y2 - bb.y1;\n } else if (!elementOrCollection(elements)) {\n elements = this.mutableElements();\n }\n\n if (elementOrCollection(elements) && elements.empty()) {\n return;\n } // can't fit to nothing\n\n\n bb = bb || elements.boundingBox();\n var w = this.width();\n var h = this.height();\n var zoom;\n padding = number$1(padding) ? padding : 0;\n\n if (!isNaN(w) && !isNaN(h) && w > 0 && h > 0 && !isNaN(bb.w) && !isNaN(bb.h) && bb.w > 0 && bb.h > 0) {\n zoom = Math.min((w - 2 * padding) / bb.w, (h - 2 * padding) / bb.h); // crop zoom\n\n zoom = zoom > this._private.maxZoom ? this._private.maxZoom : zoom;\n zoom = zoom < this._private.minZoom ? this._private.minZoom : zoom;\n var pan = {\n // now pan to middle\n x: (w - zoom * (bb.x1 + bb.x2)) / 2,\n y: (h - zoom * (bb.y1 + bb.y2)) / 2\n };\n return {\n zoom: zoom,\n pan: pan\n };\n }\n\n return;\n },\n zoomRange: function zoomRange(min, max) {\n var _p = this._private;\n\n if (max == null) {\n var opts = min;\n min = opts.min;\n max = opts.max;\n }\n\n if (number$1(min) && number$1(max) && min <= max) {\n _p.minZoom = min;\n _p.maxZoom = max;\n } else if (number$1(min) && max === undefined && min <= _p.maxZoom) {\n _p.minZoom = min;\n } else if (number$1(max) && min === undefined && max >= _p.minZoom) {\n _p.maxZoom = max;\n }\n\n return this;\n },\n minZoom: function minZoom(zoom) {\n if (zoom === undefined) {\n return this._private.minZoom;\n } else {\n return this.zoomRange({\n min: zoom\n });\n }\n },\n maxZoom: function maxZoom(zoom) {\n if (zoom === undefined) {\n return this._private.maxZoom;\n } else {\n return this.zoomRange({\n max: zoom\n });\n }\n },\n getZoomedViewport: function getZoomedViewport(params) {\n var _p = this._private;\n var currentPan = _p.pan;\n var currentZoom = _p.zoom;\n var pos; // in rendered px\n\n var zoom;\n var bail = false;\n\n if (!_p.zoomingEnabled) {\n // zooming disabled\n bail = true;\n }\n\n if (number$1(params)) {\n // then set the zoom\n zoom = params;\n } else if (plainObject(params)) {\n // then zoom about a point\n zoom = params.level;\n\n if (params.position != null) {\n pos = modelToRenderedPosition(params.position, currentZoom, currentPan);\n } else if (params.renderedPosition != null) {\n pos = params.renderedPosition;\n }\n\n if (pos != null && !_p.panningEnabled) {\n // panning disabled\n bail = true;\n }\n } // crop zoom\n\n\n zoom = zoom > _p.maxZoom ? _p.maxZoom : zoom;\n zoom = zoom < _p.minZoom ? _p.minZoom : zoom; // can't zoom with invalid params\n\n if (bail || !number$1(zoom) || zoom === currentZoom || pos != null && (!number$1(pos.x) || !number$1(pos.y))) {\n return null;\n }\n\n if (pos != null) {\n // set zoom about position\n var pan1 = currentPan;\n var zoom1 = currentZoom;\n var zoom2 = zoom;\n var pan2 = {\n x: -zoom2 / zoom1 * (pos.x - pan1.x) + pos.x,\n y: -zoom2 / zoom1 * (pos.y - pan1.y) + pos.y\n };\n return {\n zoomed: true,\n panned: true,\n zoom: zoom2,\n pan: pan2\n };\n } else {\n // just set the zoom\n return {\n zoomed: true,\n panned: false,\n zoom: zoom,\n pan: currentPan\n };\n }\n },\n zoom: function zoom(params) {\n if (params === undefined) {\n // get\n return this._private.zoom;\n } else {\n // set\n var vp = this.getZoomedViewport(params);\n var _p = this._private;\n\n if (vp == null || !vp.zoomed) {\n return this;\n }\n\n _p.zoom = vp.zoom;\n\n if (vp.panned) {\n _p.pan.x = vp.pan.x;\n _p.pan.y = vp.pan.y;\n }\n\n this.emit('zoom' + (vp.panned ? ' pan' : '') + ' viewport');\n this.notify('viewport');\n return this; // chaining\n }\n },\n viewport: function viewport(opts) {\n var _p = this._private;\n var zoomDefd = true;\n var panDefd = true;\n var events = []; // to trigger\n\n var zoomFailed = false;\n var panFailed = false;\n\n if (!opts) {\n return this;\n }\n\n if (!number$1(opts.zoom)) {\n zoomDefd = false;\n }\n\n if (!plainObject(opts.pan)) {\n panDefd = false;\n }\n\n if (!zoomDefd && !panDefd) {\n return this;\n }\n\n if (zoomDefd) {\n var z = opts.zoom;\n\n if (z < _p.minZoom || z > _p.maxZoom || !_p.zoomingEnabled) {\n zoomFailed = true;\n } else {\n _p.zoom = z;\n events.push('zoom');\n }\n }\n\n if (panDefd && (!zoomFailed || !opts.cancelOnFailedZoom) && _p.panningEnabled) {\n var p = opts.pan;\n\n if (number$1(p.x)) {\n _p.pan.x = p.x;\n panFailed = false;\n }\n\n if (number$1(p.y)) {\n _p.pan.y = p.y;\n panFailed = false;\n }\n\n if (!panFailed) {\n events.push('pan');\n }\n }\n\n if (events.length > 0) {\n events.push('viewport');\n this.emit(events.join(' '));\n this.notify('viewport');\n }\n\n return this; // chaining\n },\n center: function center(elements) {\n var pan = this.getCenterPan(elements);\n\n if (pan) {\n this._private.pan = pan;\n this.emit('pan viewport');\n this.notify('viewport');\n }\n\n return this; // chaining\n },\n getCenterPan: function getCenterPan(elements, zoom) {\n if (!this._private.panningEnabled) {\n return;\n }\n\n if (string(elements)) {\n var selector = elements;\n elements = this.mutableElements().filter(selector);\n } else if (!elementOrCollection(elements)) {\n elements = this.mutableElements();\n }\n\n if (elements.length === 0) {\n return;\n } // can't centre pan to nothing\n\n\n var bb = elements.boundingBox();\n var w = this.width();\n var h = this.height();\n zoom = zoom === undefined ? this._private.zoom : zoom;\n var pan = {\n // middle\n x: (w - zoom * (bb.x1 + bb.x2)) / 2,\n y: (h - zoom * (bb.y1 + bb.y2)) / 2\n };\n return pan;\n },\n reset: function reset() {\n if (!this._private.panningEnabled || !this._private.zoomingEnabled) {\n return this;\n }\n\n this.viewport({\n pan: {\n x: 0,\n y: 0\n },\n zoom: 1\n });\n return this; // chaining\n },\n invalidateSize: function invalidateSize() {\n this._private.sizeCache = null;\n },\n size: function size() {\n var _p = this._private;\n var container = _p.container;\n var cy = this;\n return _p.sizeCache = _p.sizeCache || (container ? function () {\n var style = cy.window().getComputedStyle(container);\n\n var val = function val(name) {\n return parseFloat(style.getPropertyValue(name));\n };\n\n return {\n width: container.clientWidth - val('padding-left') - val('padding-right'),\n height: container.clientHeight - val('padding-top') - val('padding-bottom')\n };\n }() : {\n // fallback if no container (not 0 b/c can be used for dividing etc)\n width: 1,\n height: 1\n });\n },\n width: function width() {\n return this.size().width;\n },\n height: function height() {\n return this.size().height;\n },\n extent: function extent() {\n var pan = this._private.pan;\n var zoom = this._private.zoom;\n var rb = this.renderedExtent();\n var b = {\n x1: (rb.x1 - pan.x) / zoom,\n x2: (rb.x2 - pan.x) / zoom,\n y1: (rb.y1 - pan.y) / zoom,\n y2: (rb.y2 - pan.y) / zoom\n };\n b.w = b.x2 - b.x1;\n b.h = b.y2 - b.y1;\n return b;\n },\n renderedExtent: function renderedExtent() {\n var width = this.width();\n var height = this.height();\n return {\n x1: 0,\n y1: 0,\n x2: width,\n y2: height,\n w: width,\n h: height\n };\n },\n multiClickDebounceTime: function multiClickDebounceTime(_int) {\n if (_int) this._private.multiClickDebounceTime = _int;else return this._private.multiClickDebounceTime;\n return this; // chaining\n }\n }; // aliases\n\n corefn$1.centre = corefn$1.center; // backwards compatibility\n\n corefn$1.autolockNodes = corefn$1.autolock;\n corefn$1.autoungrabifyNodes = corefn$1.autoungrabify;\n\n var fn = {\n data: define.data({\n field: 'data',\n bindingEvent: 'data',\n allowBinding: true,\n allowSetting: true,\n settingEvent: 'data',\n settingTriggersEvent: true,\n triggerFnName: 'trigger',\n allowGetting: true,\n updateStyle: true\n }),\n removeData: define.removeData({\n field: 'data',\n event: 'data',\n triggerFnName: 'trigger',\n triggerEvent: true,\n updateStyle: true\n }),\n scratch: define.data({\n field: 'scratch',\n bindingEvent: 'scratch',\n allowBinding: true,\n allowSetting: true,\n settingEvent: 'scratch',\n settingTriggersEvent: true,\n triggerFnName: 'trigger',\n allowGetting: true,\n updateStyle: true\n }),\n removeScratch: define.removeData({\n field: 'scratch',\n event: 'scratch',\n triggerFnName: 'trigger',\n triggerEvent: true,\n updateStyle: true\n })\n }; // aliases\n\n fn.attr = fn.data;\n fn.removeAttr = fn.removeData;\n\n var Core = function Core(opts) {\n var cy = this;\n opts = extend({}, opts);\n var container = opts.container; // allow for passing a wrapped jquery object\n // e.g. cytoscape({ container: $('#cy') })\n\n if (container && !htmlElement(container) && htmlElement(container[0])) {\n container = container[0];\n }\n\n var reg = container ? container._cyreg : null; // e.g. already registered some info (e.g. readies) via jquery\n\n reg = reg || {};\n\n if (reg && reg.cy) {\n reg.cy.destroy();\n reg = {}; // old instance => replace reg completely\n }\n\n var readies = reg.readies = reg.readies || [];\n\n if (container) {\n container._cyreg = reg;\n } // make sure container assoc'd reg points to this cy\n\n\n reg.cy = cy;\n var head = _window !== undefined && container !== undefined && !opts.headless;\n var options = opts;\n options.layout = extend({\n name: head ? 'grid' : 'null'\n }, options.layout);\n options.renderer = extend({\n name: head ? 'canvas' : 'null'\n }, options.renderer);\n\n var defVal = function defVal(def, val, altVal) {\n if (val !== undefined) {\n return val;\n } else if (altVal !== undefined) {\n return altVal;\n } else {\n return def;\n }\n };\n\n var _p = this._private = {\n container: container,\n // html dom ele container\n ready: false,\n // whether ready has been triggered\n options: options,\n // cached options\n elements: new Collection(this),\n // elements in the graph\n listeners: [],\n // list of listeners\n aniEles: new Collection(this),\n // elements being animated\n data: options.data || {},\n // data for the core\n scratch: {},\n // scratch object for core\n layout: null,\n renderer: null,\n destroyed: false,\n // whether destroy was called\n notificationsEnabled: true,\n // whether notifications are sent to the renderer\n minZoom: 1e-50,\n maxZoom: 1e50,\n zoomingEnabled: defVal(true, options.zoomingEnabled),\n userZoomingEnabled: defVal(true, options.userZoomingEnabled),\n panningEnabled: defVal(true, options.panningEnabled),\n userPanningEnabled: defVal(true, options.userPanningEnabled),\n boxSelectionEnabled: defVal(true, options.boxSelectionEnabled),\n autolock: defVal(false, options.autolock, options.autolockNodes),\n autoungrabify: defVal(false, options.autoungrabify, options.autoungrabifyNodes),\n autounselectify: defVal(false, options.autounselectify),\n styleEnabled: options.styleEnabled === undefined ? head : options.styleEnabled,\n zoom: number$1(options.zoom) ? options.zoom : 1,\n pan: {\n x: plainObject(options.pan) && number$1(options.pan.x) ? options.pan.x : 0,\n y: plainObject(options.pan) && number$1(options.pan.y) ? options.pan.y : 0\n },\n animation: {\n // object for currently-running animations\n current: [],\n queue: []\n },\n hasCompoundNodes: false,\n multiClickDebounceTime: defVal(250, options.multiClickDebounceTime)\n };\n\n this.createEmitter(); // set selection type\n\n this.selectionType(options.selectionType); // init zoom bounds\n\n this.zoomRange({\n min: options.minZoom,\n max: options.maxZoom\n });\n\n var loadExtData = function loadExtData(extData, next) {\n var anyIsPromise = extData.some(promise);\n\n if (anyIsPromise) {\n return Promise$1.all(extData).then(next); // load all data asynchronously, then exec rest of init\n } else {\n next(extData); // exec synchronously for convenience\n }\n }; // start with the default stylesheet so we have something before loading an external stylesheet\n\n\n if (_p.styleEnabled) {\n cy.setStyle([]);\n } // create the renderer\n\n\n var rendererOptions = extend({}, options, options.renderer); // allow rendering hints in top level options\n\n cy.initRenderer(rendererOptions);\n\n var setElesAndLayout = function setElesAndLayout(elements, onload, ondone) {\n cy.notifications(false); // remove old elements\n\n var oldEles = cy.mutableElements();\n\n if (oldEles.length > 0) {\n oldEles.remove();\n }\n\n if (elements != null) {\n if (plainObject(elements) || array(elements)) {\n cy.add(elements);\n }\n }\n\n cy.one('layoutready', function (e) {\n cy.notifications(true);\n cy.emit(e); // we missed this event by turning notifications off, so pass it on\n\n cy.one('load', onload);\n cy.emitAndNotify('load');\n }).one('layoutstop', function () {\n cy.one('done', ondone);\n cy.emit('done');\n });\n var layoutOpts = extend({}, cy._private.options.layout);\n layoutOpts.eles = cy.elements();\n cy.layout(layoutOpts).run();\n };\n\n loadExtData([options.style, options.elements], function (thens) {\n var initStyle = thens[0];\n var initEles = thens[1]; // init style\n\n if (_p.styleEnabled) {\n cy.style().append(initStyle);\n } // initial load\n\n\n setElesAndLayout(initEles, function () {\n // onready\n cy.startAnimationLoop();\n _p.ready = true; // if a ready callback is specified as an option, the bind it\n\n if (fn$6(options.ready)) {\n cy.on('ready', options.ready);\n } // bind all the ready handlers registered before creating this instance\n\n\n for (var i = 0; i < readies.length; i++) {\n var fn = readies[i];\n cy.on('ready', fn);\n }\n\n if (reg) {\n reg.readies = [];\n } // clear b/c we've bound them all and don't want to keep it around in case a new core uses the same div etc\n\n\n cy.emit('ready');\n }, options.done);\n });\n };\n\n var corefn = Core.prototype; // short alias\n\n extend(corefn, {\n instanceString: function instanceString() {\n return 'core';\n },\n isReady: function isReady() {\n return this._private.ready;\n },\n destroyed: function destroyed() {\n return this._private.destroyed;\n },\n ready: function ready(fn) {\n if (this.isReady()) {\n this.emitter().emit('ready', [], fn); // just calls fn as though triggered via ready event\n } else {\n this.on('ready', fn);\n }\n\n return this;\n },\n destroy: function destroy() {\n var cy = this;\n if (cy.destroyed()) return;\n cy.stopAnimationLoop();\n cy.destroyRenderer();\n this.emit('destroy');\n cy._private.destroyed = true;\n return cy;\n },\n hasElementWithId: function hasElementWithId(id) {\n return this._private.elements.hasElementWithId(id);\n },\n getElementById: function getElementById(id) {\n return this._private.elements.getElementById(id);\n },\n hasCompoundNodes: function hasCompoundNodes() {\n return this._private.hasCompoundNodes;\n },\n headless: function headless() {\n return this._private.renderer.isHeadless();\n },\n styleEnabled: function styleEnabled() {\n return this._private.styleEnabled;\n },\n addToPool: function addToPool(eles) {\n this._private.elements.merge(eles);\n\n return this; // chaining\n },\n removeFromPool: function removeFromPool(eles) {\n this._private.elements.unmerge(eles);\n\n return this;\n },\n container: function container() {\n return this._private.container || null;\n },\n window: function window() {\n var container = this._private.container;\n if (container == null) return _window;\n var ownerDocument = this._private.container.ownerDocument;\n\n if (ownerDocument === undefined || ownerDocument == null) {\n return _window;\n }\n\n return ownerDocument.defaultView || _window;\n },\n mount: function mount(container) {\n if (container == null) {\n return;\n }\n\n var cy = this;\n var _p = cy._private;\n var options = _p.options;\n\n if (!htmlElement(container) && htmlElement(container[0])) {\n container = container[0];\n }\n\n cy.stopAnimationLoop();\n cy.destroyRenderer();\n _p.container = container;\n _p.styleEnabled = true;\n cy.invalidateSize();\n cy.initRenderer(extend({}, options, options.renderer, {\n // allow custom renderer name to be re-used, otherwise use canvas\n name: options.renderer.name === 'null' ? 'canvas' : options.renderer.name\n }));\n cy.startAnimationLoop();\n cy.style(options.style);\n cy.emit('mount');\n return cy;\n },\n unmount: function unmount() {\n var cy = this;\n cy.stopAnimationLoop();\n cy.destroyRenderer();\n cy.initRenderer({\n name: 'null'\n });\n cy.emit('unmount');\n return cy;\n },\n options: function options() {\n return copy(this._private.options);\n },\n json: function json(obj) {\n var cy = this;\n var _p = cy._private;\n var eles = cy.mutableElements();\n\n var getFreshRef = function getFreshRef(ele) {\n return cy.getElementById(ele.id());\n };\n\n if (plainObject(obj)) {\n // set\n cy.startBatch();\n\n if (obj.elements) {\n var idInJson = {};\n\n var updateEles = function updateEles(jsons, gr) {\n var toAdd = [];\n var toMod = [];\n\n for (var i = 0; i < jsons.length; i++) {\n var json = jsons[i];\n\n if (!json.data.id) {\n warn('cy.json() cannot handle elements without an ID attribute');\n continue;\n }\n\n var id = '' + json.data.id; // id must be string\n\n var ele = cy.getElementById(id);\n idInJson[id] = true;\n\n if (ele.length !== 0) {\n // existing element should be updated\n toMod.push({\n ele: ele,\n json: json\n });\n } else {\n // otherwise should be added\n if (gr) {\n json.group = gr;\n toAdd.push(json);\n } else {\n toAdd.push(json);\n }\n }\n }\n\n cy.add(toAdd);\n\n for (var _i = 0; _i < toMod.length; _i++) {\n var _toMod$_i = toMod[_i],\n _ele = _toMod$_i.ele,\n _json = _toMod$_i.json;\n\n _ele.json(_json);\n }\n };\n\n if (array(obj.elements)) {\n // elements: []\n updateEles(obj.elements);\n } else {\n // elements: { nodes: [], edges: [] }\n var grs = ['nodes', 'edges'];\n\n for (var i = 0; i < grs.length; i++) {\n var gr = grs[i];\n var elements = obj.elements[gr];\n\n if (array(elements)) {\n updateEles(elements, gr);\n }\n }\n }\n\n var parentsToRemove = cy.collection();\n eles.filter(function (ele) {\n return !idInJson[ele.id()];\n }).forEach(function (ele) {\n if (ele.isParent()) {\n parentsToRemove.merge(ele);\n } else {\n ele.remove();\n }\n }); // so that children are not removed w/parent\n\n parentsToRemove.forEach(function (ele) {\n return ele.children().move({\n parent: null\n });\n }); // intermediate parents may be moved by prior line, so make sure we remove by fresh refs\n\n parentsToRemove.forEach(function (ele) {\n return getFreshRef(ele).remove();\n });\n }\n\n if (obj.style) {\n cy.style(obj.style);\n }\n\n if (obj.zoom != null && obj.zoom !== _p.zoom) {\n cy.zoom(obj.zoom);\n }\n\n if (obj.pan) {\n if (obj.pan.x !== _p.pan.x || obj.pan.y !== _p.pan.y) {\n cy.pan(obj.pan);\n }\n }\n\n if (obj.data) {\n cy.data(obj.data);\n }\n\n var fields = ['minZoom', 'maxZoom', 'zoomingEnabled', 'userZoomingEnabled', 'panningEnabled', 'userPanningEnabled', 'boxSelectionEnabled', 'autolock', 'autoungrabify', 'autounselectify', 'multiClickDebounceTime'];\n\n for (var _i2 = 0; _i2 < fields.length; _i2++) {\n var f = fields[_i2];\n\n if (obj[f] != null) {\n cy[f](obj[f]);\n }\n }\n\n cy.endBatch();\n return this; // chaining\n } else {\n // get\n var flat = !!obj;\n var json = {};\n\n if (flat) {\n json.elements = this.elements().map(function (ele) {\n return ele.json();\n });\n } else {\n json.elements = {};\n eles.forEach(function (ele) {\n var group = ele.group();\n\n if (!json.elements[group]) {\n json.elements[group] = [];\n }\n\n json.elements[group].push(ele.json());\n });\n }\n\n if (this._private.styleEnabled) {\n json.style = cy.style().json();\n }\n\n json.data = copy(cy.data());\n var options = _p.options;\n json.zoomingEnabled = _p.zoomingEnabled;\n json.userZoomingEnabled = _p.userZoomingEnabled;\n json.zoom = _p.zoom;\n json.minZoom = _p.minZoom;\n json.maxZoom = _p.maxZoom;\n json.panningEnabled = _p.panningEnabled;\n json.userPanningEnabled = _p.userPanningEnabled;\n json.pan = copy(_p.pan);\n json.boxSelectionEnabled = _p.boxSelectionEnabled;\n json.renderer = copy(options.renderer);\n json.hideEdgesOnViewport = options.hideEdgesOnViewport;\n json.textureOnViewport = options.textureOnViewport;\n json.wheelSensitivity = options.wheelSensitivity;\n json.motionBlur = options.motionBlur;\n json.multiClickDebounceTime = options.multiClickDebounceTime;\n return json;\n }\n }\n });\n corefn.$id = corefn.getElementById;\n [corefn$9, corefn$8, elesfn, corefn$7, corefn$6, corefn$5, corefn$4, corefn$3, corefn$2, corefn$1, fn].forEach(function (props) {\n extend(corefn, props);\n });\n\n /* eslint-disable no-unused-vars */\n\n var defaults$7 = {\n fit: true,\n // whether to fit the viewport to the graph\n directed: false,\n // whether the tree is directed downwards (or edges can point in any direction if false)\n padding: 30,\n // padding on fit\n circle: false,\n // put depths in concentric circles if true, put depths top down if false\n grid: false,\n // whether to create an even grid into which the DAG is placed (circle:false only)\n spacingFactor: 1.75,\n // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)\n boundingBox: undefined,\n // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }\n avoidOverlap: true,\n // prevents node overlap, may overflow boundingBox if not enough space\n nodeDimensionsIncludeLabels: false,\n // Excludes the label when calculating node bounding boxes for the layout algorithm\n roots: undefined,\n // the roots of the trees\n depthSort: undefined,\n // a sorting function to order nodes at equal depth. e.g. function(a, b){ return a.data('weight') - b.data('weight') }\n animate: false,\n // whether to transition the node positions\n animationDuration: 500,\n // duration of animation in ms if enabled\n animationEasing: undefined,\n // easing of animation if enabled,\n animateFilter: function animateFilter(node, i) {\n return true;\n },\n // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts\n ready: undefined,\n // callback on layoutready\n stop: undefined,\n // callback on layoutstop\n transform: function transform(node, position) {\n return position;\n } // transform a given node position. Useful for changing flow direction in discrete layouts\n\n };\n var deprecatedOptionDefaults = {\n maximal: false,\n // whether to shift nodes down their natural BFS depths in order to avoid upwards edges (DAGS only); setting acyclic to true sets maximal to true also\n acyclic: false // whether the tree is acyclic and thus a node could be shifted (due to the maximal option) multiple times without causing an infinite loop; setting to true sets maximal to true also; if you are uncertain whether a tree is acyclic, set to false to avoid potential infinite loops\n\n };\n /* eslint-enable */\n\n var getInfo = function getInfo(ele) {\n return ele.scratch('breadthfirst');\n };\n\n var setInfo = function setInfo(ele, obj) {\n return ele.scratch('breadthfirst', obj);\n };\n\n function BreadthFirstLayout(options) {\n this.options = extend({}, defaults$7, deprecatedOptionDefaults, options);\n }\n\n BreadthFirstLayout.prototype.run = function () {\n var params = this.options;\n var options = params;\n var cy = params.cy;\n var eles = options.eles;\n var nodes = eles.nodes().filter(function (n) {\n return !n.isParent();\n });\n var graph = eles;\n var directed = options.directed;\n var maximal = options.acyclic || options.maximal || options.maximalAdjustments > 0; // maximalAdjustments for compat. w/ old code; also, setting acyclic to true sets maximal to true\n\n var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : {\n x1: 0,\n y1: 0,\n w: cy.width(),\n h: cy.height()\n });\n var roots;\n\n if (elementOrCollection(options.roots)) {\n roots = options.roots;\n } else if (array(options.roots)) {\n var rootsArray = [];\n\n for (var i = 0; i < options.roots.length; i++) {\n var id = options.roots[i];\n var ele = cy.getElementById(id);\n rootsArray.push(ele);\n }\n\n roots = cy.collection(rootsArray);\n } else if (string(options.roots)) {\n roots = cy.$(options.roots);\n } else {\n if (directed) {\n roots = nodes.roots();\n } else {\n var components = eles.components();\n roots = cy.collection();\n\n var _loop = function _loop(_i) {\n var comp = components[_i];\n var maxDegree = comp.maxDegree(false);\n var compRoots = comp.filter(function (ele) {\n return ele.degree(false) === maxDegree;\n });\n roots = roots.add(compRoots);\n };\n\n for (var _i = 0; _i < components.length; _i++) {\n _loop(_i);\n }\n }\n }\n\n var depths = [];\n var foundByBfs = {};\n\n var addToDepth = function addToDepth(ele, d) {\n if (depths[d] == null) {\n depths[d] = [];\n }\n\n var i = depths[d].length;\n depths[d].push(ele);\n setInfo(ele, {\n index: i,\n depth: d\n });\n };\n\n var changeDepth = function changeDepth(ele, newDepth) {\n var _getInfo = getInfo(ele),\n depth = _getInfo.depth,\n index = _getInfo.index;\n\n depths[depth][index] = null;\n addToDepth(ele, newDepth);\n }; // find the depths of the nodes\n\n\n graph.bfs({\n roots: roots,\n directed: options.directed,\n visit: function visit(node, edge, pNode, i, depth) {\n var ele = node[0];\n var id = ele.id();\n addToDepth(ele, depth);\n foundByBfs[id] = true;\n }\n }); // check for nodes not found by bfs\n\n var orphanNodes = [];\n\n for (var _i2 = 0; _i2 < nodes.length; _i2++) {\n var _ele = nodes[_i2];\n\n if (foundByBfs[_ele.id()]) {\n continue;\n } else {\n orphanNodes.push(_ele);\n }\n } // assign the nodes a depth and index\n\n\n var assignDepthsAt = function assignDepthsAt(i) {\n var eles = depths[i];\n\n for (var j = 0; j < eles.length; j++) {\n var _ele2 = eles[j];\n\n if (_ele2 == null) {\n eles.splice(j, 1);\n j--;\n continue;\n }\n\n setInfo(_ele2, {\n depth: i,\n index: j\n });\n }\n };\n\n var assignDepths = function assignDepths() {\n for (var _i3 = 0; _i3 < depths.length; _i3++) {\n assignDepthsAt(_i3);\n }\n };\n\n var adjustMaximally = function adjustMaximally(ele, shifted) {\n var eInfo = getInfo(ele);\n var incomers = ele.incomers().filter(function (el) {\n return el.isNode() && eles.has(el);\n });\n var maxDepth = -1;\n var id = ele.id();\n\n for (var k = 0; k < incomers.length; k++) {\n var incmr = incomers[k];\n var iInfo = getInfo(incmr);\n maxDepth = Math.max(maxDepth, iInfo.depth);\n }\n\n if (eInfo.depth <= maxDepth) {\n if (!options.acyclic && shifted[id]) {\n return null;\n }\n\n var newDepth = maxDepth + 1;\n changeDepth(ele, newDepth);\n shifted[id] = newDepth;\n return true;\n }\n\n return false;\n }; // for the directed case, try to make the edges all go down (i.e. depth i => depth i + 1)\n\n\n if (directed && maximal) {\n var Q = [];\n var shifted = {};\n\n var enqueue = function enqueue(n) {\n return Q.push(n);\n };\n\n var dequeue = function dequeue() {\n return Q.shift();\n };\n\n nodes.forEach(function (n) {\n return Q.push(n);\n });\n\n while (Q.length > 0) {\n var _ele3 = dequeue();\n\n var didShift = adjustMaximally(_ele3, shifted);\n\n if (didShift) {\n _ele3.outgoers().filter(function (el) {\n return el.isNode() && eles.has(el);\n }).forEach(enqueue);\n } else if (didShift === null) {\n warn('Detected double maximal shift for node `' + _ele3.id() + '`. Bailing maximal adjustment due to cycle. Use `options.maximal: true` only on DAGs.');\n break; // exit on failure\n }\n }\n }\n\n assignDepths(); // clear holes\n // find min distance we need to leave between nodes\n\n var minDistance = 0;\n\n if (options.avoidOverlap) {\n for (var _i4 = 0; _i4 < nodes.length; _i4++) {\n var n = nodes[_i4];\n var nbb = n.layoutDimensions(options);\n var w = nbb.w;\n var h = nbb.h;\n minDistance = Math.max(minDistance, w, h);\n }\n } // get the weighted percent for an element based on its connectivity to other levels\n\n\n var cachedWeightedPercent = {};\n\n var getWeightedPercent = function getWeightedPercent(ele) {\n if (cachedWeightedPercent[ele.id()]) {\n return cachedWeightedPercent[ele.id()];\n }\n\n var eleDepth = getInfo(ele).depth;\n var neighbors = ele.neighborhood();\n var percent = 0;\n var samples = 0;\n\n for (var _i5 = 0; _i5 < neighbors.length; _i5++) {\n var neighbor = neighbors[_i5];\n\n if (neighbor.isEdge() || neighbor.isParent() || !nodes.has(neighbor)) {\n continue;\n }\n\n var bf = getInfo(neighbor);\n\n if (bf == null) {\n continue;\n }\n\n var index = bf.index;\n var depth = bf.depth; // unassigned neighbours shouldn't affect the ordering\n\n if (index == null || depth == null) {\n continue;\n }\n\n var nDepth = depths[depth].length;\n\n if (depth < eleDepth) {\n // only get influenced by elements above\n percent += index / nDepth;\n samples++;\n }\n }\n\n samples = Math.max(1, samples);\n percent = percent / samples;\n\n if (samples === 0) {\n // put lone nodes at the start\n percent = 0;\n }\n\n cachedWeightedPercent[ele.id()] = percent;\n return percent;\n }; // rearrange the indices in each depth level based on connectivity\n\n\n var sortFn = function sortFn(a, b) {\n var apct = getWeightedPercent(a);\n var bpct = getWeightedPercent(b);\n var diff = apct - bpct;\n\n if (diff === 0) {\n return ascending(a.id(), b.id()); // make sure sort doesn't have don't-care comparisons\n } else {\n return diff;\n }\n };\n\n if (options.depthSort !== undefined) {\n sortFn = options.depthSort;\n } // sort each level to make connected nodes closer\n\n\n for (var _i6 = 0; _i6 < depths.length; _i6++) {\n depths[_i6].sort(sortFn);\n\n assignDepthsAt(_i6);\n } // assign orphan nodes to a new top-level depth\n\n\n var orphanDepth = [];\n\n for (var _i7 = 0; _i7 < orphanNodes.length; _i7++) {\n orphanDepth.push(orphanNodes[_i7]);\n }\n\n depths.unshift(orphanDepth);\n assignDepths();\n var biggestDepthSize = 0;\n\n for (var _i8 = 0; _i8 < depths.length; _i8++) {\n biggestDepthSize = Math.max(depths[_i8].length, biggestDepthSize);\n }\n\n var center = {\n x: bb.x1 + bb.w / 2,\n y: bb.x1 + bb.h / 2\n };\n var maxDepthSize = depths.reduce(function (max, eles) {\n return Math.max(max, eles.length);\n }, 0);\n\n var getPosition = function getPosition(ele) {\n var _getInfo2 = getInfo(ele),\n depth = _getInfo2.depth,\n index = _getInfo2.index;\n\n var depthSize = depths[depth].length;\n var distanceX = Math.max(bb.w / ((options.grid ? maxDepthSize : depthSize) + 1), minDistance);\n var distanceY = Math.max(bb.h / (depths.length + 1), minDistance);\n var radiusStepSize = Math.min(bb.w / 2 / depths.length, bb.h / 2 / depths.length);\n radiusStepSize = Math.max(radiusStepSize, minDistance);\n\n if (!options.circle) {\n var epos = {\n x: center.x + (index + 1 - (depthSize + 1) / 2) * distanceX,\n y: (depth + 1) * distanceY\n };\n return epos;\n } else {\n var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize / 2 : 0);\n var theta = 2 * Math.PI / depths[depth].length * index;\n\n if (depth === 0 && depths[0].length === 1) {\n radius = 1;\n }\n\n return {\n x: center.x + radius * Math.cos(theta),\n y: center.y + radius * Math.sin(theta)\n };\n }\n };\n\n eles.nodes().layoutPositions(this, options, getPosition);\n return this; // chaining\n };\n\n var defaults$6 = {\n fit: true,\n // whether to fit the viewport to the graph\n padding: 30,\n // the padding on fit\n boundingBox: undefined,\n // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }\n avoidOverlap: true,\n // prevents node overlap, may overflow boundingBox and radius if not enough space\n nodeDimensionsIncludeLabels: false,\n // Excludes the label when calculating node bounding boxes for the layout algorithm\n spacingFactor: undefined,\n // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up\n radius: undefined,\n // the radius of the circle\n startAngle: 3 / 2 * Math.PI,\n // where nodes start in radians\n sweep: undefined,\n // how many radians should be between the first and last node (defaults to full circle)\n clockwise: true,\n // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false)\n sort: undefined,\n // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') }\n animate: false,\n // whether to transition the node positions\n animationDuration: 500,\n // duration of animation in ms if enabled\n animationEasing: undefined,\n // easing of animation if enabled\n animateFilter: function animateFilter(node, i) {\n return true;\n },\n // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts\n ready: undefined,\n // callback on layoutready\n stop: undefined,\n // callback on layoutstop\n transform: function transform(node, position) {\n return position;\n } // transform a given node position. Useful for changing flow direction in discrete layouts \n\n };\n\n function CircleLayout(options) {\n this.options = extend({}, defaults$6, options);\n }\n\n CircleLayout.prototype.run = function () {\n var params = this.options;\n var options = params;\n var cy = params.cy;\n var eles = options.eles;\n var clockwise = options.counterclockwise !== undefined ? !options.counterclockwise : options.clockwise;\n var nodes = eles.nodes().not(':parent');\n\n if (options.sort) {\n nodes = nodes.sort(options.sort);\n }\n\n var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : {\n x1: 0,\n y1: 0,\n w: cy.width(),\n h: cy.height()\n });\n var center = {\n x: bb.x1 + bb.w / 2,\n y: bb.y1 + bb.h / 2\n };\n var sweep = options.sweep === undefined ? 2 * Math.PI - 2 * Math.PI / nodes.length : options.sweep;\n var dTheta = sweep / Math.max(1, nodes.length - 1);\n var r;\n var minDistance = 0;\n\n for (var i = 0; i < nodes.length; i++) {\n var n = nodes[i];\n var nbb = n.layoutDimensions(options);\n var w = nbb.w;\n var h = nbb.h;\n minDistance = Math.max(minDistance, w, h);\n }\n\n if (number$1(options.radius)) {\n r = options.radius;\n } else if (nodes.length <= 1) {\n r = 0;\n } else {\n r = Math.min(bb.h, bb.w) / 2 - minDistance;\n } // calculate the radius\n\n\n if (nodes.length > 1 && options.avoidOverlap) {\n // but only if more than one node (can't overlap)\n minDistance *= 1.75; // just to have some nice spacing\n\n var dcos = Math.cos(dTheta) - Math.cos(0);\n var dsin = Math.sin(dTheta) - Math.sin(0);\n var rMin = Math.sqrt(minDistance * minDistance / (dcos * dcos + dsin * dsin)); // s.t. no nodes overlapping\n\n r = Math.max(rMin, r);\n }\n\n var getPos = function getPos(ele, i) {\n var theta = options.startAngle + i * dTheta * (clockwise ? 1 : -1);\n var rx = r * Math.cos(theta);\n var ry = r * Math.sin(theta);\n var pos = {\n x: center.x + rx,\n y: center.y + ry\n };\n return pos;\n };\n\n eles.nodes().layoutPositions(this, options, getPos);\n return this; // chaining\n };\n\n var defaults$5 = {\n fit: true,\n // whether to fit the viewport to the graph\n padding: 30,\n // the padding on fit\n startAngle: 3 / 2 * Math.PI,\n // where nodes start in radians\n sweep: undefined,\n // how many radians should be between the first and last node (defaults to full circle)\n clockwise: true,\n // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false)\n equidistant: false,\n // whether levels have an equal radial distance betwen them, may cause bounding box overflow\n minNodeSpacing: 10,\n // min spacing between outside of nodes (used for radius adjustment)\n boundingBox: undefined,\n // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }\n avoidOverlap: true,\n // prevents node overlap, may overflow boundingBox if not enough space\n nodeDimensionsIncludeLabels: false,\n // Excludes the label when calculating node bounding boxes for the layout algorithm\n height: undefined,\n // height of layout area (overrides container height)\n width: undefined,\n // width of layout area (overrides container width)\n spacingFactor: undefined,\n // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up\n concentric: function concentric(node) {\n // returns numeric value for each node, placing higher nodes in levels towards the centre\n return node.degree();\n },\n levelWidth: function levelWidth(nodes) {\n // the variation of concentric values in each level\n return nodes.maxDegree() / 4;\n },\n animate: false,\n // whether to transition the node positions\n animationDuration: 500,\n // duration of animation in ms if enabled\n animationEasing: undefined,\n // easing of animation if enabled\n animateFilter: function animateFilter(node, i) {\n return true;\n },\n // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts\n ready: undefined,\n // callback on layoutready\n stop: undefined,\n // callback on layoutstop\n transform: function transform(node, position) {\n return position;\n } // transform a given node position. Useful for changing flow direction in discrete layouts\n\n };\n\n function ConcentricLayout(options) {\n this.options = extend({}, defaults$5, options);\n }\n\n ConcentricLayout.prototype.run = function () {\n var params = this.options;\n var options = params;\n var clockwise = options.counterclockwise !== undefined ? !options.counterclockwise : options.clockwise;\n var cy = params.cy;\n var eles = options.eles;\n var nodes = eles.nodes().not(':parent');\n var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : {\n x1: 0,\n y1: 0,\n w: cy.width(),\n h: cy.height()\n });\n var center = {\n x: bb.x1 + bb.w / 2,\n y: bb.y1 + bb.h / 2\n };\n var nodeValues = []; // { node, value }\n\n var maxNodeSize = 0;\n\n for (var i = 0; i < nodes.length; i++) {\n var node = nodes[i];\n var value = void 0; // calculate the node value\n\n value = options.concentric(node);\n nodeValues.push({\n value: value,\n node: node\n }); // for style mapping\n\n node._private.scratch.concentric = value;\n } // in case we used the `concentric` in style\n\n\n nodes.updateStyle(); // calculate max size now based on potentially updated mappers\n\n for (var _i = 0; _i < nodes.length; _i++) {\n var _node = nodes[_i];\n\n var nbb = _node.layoutDimensions(options);\n\n maxNodeSize = Math.max(maxNodeSize, nbb.w, nbb.h);\n } // sort node values in descreasing order\n\n\n nodeValues.sort(function (a, b) {\n return b.value - a.value;\n });\n var levelWidth = options.levelWidth(nodes); // put the values into levels\n\n var levels = [[]];\n var currentLevel = levels[0];\n\n for (var _i2 = 0; _i2 < nodeValues.length; _i2++) {\n var val = nodeValues[_i2];\n\n if (currentLevel.length > 0) {\n var diff = Math.abs(currentLevel[0].value - val.value);\n\n if (diff >= levelWidth) {\n currentLevel = [];\n levels.push(currentLevel);\n }\n }\n\n currentLevel.push(val);\n } // create positions from levels\n\n\n var minDist = maxNodeSize + options.minNodeSpacing; // min dist between nodes\n\n if (!options.avoidOverlap) {\n // then strictly constrain to bb\n var firstLvlHasMulti = levels.length > 0 && levels[0].length > 1;\n var maxR = Math.min(bb.w, bb.h) / 2 - minDist;\n var rStep = maxR / (levels.length + firstLvlHasMulti ? 1 : 0);\n minDist = Math.min(minDist, rStep);\n } // find the metrics for each level\n\n\n var r = 0;\n\n for (var _i3 = 0; _i3 < levels.length; _i3++) {\n var level = levels[_i3];\n var sweep = options.sweep === undefined ? 2 * Math.PI - 2 * Math.PI / level.length : options.sweep;\n var dTheta = level.dTheta = sweep / Math.max(1, level.length - 1); // calculate the radius\n\n if (level.length > 1 && options.avoidOverlap) {\n // but only if more than one node (can't overlap)\n var dcos = Math.cos(dTheta) - Math.cos(0);\n var dsin = Math.sin(dTheta) - Math.sin(0);\n var rMin = Math.sqrt(minDist * minDist / (dcos * dcos + dsin * dsin)); // s.t. no nodes overlapping\n\n r = Math.max(rMin, r);\n }\n\n level.r = r;\n r += minDist;\n }\n\n if (options.equidistant) {\n var rDeltaMax = 0;\n var _r = 0;\n\n for (var _i4 = 0; _i4 < levels.length; _i4++) {\n var _level = levels[_i4];\n var rDelta = _level.r - _r;\n rDeltaMax = Math.max(rDeltaMax, rDelta);\n }\n\n _r = 0;\n\n for (var _i5 = 0; _i5 < levels.length; _i5++) {\n var _level2 = levels[_i5];\n\n if (_i5 === 0) {\n _r = _level2.r;\n }\n\n _level2.r = _r;\n _r += rDeltaMax;\n }\n } // calculate the node positions\n\n\n var pos = {}; // id => position\n\n for (var _i6 = 0; _i6 < levels.length; _i6++) {\n var _level3 = levels[_i6];\n var _dTheta = _level3.dTheta;\n var _r2 = _level3.r;\n\n for (var j = 0; j < _level3.length; j++) {\n var _val = _level3[j];\n var theta = options.startAngle + (clockwise ? 1 : -1) * _dTheta * j;\n var p = {\n x: center.x + _r2 * Math.cos(theta),\n y: center.y + _r2 * Math.sin(theta)\n };\n pos[_val.node.id()] = p;\n }\n } // position the nodes\n\n\n eles.nodes().layoutPositions(this, options, function (ele) {\n var id = ele.id();\n return pos[id];\n });\n return this; // chaining\n };\n\n /*\n The CoSE layout was written by Gerardo Huck.\n https://www.linkedin.com/in/gerardohuck/\n\n Based on the following article:\n http://dl.acm.org/citation.cfm?id=1498047\n\n Modifications tracked on Github.\n */\n var DEBUG;\n /**\n * @brief : default layout options\n */\n\n var defaults$4 = {\n // Called on `layoutready`\n ready: function ready() {},\n // Called on `layoutstop`\n stop: function stop() {},\n // Whether to animate while running the layout\n // true : Animate continuously as the layout is running\n // false : Just show the end result\n // 'end' : Animate with the end result, from the initial positions to the end positions\n animate: true,\n // Easing of the animation for animate:'end'\n animationEasing: undefined,\n // The duration of the animation for animate:'end'\n animationDuration: undefined,\n // A function that determines whether the node should be animated\n // All nodes animated by default on animate enabled\n // Non-animated nodes are positioned immediately when the layout starts\n animateFilter: function animateFilter(node, i) {\n return true;\n },\n // The layout animates only after this many milliseconds for animate:true\n // (prevents flashing on fast runs)\n animationThreshold: 250,\n // Number of iterations between consecutive screen positions update\n refresh: 20,\n // Whether to fit the network view after when done\n fit: true,\n // Padding on fit\n padding: 30,\n // Constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }\n boundingBox: undefined,\n // Excludes the label when calculating node bounding boxes for the layout algorithm\n nodeDimensionsIncludeLabels: false,\n // Randomize the initial positions of the nodes (true) or use existing positions (false)\n randomize: false,\n // Extra spacing between components in non-compound graphs\n componentSpacing: 40,\n // Node repulsion (non overlapping) multiplier\n nodeRepulsion: function nodeRepulsion(node) {\n return 2048;\n },\n // Node repulsion (overlapping) multiplier\n nodeOverlap: 4,\n // Ideal edge (non nested) length\n idealEdgeLength: function idealEdgeLength(edge) {\n return 32;\n },\n // Divisor to compute edge forces\n edgeElasticity: function edgeElasticity(edge) {\n return 32;\n },\n // Nesting factor (multiplier) to compute ideal edge length for nested edges\n nestingFactor: 1.2,\n // Gravity force (constant)\n gravity: 1,\n // Maximum number of iterations to perform\n numIter: 1000,\n // Initial temperature (maximum node displacement)\n initialTemp: 1000,\n // Cooling factor (how the temperature is reduced between consecutive iterations\n coolingFactor: 0.99,\n // Lower temperature threshold (below this point the layout will end)\n minTemp: 1.0\n };\n /**\n * @brief : constructor\n * @arg options : object containing layout options\n */\n\n function CoseLayout(options) {\n this.options = extend({}, defaults$4, options);\n this.options.layout = this;\n }\n /**\n * @brief : runs the layout\n */\n\n\n CoseLayout.prototype.run = function () {\n var options = this.options;\n var cy = options.cy;\n var layout = this;\n layout.stopped = false;\n\n if (options.animate === true || options.animate === false) {\n layout.emit({\n type: 'layoutstart',\n layout: layout\n });\n } // Set DEBUG - Global variable\n\n\n if (true === options.debug) {\n DEBUG = true;\n } else {\n DEBUG = false;\n } // Initialize layout info\n\n\n var layoutInfo = createLayoutInfo(cy, layout, options); // Show LayoutInfo contents if debugging\n\n if (DEBUG) {\n printLayoutInfo(layoutInfo);\n } // If required, randomize node positions\n\n\n if (options.randomize) {\n randomizePositions(layoutInfo);\n }\n\n var startTime = performanceNow();\n\n var refresh = function refresh() {\n refreshPositions(layoutInfo, cy, options); // Fit the graph if necessary\n\n if (true === options.fit) {\n cy.fit(options.padding);\n }\n };\n\n var mainLoop = function mainLoop(i) {\n if (layout.stopped || i >= options.numIter) {\n // logDebug(\"Layout manually stopped. Stopping computation in step \" + i);\n return false;\n } // Do one step in the phisical simulation\n\n\n step(layoutInfo, options); // Update temperature\n\n layoutInfo.temperature = layoutInfo.temperature * options.coolingFactor; // logDebug(\"New temperature: \" + layoutInfo.temperature);\n\n if (layoutInfo.temperature < options.minTemp) {\n // logDebug(\"Temperature drop below minimum threshold. Stopping computation in step \" + i);\n return false;\n }\n\n return true;\n };\n\n var done = function done() {\n if (options.animate === true || options.animate === false) {\n refresh(); // Layout has finished\n\n layout.one('layoutstop', options.stop);\n layout.emit({\n type: 'layoutstop',\n layout: layout\n });\n } else {\n var nodes = options.eles.nodes();\n var getScaledPos = getScaleInBoundsFn(layoutInfo, options, nodes);\n nodes.layoutPositions(layout, options, getScaledPos);\n }\n };\n\n var i = 0;\n var loopRet = true;\n\n if (options.animate === true) {\n var frame = function frame() {\n var f = 0;\n\n while (loopRet && f < options.refresh) {\n loopRet = mainLoop(i);\n i++;\n f++;\n }\n\n if (!loopRet) {\n // it's done\n separateComponents(layoutInfo, options);\n done();\n } else {\n var now = performanceNow();\n\n if (now - startTime >= options.animationThreshold) {\n refresh();\n }\n\n requestAnimationFrame(frame);\n }\n };\n\n frame();\n } else {\n while (loopRet) {\n loopRet = mainLoop(i);\n i++;\n }\n\n separateComponents(layoutInfo, options);\n done();\n }\n\n return this; // chaining\n };\n /**\n * @brief : called on continuous layouts to stop them before they finish\n */\n\n\n CoseLayout.prototype.stop = function () {\n this.stopped = true;\n\n if (this.thread) {\n this.thread.stop();\n }\n\n this.emit('layoutstop');\n return this; // chaining\n };\n\n CoseLayout.prototype.destroy = function () {\n if (this.thread) {\n this.thread.stop();\n }\n\n return this; // chaining\n };\n /**\n * @brief : Creates an object which is contains all the data\n * used in the layout process\n * @arg cy : cytoscape.js object\n * @return : layoutInfo object initialized\n */\n\n\n var createLayoutInfo = function createLayoutInfo(cy, layout, options) {\n // Shortcut\n var edges = options.eles.edges();\n var nodes = options.eles.nodes();\n var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : {\n x1: 0,\n y1: 0,\n w: cy.width(),\n h: cy.height()\n });\n var layoutInfo = {\n isCompound: cy.hasCompoundNodes(),\n layoutNodes: [],\n idToIndex: {},\n nodeSize: nodes.size(),\n graphSet: [],\n indexToGraph: [],\n layoutEdges: [],\n edgeSize: edges.size(),\n temperature: options.initialTemp,\n clientWidth: bb.w,\n clientHeight: bb.h,\n boundingBox: bb\n };\n var components = options.eles.components();\n var id2cmptId = {};\n\n for (var i = 0; i < components.length; i++) {\n var component = components[i];\n\n for (var j = 0; j < component.length; j++) {\n var node = component[j];\n id2cmptId[node.id()] = i;\n }\n } // Iterate over all nodes, creating layout nodes\n\n\n for (var i = 0; i < layoutInfo.nodeSize; i++) {\n var n = nodes[i];\n var nbb = n.layoutDimensions(options);\n var tempNode = {};\n tempNode.isLocked = n.locked();\n tempNode.id = n.data('id');\n tempNode.parentId = n.data('parent');\n tempNode.cmptId = id2cmptId[n.id()];\n tempNode.children = [];\n tempNode.positionX = n.position('x');\n tempNode.positionY = n.position('y');\n tempNode.offsetX = 0;\n tempNode.offsetY = 0;\n tempNode.height = nbb.w;\n tempNode.width = nbb.h;\n tempNode.maxX = tempNode.positionX + tempNode.width / 2;\n tempNode.minX = tempNode.positionX - tempNode.width / 2;\n tempNode.maxY = tempNode.positionY + tempNode.height / 2;\n tempNode.minY = tempNode.positionY - tempNode.height / 2;\n tempNode.padLeft = parseFloat(n.style('padding'));\n tempNode.padRight = parseFloat(n.style('padding'));\n tempNode.padTop = parseFloat(n.style('padding'));\n tempNode.padBottom = parseFloat(n.style('padding')); // forces\n\n tempNode.nodeRepulsion = fn$6(options.nodeRepulsion) ? options.nodeRepulsion(n) : options.nodeRepulsion; // Add new node\n\n layoutInfo.layoutNodes.push(tempNode); // Add entry to id-index map\n\n layoutInfo.idToIndex[tempNode.id] = i;\n } // Inline implementation of a queue, used for traversing the graph in BFS order\n\n\n var queue = [];\n var start = 0; // Points to the start the queue\n\n var end = -1; // Points to the end of the queue\n\n var tempGraph = []; // Second pass to add child information and\n // initialize queue for hierarchical traversal\n\n for (var i = 0; i < layoutInfo.nodeSize; i++) {\n var n = layoutInfo.layoutNodes[i];\n var p_id = n.parentId; // Check if node n has a parent node\n\n if (null != p_id) {\n // Add node Id to parent's list of children\n layoutInfo.layoutNodes[layoutInfo.idToIndex[p_id]].children.push(n.id);\n } else {\n // If a node doesn't have a parent, then it's in the root graph\n queue[++end] = n.id;\n tempGraph.push(n.id);\n }\n } // Add root graph to graphSet\n\n\n layoutInfo.graphSet.push(tempGraph); // Traverse the graph, level by level,\n\n while (start <= end) {\n // Get the node to visit and remove it from queue\n var node_id = queue[start++];\n var node_ix = layoutInfo.idToIndex[node_id];\n var node = layoutInfo.layoutNodes[node_ix];\n var children = node.children;\n\n if (children.length > 0) {\n // Add children nodes as a new graph to graph set\n layoutInfo.graphSet.push(children); // Add children to que queue to be visited\n\n for (var i = 0; i < children.length; i++) {\n queue[++end] = children[i];\n }\n }\n } // Create indexToGraph map\n\n\n for (var i = 0; i < layoutInfo.graphSet.length; i++) {\n var graph = layoutInfo.graphSet[i];\n\n for (var j = 0; j < graph.length; j++) {\n var index = layoutInfo.idToIndex[graph[j]];\n layoutInfo.indexToGraph[index] = i;\n }\n } // Iterate over all edges, creating Layout Edges\n\n\n for (var i = 0; i < layoutInfo.edgeSize; i++) {\n var e = edges[i];\n var tempEdge = {};\n tempEdge.id = e.data('id');\n tempEdge.sourceId = e.data('source');\n tempEdge.targetId = e.data('target'); // Compute ideal length\n\n var idealLength = fn$6(options.idealEdgeLength) ? options.idealEdgeLength(e) : options.idealEdgeLength;\n var elasticity = fn$6(options.edgeElasticity) ? options.edgeElasticity(e) : options.edgeElasticity; // Check if it's an inter graph edge\n\n var sourceIx = layoutInfo.idToIndex[tempEdge.sourceId];\n var targetIx = layoutInfo.idToIndex[tempEdge.targetId];\n var sourceGraph = layoutInfo.indexToGraph[sourceIx];\n var targetGraph = layoutInfo.indexToGraph[targetIx];\n\n if (sourceGraph != targetGraph) {\n // Find lowest common graph ancestor\n var lca = findLCA(tempEdge.sourceId, tempEdge.targetId, layoutInfo); // Compute sum of node depths, relative to lca graph\n\n var lcaGraph = layoutInfo.graphSet[lca];\n var depth = 0; // Source depth\n\n var tempNode = layoutInfo.layoutNodes[sourceIx];\n\n while (-1 === lcaGraph.indexOf(tempNode.id)) {\n tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]];\n depth++;\n } // Target depth\n\n\n tempNode = layoutInfo.layoutNodes[targetIx];\n\n while (-1 === lcaGraph.indexOf(tempNode.id)) {\n tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]];\n depth++;\n } // logDebug('LCA of nodes ' + tempEdge.sourceId + ' and ' + tempEdge.targetId +\n // \". Index: \" + lca + \" Contents: \" + lcaGraph.toString() +\n // \". Depth: \" + depth);\n // Update idealLength\n\n\n idealLength *= depth * options.nestingFactor;\n }\n\n tempEdge.idealLength = idealLength;\n tempEdge.elasticity = elasticity;\n layoutInfo.layoutEdges.push(tempEdge);\n } // Finally, return layoutInfo object\n\n\n return layoutInfo;\n };\n /**\n * @brief : This function finds the index of the lowest common\n * graph ancestor between 2 nodes in the subtree\n * (from the graph hierarchy induced tree) whose\n * root is graphIx\n *\n * @arg node1: node1's ID\n * @arg node2: node2's ID\n * @arg layoutInfo: layoutInfo object\n *\n */\n\n\n var findLCA = function findLCA(node1, node2, layoutInfo) {\n // Find their common ancester, starting from the root graph\n var res = findLCA_aux(node1, node2, 0, layoutInfo);\n\n if (2 > res.count) {\n // If aux function couldn't find the common ancester,\n // then it is the root graph\n return 0;\n } else {\n return res.graph;\n }\n };\n /**\n * @brief : Auxiliary function used for LCA computation\n *\n * @arg node1 : node1's ID\n * @arg node2 : node2's ID\n * @arg graphIx : subgraph index\n * @arg layoutInfo : layoutInfo object\n *\n * @return : object of the form {count: X, graph: Y}, where:\n * X is the number of ancestors (max: 2) found in\n * graphIx (and it's subgraphs),\n * Y is the graph index of the lowest graph containing\n * all X nodes\n */\n\n\n var findLCA_aux = function findLCA_aux(node1, node2, graphIx, layoutInfo) {\n var graph = layoutInfo.graphSet[graphIx]; // If both nodes belongs to graphIx\n\n if (-1 < graph.indexOf(node1) && -1 < graph.indexOf(node2)) {\n return {\n count: 2,\n graph: graphIx\n };\n } // Make recursive calls for all subgraphs\n\n\n var c = 0;\n\n for (var i = 0; i < graph.length; i++) {\n var nodeId = graph[i];\n var nodeIx = layoutInfo.idToIndex[nodeId];\n var children = layoutInfo.layoutNodes[nodeIx].children; // If the node has no child, skip it\n\n if (0 === children.length) {\n continue;\n }\n\n var childGraphIx = layoutInfo.indexToGraph[layoutInfo.idToIndex[children[0]]];\n var result = findLCA_aux(node1, node2, childGraphIx, layoutInfo);\n\n if (0 === result.count) {\n // Neither node1 nor node2 are present in this subgraph\n continue;\n } else if (1 === result.count) {\n // One of (node1, node2) is present in this subgraph\n c++;\n\n if (2 === c) {\n // We've already found both nodes, no need to keep searching\n break;\n }\n } else {\n // Both nodes are present in this subgraph\n return result;\n }\n }\n\n return {\n count: c,\n graph: graphIx\n };\n };\n /**\n * @brief: printsLayoutInfo into js console\n * Only used for debbuging\n */\n\n\nvar printLayoutInfo; \n /**\n * @brief : Randomizes the position of all nodes\n */\n\n\n var randomizePositions = function randomizePositions(layoutInfo, cy) {\n var width = layoutInfo.clientWidth;\n var height = layoutInfo.clientHeight;\n\n for (var i = 0; i < layoutInfo.nodeSize; i++) {\n var n = layoutInfo.layoutNodes[i]; // No need to randomize compound nodes or locked nodes\n\n if (0 === n.children.length && !n.isLocked) {\n n.positionX = Math.random() * width;\n n.positionY = Math.random() * height;\n }\n }\n };\n\n var getScaleInBoundsFn = function getScaleInBoundsFn(layoutInfo, options, nodes) {\n var bb = layoutInfo.boundingBox;\n var coseBB = {\n x1: Infinity,\n x2: -Infinity,\n y1: Infinity,\n y2: -Infinity\n };\n\n if (options.boundingBox) {\n nodes.forEach(function (node) {\n var lnode = layoutInfo.layoutNodes[layoutInfo.idToIndex[node.data('id')]];\n coseBB.x1 = Math.min(coseBB.x1, lnode.positionX);\n coseBB.x2 = Math.max(coseBB.x2, lnode.positionX);\n coseBB.y1 = Math.min(coseBB.y1, lnode.positionY);\n coseBB.y2 = Math.max(coseBB.y2, lnode.positionY);\n });\n coseBB.w = coseBB.x2 - coseBB.x1;\n coseBB.h = coseBB.y2 - coseBB.y1;\n }\n\n return function (ele, i) {\n var lnode = layoutInfo.layoutNodes[layoutInfo.idToIndex[ele.data('id')]];\n\n if (options.boundingBox) {\n // then add extra bounding box constraint\n var pctX = (lnode.positionX - coseBB.x1) / coseBB.w;\n var pctY = (lnode.positionY - coseBB.y1) / coseBB.h;\n return {\n x: bb.x1 + pctX * bb.w,\n y: bb.y1 + pctY * bb.h\n };\n } else {\n return {\n x: lnode.positionX,\n y: lnode.positionY\n };\n }\n };\n };\n /**\n * @brief : Updates the positions of nodes in the network\n * @arg layoutInfo : LayoutInfo object\n * @arg cy : Cytoscape object\n * @arg options : Layout options\n */\n\n\n var refreshPositions = function refreshPositions(layoutInfo, cy, options) {\n // var s = 'Refreshing positions';\n // logDebug(s);\n var layout = options.layout;\n var nodes = options.eles.nodes();\n var getScaledPos = getScaleInBoundsFn(layoutInfo, options, nodes);\n nodes.positions(getScaledPos); // Trigger layoutReady only on first call\n\n if (true !== layoutInfo.ready) {\n // s = 'Triggering layoutready';\n // logDebug(s);\n layoutInfo.ready = true;\n layout.one('layoutready', options.ready);\n layout.emit({\n type: 'layoutready',\n layout: this\n });\n }\n };\n /**\n * @brief : Logs a debug message in JS console, if DEBUG is ON\n */\n // var logDebug = function(text) {\n // if (DEBUG) {\n // console.debug(text);\n // }\n // };\n\n /**\n * @brief : Performs one iteration of the physical simulation\n * @arg layoutInfo : LayoutInfo object already initialized\n * @arg cy : Cytoscape object\n * @arg options : Layout options\n */\n\n\n var step = function step(layoutInfo, options, _step) {\n // var s = \"\\n\\n###############################\";\n // s += \"\\nSTEP: \" + step;\n // s += \"\\n###############################\\n\";\n // logDebug(s);\n // Calculate node repulsions\n calculateNodeForces(layoutInfo, options); // Calculate edge forces\n\n calculateEdgeForces(layoutInfo); // Calculate gravity forces\n\n calculateGravityForces(layoutInfo, options); // Propagate forces from parent to child\n\n propagateForces(layoutInfo); // Update positions based on calculated forces\n\n updatePositions(layoutInfo);\n };\n /**\n * @brief : Computes the node repulsion forces\n */\n\n\n var calculateNodeForces = function calculateNodeForces(layoutInfo, options) {\n // Go through each of the graphs in graphSet\n // Nodes only repel each other if they belong to the same graph\n // var s = 'calculateNodeForces';\n // logDebug(s);\n for (var i = 0; i < layoutInfo.graphSet.length; i++) {\n var graph = layoutInfo.graphSet[i];\n var numNodes = graph.length; // s = \"Set: \" + graph.toString();\n // logDebug(s);\n // Now get all the pairs of nodes\n // Only get each pair once, (A, B) = (B, A)\n\n for (var j = 0; j < numNodes; j++) {\n var node1 = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[j]]];\n\n for (var k = j + 1; k < numNodes; k++) {\n var node2 = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[k]]];\n nodeRepulsion(node1, node2, layoutInfo, options);\n }\n }\n }\n };\n\n var randomDistance = function randomDistance(max) {\n return -max + 2 * max * Math.random();\n };\n /**\n * @brief : Compute the node repulsion forces between a pair of nodes\n */\n\n\n var nodeRepulsion = function nodeRepulsion(node1, node2, layoutInfo, options) {\n // var s = \"Node repulsion. Node1: \" + node1.id + \" Node2: \" + node2.id;\n var cmptId1 = node1.cmptId;\n var cmptId2 = node2.cmptId;\n\n if (cmptId1 !== cmptId2 && !layoutInfo.isCompound) {\n return;\n } // Get direction of line connecting both node centers\n\n\n var directionX = node2.positionX - node1.positionX;\n var directionY = node2.positionY - node1.positionY;\n var maxRandDist = 1; // s += \"\\ndirectionX: \" + directionX + \", directionY: \" + directionY;\n // If both centers are the same, apply a random force\n\n if (0 === directionX && 0 === directionY) {\n directionX = randomDistance(maxRandDist);\n directionY = randomDistance(maxRandDist);\n }\n\n var overlap = nodesOverlap(node1, node2, directionX, directionY);\n\n if (overlap > 0) {\n // s += \"\\nNodes DO overlap.\";\n // s += \"\\nOverlap: \" + overlap;\n // If nodes overlap, repulsion force is proportional\n // to the overlap\n var force = options.nodeOverlap * overlap; // Compute the module and components of the force vector\n\n var distance = Math.sqrt(directionX * directionX + directionY * directionY); // s += \"\\nDistance: \" + distance;\n\n var forceX = force * directionX / distance;\n var forceY = force * directionY / distance;\n } else {\n // s += \"\\nNodes do NOT overlap.\";\n // If there's no overlap, force is inversely proportional\n // to squared distance\n // Get clipping points for both nodes\n var point1 = findClippingPoint(node1, directionX, directionY);\n var point2 = findClippingPoint(node2, -1 * directionX, -1 * directionY); // Use clipping points to compute distance\n\n var distanceX = point2.x - point1.x;\n var distanceY = point2.y - point1.y;\n var distanceSqr = distanceX * distanceX + distanceY * distanceY;\n var distance = Math.sqrt(distanceSqr); // s += \"\\nDistance: \" + distance;\n // Compute the module and components of the force vector\n\n var force = (node1.nodeRepulsion + node2.nodeRepulsion) / distanceSqr;\n var forceX = force * distanceX / distance;\n var forceY = force * distanceY / distance;\n } // Apply force\n\n\n if (!node1.isLocked) {\n node1.offsetX -= forceX;\n node1.offsetY -= forceY;\n }\n\n if (!node2.isLocked) {\n node2.offsetX += forceX;\n node2.offsetY += forceY;\n } // s += \"\\nForceX: \" + forceX + \" ForceY: \" + forceY;\n // logDebug(s);\n\n\n return;\n };\n /**\n * @brief : Determines whether two nodes overlap or not\n * @return : Amount of overlapping (0 => no overlap)\n */\n\n\n var nodesOverlap = function nodesOverlap(node1, node2, dX, dY) {\n if (dX > 0) {\n var overlapX = node1.maxX - node2.minX;\n } else {\n var overlapX = node2.maxX - node1.minX;\n }\n\n if (dY > 0) {\n var overlapY = node1.maxY - node2.minY;\n } else {\n var overlapY = node2.maxY - node1.minY;\n }\n\n if (overlapX >= 0 && overlapY >= 0) {\n return Math.sqrt(overlapX * overlapX + overlapY * overlapY);\n } else {\n return 0;\n }\n };\n /**\n * @brief : Finds the point in which an edge (direction dX, dY) intersects\n * the rectangular bounding box of it's source/target node\n */\n\n\n var findClippingPoint = function findClippingPoint(node, dX, dY) {\n // Shorcuts\n var X = node.positionX;\n var Y = node.positionY;\n var H = node.height || 1;\n var W = node.width || 1;\n var dirSlope = dY / dX;\n var nodeSlope = H / W; // var s = 'Computing clipping point of node ' + node.id +\n // \" . Height: \" + H + \", Width: \" + W +\n // \"\\nDirection \" + dX + \", \" + dY;\n //\n // Compute intersection\n\n var res = {}; // Case: Vertical direction (up)\n\n if (0 === dX && 0 < dY) {\n res.x = X; // s += \"\\nUp direction\";\n\n res.y = Y + H / 2;\n return res;\n } // Case: Vertical direction (down)\n\n\n if (0 === dX && 0 > dY) {\n res.x = X;\n res.y = Y + H / 2; // s += \"\\nDown direction\";\n\n return res;\n } // Case: Intersects the right border\n\n\n if (0 < dX && -1 * nodeSlope <= dirSlope && dirSlope <= nodeSlope) {\n res.x = X + W / 2;\n res.y = Y + W * dY / 2 / dX; // s += \"\\nRightborder\";\n\n return res;\n } // Case: Intersects the left border\n\n\n if (0 > dX && -1 * nodeSlope <= dirSlope && dirSlope <= nodeSlope) {\n res.x = X - W / 2;\n res.y = Y - W * dY / 2 / dX; // s += \"\\nLeftborder\";\n\n return res;\n } // Case: Intersects the top border\n\n\n if (0 < dY && (dirSlope <= -1 * nodeSlope || dirSlope >= nodeSlope)) {\n res.x = X + H * dX / 2 / dY;\n res.y = Y + H / 2; // s += \"\\nTop border\";\n\n return res;\n } // Case: Intersects the bottom border\n\n\n if (0 > dY && (dirSlope <= -1 * nodeSlope || dirSlope >= nodeSlope)) {\n res.x = X - H * dX / 2 / dY;\n res.y = Y - H / 2; // s += \"\\nBottom border\";\n\n return res;\n } // s += \"\\nClipping point found at \" + res.x + \", \" + res.y;\n // logDebug(s);\n\n\n return res;\n };\n /**\n * @brief : Calculates all edge forces\n */\n\n\n var calculateEdgeForces = function calculateEdgeForces(layoutInfo, options) {\n // Iterate over all edges\n for (var i = 0; i < layoutInfo.edgeSize; i++) {\n // Get edge, source & target nodes\n var edge = layoutInfo.layoutEdges[i];\n var sourceIx = layoutInfo.idToIndex[edge.sourceId];\n var source = layoutInfo.layoutNodes[sourceIx];\n var targetIx = layoutInfo.idToIndex[edge.targetId];\n var target = layoutInfo.layoutNodes[targetIx]; // Get direction of line connecting both node centers\n\n var directionX = target.positionX - source.positionX;\n var directionY = target.positionY - source.positionY; // If both centers are the same, do nothing.\n // A random force has already been applied as node repulsion\n\n if (0 === directionX && 0 === directionY) {\n continue;\n } // Get clipping points for both nodes\n\n\n var point1 = findClippingPoint(source, directionX, directionY);\n var point2 = findClippingPoint(target, -1 * directionX, -1 * directionY);\n var lx = point2.x - point1.x;\n var ly = point2.y - point1.y;\n var l = Math.sqrt(lx * lx + ly * ly);\n var force = Math.pow(edge.idealLength - l, 2) / edge.elasticity;\n\n if (0 !== l) {\n var forceX = force * lx / l;\n var forceY = force * ly / l;\n } else {\n var forceX = 0;\n var forceY = 0;\n } // Add this force to target and source nodes\n\n\n if (!source.isLocked) {\n source.offsetX += forceX;\n source.offsetY += forceY;\n }\n\n if (!target.isLocked) {\n target.offsetX -= forceX;\n target.offsetY -= forceY;\n } // var s = 'Edge force between nodes ' + source.id + ' and ' + target.id;\n // s += \"\\nDistance: \" + l + \" Force: (\" + forceX + \", \" + forceY + \")\";\n // logDebug(s);\n\n }\n };\n /**\n * @brief : Computes gravity forces for all nodes\n */\n\n\n var calculateGravityForces = function calculateGravityForces(layoutInfo, options) {\n if (options.gravity === 0) {\n return;\n }\n\n var distThreshold = 1; // var s = 'calculateGravityForces';\n // logDebug(s);\n\n for (var i = 0; i < layoutInfo.graphSet.length; i++) {\n var graph = layoutInfo.graphSet[i];\n var numNodes = graph.length; // s = \"Set: \" + graph.toString();\n // logDebug(s);\n // Compute graph center\n\n if (0 === i) {\n var centerX = layoutInfo.clientHeight / 2;\n var centerY = layoutInfo.clientWidth / 2;\n } else {\n // Get Parent node for this graph, and use its position as center\n var temp = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[0]]];\n var parent = layoutInfo.layoutNodes[layoutInfo.idToIndex[temp.parentId]];\n var centerX = parent.positionX;\n var centerY = parent.positionY;\n } // s = \"Center found at: \" + centerX + \", \" + centerY;\n // logDebug(s);\n // Apply force to all nodes in graph\n\n\n for (var j = 0; j < numNodes; j++) {\n var node = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[j]]]; // s = \"Node: \" + node.id;\n\n if (node.isLocked) {\n continue;\n }\n\n var dx = centerX - node.positionX;\n var dy = centerY - node.positionY;\n var d = Math.sqrt(dx * dx + dy * dy);\n\n if (d > distThreshold) {\n var fx = options.gravity * dx / d;\n var fy = options.gravity * dy / d;\n node.offsetX += fx;\n node.offsetY += fy; // s += \": Applied force: \" + fx + \", \" + fy;\n } // logDebug(s);\n\n }\n }\n };\n /**\n * @brief : This function propagates the existing offsets from\n * parent nodes to its descendents.\n * @arg layoutInfo : layoutInfo Object\n * @arg cy : cytoscape Object\n * @arg options : Layout options\n */\n\n\n var propagateForces = function propagateForces(layoutInfo, options) {\n // Inline implementation of a queue, used for traversing the graph in BFS order\n var queue = [];\n var start = 0; // Points to the start the queue\n\n var end = -1; // Points to the end of the queue\n // logDebug('propagateForces');\n // Start by visiting the nodes in the root graph\n\n queue.push.apply(queue, layoutInfo.graphSet[0]);\n end += layoutInfo.graphSet[0].length; // Traverse the graph, level by level,\n\n while (start <= end) {\n // Get the node to visit and remove it from queue\n var nodeId = queue[start++];\n var nodeIndex = layoutInfo.idToIndex[nodeId];\n var node = layoutInfo.layoutNodes[nodeIndex];\n var children = node.children; // We only need to process the node if it's compound\n\n if (0 < children.length && !node.isLocked) {\n var offX = node.offsetX;\n var offY = node.offsetY; // var s = \"Propagating offset from parent node : \" + node.id +\n // \". OffsetX: \" + offX + \". OffsetY: \" + offY;\n // s += \"\\n Children: \" + children.toString();\n // logDebug(s);\n\n for (var i = 0; i < children.length; i++) {\n var childNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[children[i]]]; // Propagate offset\n\n childNode.offsetX += offX;\n childNode.offsetY += offY; // Add children to queue to be visited\n\n queue[++end] = children[i];\n } // Reset parent offsets\n\n\n node.offsetX = 0;\n node.offsetY = 0;\n }\n }\n };\n /**\n * @brief : Updates the layout model positions, based on\n * the accumulated forces\n */\n\n\n var updatePositions = function updatePositions(layoutInfo, options) {\n // var s = 'Updating positions';\n // logDebug(s);\n // Reset boundaries for compound nodes\n for (var i = 0; i < layoutInfo.nodeSize; i++) {\n var n = layoutInfo.layoutNodes[i];\n\n if (0 < n.children.length) {\n // logDebug(\"Resetting boundaries of compound node: \" + n.id);\n n.maxX = undefined;\n n.minX = undefined;\n n.maxY = undefined;\n n.minY = undefined;\n }\n }\n\n for (var i = 0; i < layoutInfo.nodeSize; i++) {\n var n = layoutInfo.layoutNodes[i];\n\n if (0 < n.children.length || n.isLocked) {\n // No need to set compound or locked node position\n // logDebug(\"Skipping position update of node: \" + n.id);\n continue;\n } // s = \"Node: \" + n.id + \" Previous position: (\" +\n // n.positionX + \", \" + n.positionY + \").\";\n // Limit displacement in order to improve stability\n\n\n var tempForce = limitForce(n.offsetX, n.offsetY, layoutInfo.temperature);\n n.positionX += tempForce.x;\n n.positionY += tempForce.y;\n n.offsetX = 0;\n n.offsetY = 0;\n n.minX = n.positionX - n.width;\n n.maxX = n.positionX + n.width;\n n.minY = n.positionY - n.height;\n n.maxY = n.positionY + n.height; // s += \" New Position: (\" + n.positionX + \", \" + n.positionY + \").\";\n // logDebug(s);\n // Update ancestry boudaries\n\n updateAncestryBoundaries(n, layoutInfo);\n } // Update size, position of compund nodes\n\n\n for (var i = 0; i < layoutInfo.nodeSize; i++) {\n var n = layoutInfo.layoutNodes[i];\n\n if (0 < n.children.length && !n.isLocked) {\n n.positionX = (n.maxX + n.minX) / 2;\n n.positionY = (n.maxY + n.minY) / 2;\n n.width = n.maxX - n.minX;\n n.height = n.maxY - n.minY; // s = \"Updating position, size of compound node \" + n.id;\n // s += \"\\nPositionX: \" + n.positionX + \", PositionY: \" + n.positionY;\n // s += \"\\nWidth: \" + n.width + \", Height: \" + n.height;\n // logDebug(s);\n }\n }\n };\n /**\n * @brief : Limits a force (forceX, forceY) to be not\n * greater (in modulo) than max.\n 8 Preserves force direction.\n */\n\n\n var limitForce = function limitForce(forceX, forceY, max) {\n // var s = \"Limiting force: (\" + forceX + \", \" + forceY + \"). Max: \" + max;\n var force = Math.sqrt(forceX * forceX + forceY * forceY);\n\n if (force > max) {\n var res = {\n x: max * forceX / force,\n y: max * forceY / force\n };\n } else {\n var res = {\n x: forceX,\n y: forceY\n };\n } // s += \".\\nResult: (\" + res.x + \", \" + res.y + \")\";\n // logDebug(s);\n\n\n return res;\n };\n /**\n * @brief : Function used for keeping track of compound node\n * sizes, since they should bound all their subnodes.\n */\n\n\n var updateAncestryBoundaries = function updateAncestryBoundaries(node, layoutInfo) {\n // var s = \"Propagating new position/size of node \" + node.id;\n var parentId = node.parentId;\n\n if (null == parentId) {\n // If there's no parent, we are done\n // s += \". No parent node.\";\n // logDebug(s);\n return;\n } // Get Parent Node\n\n\n var p = layoutInfo.layoutNodes[layoutInfo.idToIndex[parentId]];\n var flag = false; // MaxX\n\n if (null == p.maxX || node.maxX + p.padRight > p.maxX) {\n p.maxX = node.maxX + p.padRight;\n flag = true; // s += \"\\nNew maxX for parent node \" + p.id + \": \" + p.maxX;\n } // MinX\n\n\n if (null == p.minX || node.minX - p.padLeft < p.minX) {\n p.minX = node.minX - p.padLeft;\n flag = true; // s += \"\\nNew minX for parent node \" + p.id + \": \" + p.minX;\n } // MaxY\n\n\n if (null == p.maxY || node.maxY + p.padBottom > p.maxY) {\n p.maxY = node.maxY + p.padBottom;\n flag = true; // s += \"\\nNew maxY for parent node \" + p.id + \": \" + p.maxY;\n } // MinY\n\n\n if (null == p.minY || node.minY - p.padTop < p.minY) {\n p.minY = node.minY - p.padTop;\n flag = true; // s += \"\\nNew minY for parent node \" + p.id + \": \" + p.minY;\n } // If updated boundaries, propagate changes upward\n\n\n if (flag) {\n // logDebug(s);\n return updateAncestryBoundaries(p, layoutInfo);\n } // s += \". No changes in boundaries/position of parent node \" + p.id;\n // logDebug(s);\n\n\n return;\n };\n\n var separateComponents = function separateComponents(layoutInfo, options) {\n var nodes = layoutInfo.layoutNodes;\n var components = [];\n\n for (var i = 0; i < nodes.length; i++) {\n var node = nodes[i];\n var cid = node.cmptId;\n var component = components[cid] = components[cid] || [];\n component.push(node);\n }\n\n var totalA = 0;\n\n for (var i = 0; i < components.length; i++) {\n var c = components[i];\n\n if (!c) {\n continue;\n }\n\n c.x1 = Infinity;\n c.x2 = -Infinity;\n c.y1 = Infinity;\n c.y2 = -Infinity;\n\n for (var j = 0; j < c.length; j++) {\n var n = c[j];\n c.x1 = Math.min(c.x1, n.positionX - n.width / 2);\n c.x2 = Math.max(c.x2, n.positionX + n.width / 2);\n c.y1 = Math.min(c.y1, n.positionY - n.height / 2);\n c.y2 = Math.max(c.y2, n.positionY + n.height / 2);\n }\n\n c.w = c.x2 - c.x1;\n c.h = c.y2 - c.y1;\n totalA += c.w * c.h;\n }\n\n components.sort(function (c1, c2) {\n return c2.w * c2.h - c1.w * c1.h;\n });\n var x = 0;\n var y = 0;\n var usedW = 0;\n var rowH = 0;\n var maxRowW = Math.sqrt(totalA) * layoutInfo.clientWidth / layoutInfo.clientHeight;\n\n for (var i = 0; i < components.length; i++) {\n var c = components[i];\n\n if (!c) {\n continue;\n }\n\n for (var j = 0; j < c.length; j++) {\n var n = c[j];\n\n if (!n.isLocked) {\n n.positionX += x - c.x1;\n n.positionY += y - c.y1;\n }\n }\n\n x += c.w + options.componentSpacing;\n usedW += c.w + options.componentSpacing;\n rowH = Math.max(rowH, c.h);\n\n if (usedW > maxRowW) {\n y += rowH + options.componentSpacing;\n x = 0;\n usedW = 0;\n rowH = 0;\n }\n }\n };\n\n var defaults$3 = {\n fit: true,\n // whether to fit the viewport to the graph\n padding: 30,\n // padding used on fit\n boundingBox: undefined,\n // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }\n avoidOverlap: true,\n // prevents node overlap, may overflow boundingBox if not enough space\n avoidOverlapPadding: 10,\n // extra spacing around nodes when avoidOverlap: true\n nodeDimensionsIncludeLabels: false,\n // Excludes the label when calculating node bounding boxes for the layout algorithm\n spacingFactor: undefined,\n // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up\n condense: false,\n // uses all available space on false, uses minimal space on true\n rows: undefined,\n // force num of rows in the grid\n cols: undefined,\n // force num of columns in the grid\n position: function position(node) {},\n // returns { row, col } for element\n sort: undefined,\n // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') }\n animate: false,\n // whether to transition the node positions\n animationDuration: 500,\n // duration of animation in ms if enabled\n animationEasing: undefined,\n // easing of animation if enabled\n animateFilter: function animateFilter(node, i) {\n return true;\n },\n // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts\n ready: undefined,\n // callback on layoutready\n stop: undefined,\n // callback on layoutstop\n transform: function transform(node, position) {\n return position;\n } // transform a given node position. Useful for changing flow direction in discrete layouts \n\n };\n\n function GridLayout(options) {\n this.options = extend({}, defaults$3, options);\n }\n\n GridLayout.prototype.run = function () {\n var params = this.options;\n var options = params;\n var cy = params.cy;\n var eles = options.eles;\n var nodes = eles.nodes().not(':parent');\n\n if (options.sort) {\n nodes = nodes.sort(options.sort);\n }\n\n var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : {\n x1: 0,\n y1: 0,\n w: cy.width(),\n h: cy.height()\n });\n\n if (bb.h === 0 || bb.w === 0) {\n eles.nodes().layoutPositions(this, options, function (ele) {\n return {\n x: bb.x1,\n y: bb.y1\n };\n });\n } else {\n // width/height * splits^2 = cells where splits is number of times to split width\n var cells = nodes.size();\n var splits = Math.sqrt(cells * bb.h / bb.w);\n var rows = Math.round(splits);\n var cols = Math.round(bb.w / bb.h * splits);\n\n var small = function small(val) {\n if (val == null) {\n return Math.min(rows, cols);\n } else {\n var min = Math.min(rows, cols);\n\n if (min == rows) {\n rows = val;\n } else {\n cols = val;\n }\n }\n };\n\n var large = function large(val) {\n if (val == null) {\n return Math.max(rows, cols);\n } else {\n var max = Math.max(rows, cols);\n\n if (max == rows) {\n rows = val;\n } else {\n cols = val;\n }\n }\n };\n\n var oRows = options.rows;\n var oCols = options.cols != null ? options.cols : options.columns; // if rows or columns were set in options, use those values\n\n if (oRows != null && oCols != null) {\n rows = oRows;\n cols = oCols;\n } else if (oRows != null && oCols == null) {\n rows = oRows;\n cols = Math.ceil(cells / rows);\n } else if (oRows == null && oCols != null) {\n cols = oCols;\n rows = Math.ceil(cells / cols);\n } // otherwise use the automatic values and adjust accordingly\n // if rounding was up, see if we can reduce rows or columns\n else if (cols * rows > cells) {\n var sm = small();\n var lg = large(); // reducing the small side takes away the most cells, so try it first\n\n if ((sm - 1) * lg >= cells) {\n small(sm - 1);\n } else if ((lg - 1) * sm >= cells) {\n large(lg - 1);\n }\n } else {\n // if rounding was too low, add rows or columns\n while (cols * rows < cells) {\n var _sm = small();\n\n var _lg = large(); // try to add to larger side first (adds less in multiplication)\n\n\n if ((_lg + 1) * _sm >= cells) {\n large(_lg + 1);\n } else {\n small(_sm + 1);\n }\n }\n }\n\n var cellWidth = bb.w / cols;\n var cellHeight = bb.h / rows;\n\n if (options.condense) {\n cellWidth = 0;\n cellHeight = 0;\n }\n\n if (options.avoidOverlap) {\n for (var i = 0; i < nodes.length; i++) {\n var node = nodes[i];\n var pos = node._private.position;\n\n if (pos.x == null || pos.y == null) {\n // for bb\n pos.x = 0;\n pos.y = 0;\n }\n\n var nbb = node.layoutDimensions(options);\n var p = options.avoidOverlapPadding;\n var w = nbb.w + p;\n var h = nbb.h + p;\n cellWidth = Math.max(cellWidth, w);\n cellHeight = Math.max(cellHeight, h);\n }\n }\n\n var cellUsed = {}; // e.g. 'c-0-2' => true\n\n var used = function used(row, col) {\n return cellUsed['c-' + row + '-' + col] ? true : false;\n };\n\n var use = function use(row, col) {\n cellUsed['c-' + row + '-' + col] = true;\n }; // to keep track of current cell position\n\n\n var row = 0;\n var col = 0;\n\n var moveToNextCell = function moveToNextCell() {\n col++;\n\n if (col >= cols) {\n col = 0;\n row++;\n }\n }; // get a cache of all the manual positions\n\n\n var id2manPos = {};\n\n for (var _i = 0; _i < nodes.length; _i++) {\n var _node = nodes[_i];\n var rcPos = options.position(_node);\n\n if (rcPos && (rcPos.row !== undefined || rcPos.col !== undefined)) {\n // must have at least row or col def'd\n var _pos = {\n row: rcPos.row,\n col: rcPos.col\n };\n\n if (_pos.col === undefined) {\n // find unused col\n _pos.col = 0;\n\n while (used(_pos.row, _pos.col)) {\n _pos.col++;\n }\n } else if (_pos.row === undefined) {\n // find unused row\n _pos.row = 0;\n\n while (used(_pos.row, _pos.col)) {\n _pos.row++;\n }\n }\n\n id2manPos[_node.id()] = _pos;\n use(_pos.row, _pos.col);\n }\n }\n\n var getPos = function getPos(element, i) {\n var x, y;\n\n if (element.locked() || element.isParent()) {\n return false;\n } // see if we have a manual position set\n\n\n var rcPos = id2manPos[element.id()];\n\n if (rcPos) {\n x = rcPos.col * cellWidth + cellWidth / 2 + bb.x1;\n y = rcPos.row * cellHeight + cellHeight / 2 + bb.y1;\n } else {\n // otherwise set automatically\n while (used(row, col)) {\n moveToNextCell();\n }\n\n x = col * cellWidth + cellWidth / 2 + bb.x1;\n y = row * cellHeight + cellHeight / 2 + bb.y1;\n use(row, col);\n moveToNextCell();\n }\n\n return {\n x: x,\n y: y\n };\n };\n\n nodes.layoutPositions(this, options, getPos);\n }\n\n return this; // chaining\n };\n\n var defaults$2 = {\n ready: function ready() {},\n // on layoutready\n stop: function stop() {} // on layoutstop\n\n }; // constructor\n // options : object containing layout options\n\n function NullLayout(options) {\n this.options = extend({}, defaults$2, options);\n } // runs the layout\n\n\n NullLayout.prototype.run = function () {\n var options = this.options;\n var eles = options.eles; // elements to consider in the layout\n\n var layout = this; // cy is automatically populated for us in the constructor\n // (disable eslint for next line as this serves as example layout code to external developers)\n // eslint-disable-next-line no-unused-vars\n\n options.cy;\n layout.emit('layoutstart'); // puts all nodes at (0, 0)\n // n.b. most layouts would use layoutPositions(), instead of positions() and manual events\n\n eles.nodes().positions(function () {\n return {\n x: 0,\n y: 0\n };\n }); // trigger layoutready when each node has had its position set at least once\n\n layout.one('layoutready', options.ready);\n layout.emit('layoutready'); // trigger layoutstop when the layout stops (e.g. finishes)\n\n layout.one('layoutstop', options.stop);\n layout.emit('layoutstop');\n return this; // chaining\n }; // called on continuous layouts to stop them before they finish\n\n\n NullLayout.prototype.stop = function () {\n return this; // chaining\n };\n\n var defaults$1 = {\n positions: undefined,\n // map of (node id) => (position obj); or function(node){ return somPos; }\n zoom: undefined,\n // the zoom level to set (prob want fit = false if set)\n pan: undefined,\n // the pan level to set (prob want fit = false if set)\n fit: true,\n // whether to fit to viewport\n padding: 30,\n // padding on fit\n animate: false,\n // whether to transition the node positions\n animationDuration: 500,\n // duration of animation in ms if enabled\n animationEasing: undefined,\n // easing of animation if enabled\n animateFilter: function animateFilter(node, i) {\n return true;\n },\n // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts\n ready: undefined,\n // callback on layoutready\n stop: undefined,\n // callback on layoutstop\n transform: function transform(node, position) {\n return position;\n } // transform a given node position. Useful for changing flow direction in discrete layouts\n\n };\n\n function PresetLayout(options) {\n this.options = extend({}, defaults$1, options);\n }\n\n PresetLayout.prototype.run = function () {\n var options = this.options;\n var eles = options.eles;\n var nodes = eles.nodes();\n var posIsFn = fn$6(options.positions);\n\n function getPosition(node) {\n if (options.positions == null) {\n return copyPosition(node.position());\n }\n\n if (posIsFn) {\n return options.positions(node);\n }\n\n var pos = options.positions[node._private.data.id];\n\n if (pos == null) {\n return null;\n }\n\n return pos;\n }\n\n nodes.layoutPositions(this, options, function (node, i) {\n var position = getPosition(node);\n\n if (node.locked() || position == null) {\n return false;\n }\n\n return position;\n });\n return this; // chaining\n };\n\n var defaults = {\n fit: true,\n // whether to fit to viewport\n padding: 30,\n // fit padding\n boundingBox: undefined,\n // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }\n animate: false,\n // whether to transition the node positions\n animationDuration: 500,\n // duration of animation in ms if enabled\n animationEasing: undefined,\n // easing of animation if enabled\n animateFilter: function animateFilter(node, i) {\n return true;\n },\n // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts\n ready: undefined,\n // callback on layoutready\n stop: undefined,\n // callback on layoutstop\n transform: function transform(node, position) {\n return position;\n } // transform a given node position. Useful for changing flow direction in discrete layouts \n\n };\n\n function RandomLayout(options) {\n this.options = extend({}, defaults, options);\n }\n\n RandomLayout.prototype.run = function () {\n var options = this.options;\n var cy = options.cy;\n var eles = options.eles;\n var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : {\n x1: 0,\n y1: 0,\n w: cy.width(),\n h: cy.height()\n });\n\n var getPos = function getPos(node, i) {\n return {\n x: bb.x1 + Math.round(Math.random() * bb.w),\n y: bb.y1 + Math.round(Math.random() * bb.h)\n };\n };\n\n eles.nodes().layoutPositions(this, options, getPos);\n return this; // chaining\n };\n\n var layout = [{\n name: 'breadthfirst',\n impl: BreadthFirstLayout\n }, {\n name: 'circle',\n impl: CircleLayout\n }, {\n name: 'concentric',\n impl: ConcentricLayout\n }, {\n name: 'cose',\n impl: CoseLayout\n }, {\n name: 'grid',\n impl: GridLayout\n }, {\n name: 'null',\n impl: NullLayout\n }, {\n name: 'preset',\n impl: PresetLayout\n }, {\n name: 'random',\n impl: RandomLayout\n }];\n\n function NullRenderer(options) {\n this.options = options;\n this.notifications = 0; // for testing\n }\n\n var noop = function noop() {};\n\n var throwImgErr = function throwImgErr() {\n throw new Error('A headless instance can not render images');\n };\n\n NullRenderer.prototype = {\n recalculateRenderedStyle: noop,\n notify: function notify() {\n this.notifications++;\n },\n init: noop,\n isHeadless: function isHeadless() {\n return true;\n },\n png: throwImgErr,\n jpg: throwImgErr\n };\n\n var BRp$f = {};\n BRp$f.arrowShapeWidth = 0.3;\n\n BRp$f.registerArrowShapes = function () {\n var arrowShapes = this.arrowShapes = {};\n var renderer = this; // Contract for arrow shapes:\n // 0, 0 is arrow tip\n // (0, 1) is direction towards node\n // (1, 0) is right\n //\n // functional api:\n // collide: check x, y in shape\n // roughCollide: called before collide, no false negatives\n // draw: draw\n // spacing: dist(arrowTip, nodeBoundary)\n // gap: dist(edgeTip, nodeBoundary), edgeTip may != arrowTip\n\n var bbCollide = function bbCollide(x, y, size, angle, translation, edgeWidth, padding) {\n var x1 = translation.x - size / 2 - padding;\n var x2 = translation.x + size / 2 + padding;\n var y1 = translation.y - size / 2 - padding;\n var y2 = translation.y + size / 2 + padding;\n var inside = x1 <= x && x <= x2 && y1 <= y && y <= y2;\n return inside;\n };\n\n var transform = function transform(x, y, size, angle, translation) {\n var xRotated = x * Math.cos(angle) - y * Math.sin(angle);\n var yRotated = x * Math.sin(angle) + y * Math.cos(angle);\n var xScaled = xRotated * size;\n var yScaled = yRotated * size;\n var xTranslated = xScaled + translation.x;\n var yTranslated = yScaled + translation.y;\n return {\n x: xTranslated,\n y: yTranslated\n };\n };\n\n var transformPoints = function transformPoints(pts, size, angle, translation) {\n var retPts = [];\n\n for (var i = 0; i < pts.length; i += 2) {\n var x = pts[i];\n var y = pts[i + 1];\n retPts.push(transform(x, y, size, angle, translation));\n }\n\n return retPts;\n };\n\n var pointsToArr = function pointsToArr(pts) {\n var ret = [];\n\n for (var i = 0; i < pts.length; i++) {\n var p = pts[i];\n ret.push(p.x, p.y);\n }\n\n return ret;\n };\n\n var standardGap = function standardGap(edge) {\n return edge.pstyle('width').pfValue * edge.pstyle('arrow-scale').pfValue * 2;\n };\n\n var defineArrowShape = function defineArrowShape(name, defn) {\n if (string(defn)) {\n defn = arrowShapes[defn];\n }\n\n arrowShapes[name] = extend({\n name: name,\n points: [-0.15, -0.3, 0.15, -0.3, 0.15, 0.3, -0.15, 0.3],\n collide: function collide(x, y, size, angle, translation, padding) {\n var points = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation));\n var inside = pointInsidePolygonPoints(x, y, points);\n return inside;\n },\n roughCollide: bbCollide,\n draw: function draw(context, size, angle, translation) {\n var points = transformPoints(this.points, size, angle, translation);\n renderer.arrowShapeImpl('polygon')(context, points);\n },\n spacing: function spacing(edge) {\n return 0;\n },\n gap: standardGap\n }, defn);\n };\n\n defineArrowShape('none', {\n collide: falsify,\n roughCollide: falsify,\n draw: noop$1,\n spacing: zeroify,\n gap: zeroify\n });\n defineArrowShape('triangle', {\n points: [-0.15, -0.3, 0, 0, 0.15, -0.3]\n });\n defineArrowShape('arrow', 'triangle');\n defineArrowShape('triangle-backcurve', {\n points: arrowShapes['triangle'].points,\n controlPoint: [0, -0.15],\n roughCollide: bbCollide,\n draw: function draw(context, size, angle, translation, edgeWidth) {\n var ptsTrans = transformPoints(this.points, size, angle, translation);\n var ctrlPt = this.controlPoint;\n var ctrlPtTrans = transform(ctrlPt[0], ctrlPt[1], size, angle, translation);\n renderer.arrowShapeImpl(this.name)(context, ptsTrans, ctrlPtTrans);\n },\n gap: function gap(edge) {\n return standardGap(edge) * 0.8;\n }\n });\n defineArrowShape('triangle-tee', {\n points: [0, 0, 0.15, -0.3, -0.15, -0.3, 0, 0],\n pointsTee: [-0.15, -0.4, -0.15, -0.5, 0.15, -0.5, 0.15, -0.4],\n collide: function collide(x, y, size, angle, translation, edgeWidth, padding) {\n var triPts = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation));\n var teePts = pointsToArr(transformPoints(this.pointsTee, size + 2 * padding, angle, translation));\n var inside = pointInsidePolygonPoints(x, y, triPts) || pointInsidePolygonPoints(x, y, teePts);\n return inside;\n },\n draw: function draw(context, size, angle, translation, edgeWidth) {\n var triPts = transformPoints(this.points, size, angle, translation);\n var teePts = transformPoints(this.pointsTee, size, angle, translation);\n renderer.arrowShapeImpl(this.name)(context, triPts, teePts);\n }\n });\n defineArrowShape('circle-triangle', {\n radius: 0.15,\n pointsTr: [0, -0.15, 0.15, -0.45, -0.15, -0.45, 0, -0.15],\n collide: function collide(x, y, size, angle, translation, edgeWidth, padding) {\n var t = translation;\n var circleInside = Math.pow(t.x - x, 2) + Math.pow(t.y - y, 2) <= Math.pow((size + 2 * padding) * this.radius, 2);\n var triPts = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation));\n return pointInsidePolygonPoints(x, y, triPts) || circleInside;\n },\n draw: function draw(context, size, angle, translation, edgeWidth) {\n var triPts = transformPoints(this.pointsTr, size, angle, translation);\n renderer.arrowShapeImpl(this.name)(context, triPts, translation.x, translation.y, this.radius * size);\n },\n spacing: function spacing(edge) {\n return renderer.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.radius;\n }\n });\n defineArrowShape('triangle-cross', {\n points: [0, 0, 0.15, -0.3, -0.15, -0.3, 0, 0],\n baseCrossLinePts: [-0.15, -0.4, // first half of the rectangle\n -0.15, -0.4, 0.15, -0.4, // second half of the rectangle\n 0.15, -0.4],\n crossLinePts: function crossLinePts(size, edgeWidth) {\n // shift points so that the distance between the cross points matches edge width\n var p = this.baseCrossLinePts.slice();\n var shiftFactor = edgeWidth / size;\n var y0 = 3;\n var y1 = 5;\n p[y0] = p[y0] - shiftFactor;\n p[y1] = p[y1] - shiftFactor;\n return p;\n },\n collide: function collide(x, y, size, angle, translation, edgeWidth, padding) {\n var triPts = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation));\n var teePts = pointsToArr(transformPoints(this.crossLinePts(size, edgeWidth), size + 2 * padding, angle, translation));\n var inside = pointInsidePolygonPoints(x, y, triPts) || pointInsidePolygonPoints(x, y, teePts);\n return inside;\n },\n draw: function draw(context, size, angle, translation, edgeWidth) {\n var triPts = transformPoints(this.points, size, angle, translation);\n var crossLinePts = transformPoints(this.crossLinePts(size, edgeWidth), size, angle, translation);\n renderer.arrowShapeImpl(this.name)(context, triPts, crossLinePts);\n }\n });\n defineArrowShape('vee', {\n points: [-0.15, -0.3, 0, 0, 0.15, -0.3, 0, -0.15],\n gap: function gap(edge) {\n return standardGap(edge) * 0.525;\n }\n });\n defineArrowShape('circle', {\n radius: 0.15,\n collide: function collide(x, y, size, angle, translation, edgeWidth, padding) {\n var t = translation;\n var inside = Math.pow(t.x - x, 2) + Math.pow(t.y - y, 2) <= Math.pow((size + 2 * padding) * this.radius, 2);\n return inside;\n },\n draw: function draw(context, size, angle, translation, edgeWidth) {\n renderer.arrowShapeImpl(this.name)(context, translation.x, translation.y, this.radius * size);\n },\n spacing: function spacing(edge) {\n return renderer.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.radius;\n }\n });\n defineArrowShape('tee', {\n points: [-0.15, 0, -0.15, -0.1, 0.15, -0.1, 0.15, 0],\n spacing: function spacing(edge) {\n return 1;\n },\n gap: function gap(edge) {\n return 1;\n }\n });\n defineArrowShape('square', {\n points: [-0.15, 0.00, 0.15, 0.00, 0.15, -0.3, -0.15, -0.3]\n });\n defineArrowShape('diamond', {\n points: [-0.15, -0.15, 0, -0.3, 0.15, -0.15, 0, 0],\n gap: function gap(edge) {\n return edge.pstyle('width').pfValue * edge.pstyle('arrow-scale').value;\n }\n });\n defineArrowShape('chevron', {\n points: [0, 0, -0.15, -0.15, -0.1, -0.2, 0, -0.1, 0.1, -0.2, 0.15, -0.15],\n gap: function gap(edge) {\n return 0.95 * edge.pstyle('width').pfValue * edge.pstyle('arrow-scale').value;\n }\n });\n };\n\n var BRp$e = {}; // Project mouse\n\n BRp$e.projectIntoViewport = function (clientX, clientY) {\n var cy = this.cy;\n var offsets = this.findContainerClientCoords();\n var offsetLeft = offsets[0];\n var offsetTop = offsets[1];\n var scale = offsets[4];\n var pan = cy.pan();\n var zoom = cy.zoom();\n var x = ((clientX - offsetLeft) / scale - pan.x) / zoom;\n var y = ((clientY - offsetTop) / scale - pan.y) / zoom;\n return [x, y];\n };\n\n BRp$e.findContainerClientCoords = function () {\n if (this.containerBB) {\n return this.containerBB;\n }\n\n var container = this.container;\n var rect = container.getBoundingClientRect();\n var style = this.cy.window().getComputedStyle(container);\n\n var styleValue = function styleValue(name) {\n return parseFloat(style.getPropertyValue(name));\n };\n\n var padding = {\n left: styleValue('padding-left'),\n right: styleValue('padding-right'),\n top: styleValue('padding-top'),\n bottom: styleValue('padding-bottom')\n };\n var border = {\n left: styleValue('border-left-width'),\n right: styleValue('border-right-width'),\n top: styleValue('border-top-width'),\n bottom: styleValue('border-bottom-width')\n };\n var clientWidth = container.clientWidth;\n var clientHeight = container.clientHeight;\n var paddingHor = padding.left + padding.right;\n var paddingVer = padding.top + padding.bottom;\n var borderHor = border.left + border.right;\n var scale = rect.width / (clientWidth + borderHor);\n var unscaledW = clientWidth - paddingHor;\n var unscaledH = clientHeight - paddingVer;\n var left = rect.left + padding.left + border.left;\n var top = rect.top + padding.top + border.top;\n return this.containerBB = [left, top, unscaledW, unscaledH, scale];\n };\n\n BRp$e.invalidateContainerClientCoordsCache = function () {\n this.containerBB = null;\n };\n\n BRp$e.findNearestElement = function (x, y, interactiveElementsOnly, isTouch) {\n return this.findNearestElements(x, y, interactiveElementsOnly, isTouch)[0];\n };\n\n BRp$e.findNearestElements = function (x, y, interactiveElementsOnly, isTouch) {\n var self = this;\n var r = this;\n var eles = r.getCachedZSortedEles();\n var near = []; // 1 node max, 1 edge max\n\n var zoom = r.cy.zoom();\n var hasCompounds = r.cy.hasCompoundNodes();\n var edgeThreshold = (isTouch ? 24 : 8) / zoom;\n var nodeThreshold = (isTouch ? 8 : 2) / zoom;\n var labelThreshold = (isTouch ? 8 : 2) / zoom;\n var minSqDist = Infinity;\n var nearEdge;\n var nearNode;\n\n if (interactiveElementsOnly) {\n eles = eles.interactive;\n }\n\n function addEle(ele, sqDist) {\n if (ele.isNode()) {\n if (nearNode) {\n return; // can't replace node\n } else {\n nearNode = ele;\n near.push(ele);\n }\n }\n\n if (ele.isEdge() && (sqDist == null || sqDist < minSqDist)) {\n if (nearEdge) {\n // then replace existing edge\n // can replace only if same z-index\n if (nearEdge.pstyle('z-compound-depth').value === ele.pstyle('z-compound-depth').value && nearEdge.pstyle('z-compound-depth').value === ele.pstyle('z-compound-depth').value) {\n for (var i = 0; i < near.length; i++) {\n if (near[i].isEdge()) {\n near[i] = ele;\n nearEdge = ele;\n minSqDist = sqDist != null ? sqDist : minSqDist;\n break;\n }\n }\n }\n } else {\n near.push(ele);\n nearEdge = ele;\n minSqDist = sqDist != null ? sqDist : minSqDist;\n }\n }\n }\n\n function checkNode(node) {\n var width = node.outerWidth() + 2 * nodeThreshold;\n var height = node.outerHeight() + 2 * nodeThreshold;\n var hw = width / 2;\n var hh = height / 2;\n var pos = node.position();\n\n if (pos.x - hw <= x && x <= pos.x + hw // bb check x\n && pos.y - hh <= y && y <= pos.y + hh // bb check y\n ) {\n var shape = r.nodeShapes[self.getNodeShape(node)];\n\n if (shape.checkPoint(x, y, 0, width, height, pos.x, pos.y)) {\n addEle(node, 0);\n return true;\n }\n }\n }\n\n function checkEdge(edge) {\n var _p = edge._private;\n var rs = _p.rscratch;\n var styleWidth = edge.pstyle('width').pfValue;\n var scale = edge.pstyle('arrow-scale').value;\n var width = styleWidth / 2 + edgeThreshold; // more like a distance radius from centre\n\n var widthSq = width * width;\n var width2 = width * 2;\n var src = _p.source;\n var tgt = _p.target;\n var sqDist;\n\n if (rs.edgeType === 'segments' || rs.edgeType === 'straight' || rs.edgeType === 'haystack') {\n var pts = rs.allpts;\n\n for (var i = 0; i + 3 < pts.length; i += 2) {\n if (inLineVicinity(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3], width2) && widthSq > (sqDist = sqdistToFiniteLine(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3]))) {\n addEle(edge, sqDist);\n return true;\n }\n }\n } else if (rs.edgeType === 'bezier' || rs.edgeType === 'multibezier' || rs.edgeType === 'self' || rs.edgeType === 'compound') {\n var pts = rs.allpts;\n\n for (var i = 0; i + 5 < rs.allpts.length; i += 4) {\n if (inBezierVicinity(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3], pts[i + 4], pts[i + 5], width2) && widthSq > (sqDist = sqdistToQuadraticBezier(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3], pts[i + 4], pts[i + 5]))) {\n addEle(edge, sqDist);\n return true;\n }\n }\n } // if we're close to the edge but didn't hit it, maybe we hit its arrows\n\n\n var src = src || _p.source;\n var tgt = tgt || _p.target;\n var arSize = self.getArrowWidth(styleWidth, scale);\n var arrows = [{\n name: 'source',\n x: rs.arrowStartX,\n y: rs.arrowStartY,\n angle: rs.srcArrowAngle\n }, {\n name: 'target',\n x: rs.arrowEndX,\n y: rs.arrowEndY,\n angle: rs.tgtArrowAngle\n }, {\n name: 'mid-source',\n x: rs.midX,\n y: rs.midY,\n angle: rs.midsrcArrowAngle\n }, {\n name: 'mid-target',\n x: rs.midX,\n y: rs.midY,\n angle: rs.midtgtArrowAngle\n }];\n\n for (var i = 0; i < arrows.length; i++) {\n var ar = arrows[i];\n var shape = r.arrowShapes[edge.pstyle(ar.name + '-arrow-shape').value];\n var edgeWidth = edge.pstyle('width').pfValue;\n\n if (shape.roughCollide(x, y, arSize, ar.angle, {\n x: ar.x,\n y: ar.y\n }, edgeWidth, edgeThreshold) && shape.collide(x, y, arSize, ar.angle, {\n x: ar.x,\n y: ar.y\n }, edgeWidth, edgeThreshold)) {\n addEle(edge);\n return true;\n }\n } // for compound graphs, hitting edge may actually want a connected node instead (b/c edge may have greater z-index precedence)\n\n\n if (hasCompounds && near.length > 0) {\n checkNode(src);\n checkNode(tgt);\n }\n }\n\n function preprop(obj, name, pre) {\n return getPrefixedProperty(obj, name, pre);\n }\n\n function checkLabel(ele, prefix) {\n var _p = ele._private;\n var th = labelThreshold;\n var prefixDash;\n\n if (prefix) {\n prefixDash = prefix + '-';\n } else {\n prefixDash = '';\n }\n\n ele.boundingBox();\n var bb = _p.labelBounds[prefix || 'main'];\n var text = ele.pstyle(prefixDash + 'label').value;\n var eventsEnabled = ele.pstyle('text-events').strValue === 'yes';\n\n if (!eventsEnabled || !text) {\n return;\n }\n\n var lx = preprop(_p.rscratch, 'labelX', prefix);\n var ly = preprop(_p.rscratch, 'labelY', prefix);\n var theta = preprop(_p.rscratch, 'labelAngle', prefix);\n var ox = ele.pstyle(prefixDash + 'text-margin-x').pfValue;\n var oy = ele.pstyle(prefixDash + 'text-margin-y').pfValue;\n var lx1 = bb.x1 - th - ox; // (-ox, -oy) as bb already includes margin\n\n var lx2 = bb.x2 + th - ox; // and rotation is about (lx, ly)\n\n var ly1 = bb.y1 - th - oy;\n var ly2 = bb.y2 + th - oy;\n\n if (theta) {\n var cos = Math.cos(theta);\n var sin = Math.sin(theta);\n\n var rotate = function rotate(x, y) {\n x = x - lx;\n y = y - ly;\n return {\n x: x * cos - y * sin + lx,\n y: x * sin + y * cos + ly\n };\n };\n\n var px1y1 = rotate(lx1, ly1);\n var px1y2 = rotate(lx1, ly2);\n var px2y1 = rotate(lx2, ly1);\n var px2y2 = rotate(lx2, ly2);\n var points = [// with the margin added after the rotation is applied\n px1y1.x + ox, px1y1.y + oy, px2y1.x + ox, px2y1.y + oy, px2y2.x + ox, px2y2.y + oy, px1y2.x + ox, px1y2.y + oy];\n\n if (pointInsidePolygonPoints(x, y, points)) {\n addEle(ele);\n return true;\n }\n } else {\n // do a cheaper bb check\n if (inBoundingBox(bb, x, y)) {\n addEle(ele);\n return true;\n }\n }\n }\n\n for (var i = eles.length - 1; i >= 0; i--) {\n // reverse order for precedence\n var ele = eles[i];\n\n if (ele.isNode()) {\n checkNode(ele) || checkLabel(ele);\n } else {\n // then edge\n checkEdge(ele) || checkLabel(ele) || checkLabel(ele, 'source') || checkLabel(ele, 'target');\n }\n }\n\n return near;\n }; // 'Give me everything from this box'\n\n\n BRp$e.getAllInBox = function (x1, y1, x2, y2) {\n var eles = this.getCachedZSortedEles().interactive;\n var box = [];\n var x1c = Math.min(x1, x2);\n var x2c = Math.max(x1, x2);\n var y1c = Math.min(y1, y2);\n var y2c = Math.max(y1, y2);\n x1 = x1c;\n x2 = x2c;\n y1 = y1c;\n y2 = y2c;\n var boxBb = makeBoundingBox({\n x1: x1,\n y1: y1,\n x2: x2,\n y2: y2\n });\n\n for (var e = 0; e < eles.length; e++) {\n var ele = eles[e];\n\n if (ele.isNode()) {\n var node = ele;\n var nodeBb = node.boundingBox({\n includeNodes: true,\n includeEdges: false,\n includeLabels: false\n });\n\n if (boundingBoxesIntersect(boxBb, nodeBb) && !boundingBoxInBoundingBox(nodeBb, boxBb)) {\n box.push(node);\n }\n } else {\n var edge = ele;\n var _p = edge._private;\n var rs = _p.rscratch;\n\n if (rs.startX != null && rs.startY != null && !inBoundingBox(boxBb, rs.startX, rs.startY)) {\n continue;\n }\n\n if (rs.endX != null && rs.endY != null && !inBoundingBox(boxBb, rs.endX, rs.endY)) {\n continue;\n }\n\n if (rs.edgeType === 'bezier' || rs.edgeType === 'multibezier' || rs.edgeType === 'self' || rs.edgeType === 'compound' || rs.edgeType === 'segments' || rs.edgeType === 'haystack') {\n var pts = _p.rstyle.bezierPts || _p.rstyle.linePts || _p.rstyle.haystackPts;\n var allInside = true;\n\n for (var i = 0; i < pts.length; i++) {\n if (!pointInBoundingBox(boxBb, pts[i])) {\n allInside = false;\n break;\n }\n }\n\n if (allInside) {\n box.push(edge);\n }\n } else if (rs.edgeType === 'haystack' || rs.edgeType === 'straight') {\n box.push(edge);\n }\n }\n }\n\n return box;\n };\n\n var BRp$d = {};\n\n BRp$d.calculateArrowAngles = function (edge) {\n var rs = edge._private.rscratch;\n var isHaystack = rs.edgeType === 'haystack';\n var isBezier = rs.edgeType === 'bezier';\n var isMultibezier = rs.edgeType === 'multibezier';\n var isSegments = rs.edgeType === 'segments';\n var isCompound = rs.edgeType === 'compound';\n var isSelf = rs.edgeType === 'self'; // Displacement gives direction for arrowhead orientation\n\n var dispX, dispY;\n var startX, startY, endX, endY, midX, midY;\n\n if (isHaystack) {\n startX = rs.haystackPts[0];\n startY = rs.haystackPts[1];\n endX = rs.haystackPts[2];\n endY = rs.haystackPts[3];\n } else {\n startX = rs.arrowStartX;\n startY = rs.arrowStartY;\n endX = rs.arrowEndX;\n endY = rs.arrowEndY;\n }\n\n midX = rs.midX;\n midY = rs.midY; // source\n //\n\n if (isSegments) {\n dispX = startX - rs.segpts[0];\n dispY = startY - rs.segpts[1];\n } else if (isMultibezier || isCompound || isSelf || isBezier) {\n var pts = rs.allpts;\n var bX = qbezierAt(pts[0], pts[2], pts[4], 0.1);\n var bY = qbezierAt(pts[1], pts[3], pts[5], 0.1);\n dispX = startX - bX;\n dispY = startY - bY;\n } else {\n dispX = startX - midX;\n dispY = startY - midY;\n }\n\n rs.srcArrowAngle = getAngleFromDisp(dispX, dispY); // mid target\n //\n\n var midX = rs.midX;\n var midY = rs.midY;\n\n if (isHaystack) {\n midX = (startX + endX) / 2;\n midY = (startY + endY) / 2;\n }\n\n dispX = endX - startX;\n dispY = endY - startY;\n\n if (isSegments) {\n var pts = rs.allpts;\n\n if (pts.length / 2 % 2 === 0) {\n var i2 = pts.length / 2;\n var i1 = i2 - 2;\n dispX = pts[i2] - pts[i1];\n dispY = pts[i2 + 1] - pts[i1 + 1];\n } else {\n var i2 = pts.length / 2 - 1;\n var i1 = i2 - 2;\n var i3 = i2 + 2;\n dispX = pts[i2] - pts[i1];\n dispY = pts[i2 + 1] - pts[i1 + 1];\n }\n } else if (isMultibezier || isCompound || isSelf) {\n var pts = rs.allpts;\n var cpts = rs.ctrlpts;\n var bp0x, bp0y;\n var bp1x, bp1y;\n\n if (cpts.length / 2 % 2 === 0) {\n var p0 = pts.length / 2 - 1; // startpt\n\n var ic = p0 + 2;\n var p1 = ic + 2;\n bp0x = qbezierAt(pts[p0], pts[ic], pts[p1], 0.0);\n bp0y = qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.0);\n bp1x = qbezierAt(pts[p0], pts[ic], pts[p1], 0.0001);\n bp1y = qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.0001);\n } else {\n var ic = pts.length / 2 - 1; // ctrpt\n\n var p0 = ic - 2; // startpt\n\n var p1 = ic + 2; // endpt\n\n bp0x = qbezierAt(pts[p0], pts[ic], pts[p1], 0.4999);\n bp0y = qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.4999);\n bp1x = qbezierAt(pts[p0], pts[ic], pts[p1], 0.5);\n bp1y = qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.5);\n }\n\n dispX = bp1x - bp0x;\n dispY = bp1y - bp0y;\n }\n\n rs.midtgtArrowAngle = getAngleFromDisp(dispX, dispY);\n rs.midDispX = dispX;\n rs.midDispY = dispY; // mid source\n //\n\n dispX *= -1;\n dispY *= -1;\n\n if (isSegments) {\n var pts = rs.allpts;\n\n if (pts.length / 2 % 2 === 0) ; else {\n var i2 = pts.length / 2 - 1;\n var i3 = i2 + 2;\n dispX = -(pts[i3] - pts[i2]);\n dispY = -(pts[i3 + 1] - pts[i2 + 1]);\n }\n }\n\n rs.midsrcArrowAngle = getAngleFromDisp(dispX, dispY); // target\n //\n\n if (isSegments) {\n dispX = endX - rs.segpts[rs.segpts.length - 2];\n dispY = endY - rs.segpts[rs.segpts.length - 1];\n } else if (isMultibezier || isCompound || isSelf || isBezier) {\n var pts = rs.allpts;\n var l = pts.length;\n var bX = qbezierAt(pts[l - 6], pts[l - 4], pts[l - 2], 0.9);\n var bY = qbezierAt(pts[l - 5], pts[l - 3], pts[l - 1], 0.9);\n dispX = endX - bX;\n dispY = endY - bY;\n } else {\n dispX = endX - midX;\n dispY = endY - midY;\n }\n\n rs.tgtArrowAngle = getAngleFromDisp(dispX, dispY);\n };\n\n BRp$d.getArrowWidth = BRp$d.getArrowHeight = function (edgeWidth, scale) {\n var cache = this.arrowWidthCache = this.arrowWidthCache || {};\n var cachedVal = cache[edgeWidth + ', ' + scale];\n\n if (cachedVal) {\n return cachedVal;\n }\n\n cachedVal = Math.max(Math.pow(edgeWidth * 13.37, 0.9), 29) * scale;\n cache[edgeWidth + ', ' + scale] = cachedVal;\n return cachedVal;\n };\n\n var BRp$c = {};\n\n BRp$c.findHaystackPoints = function (edges) {\n for (var i = 0; i < edges.length; i++) {\n var edge = edges[i];\n var _p = edge._private;\n var rs = _p.rscratch;\n\n if (!rs.haystack) {\n var angle = Math.random() * 2 * Math.PI;\n rs.source = {\n x: Math.cos(angle),\n y: Math.sin(angle)\n };\n angle = Math.random() * 2 * Math.PI;\n rs.target = {\n x: Math.cos(angle),\n y: Math.sin(angle)\n };\n }\n\n var src = _p.source;\n var tgt = _p.target;\n var srcPos = src.position();\n var tgtPos = tgt.position();\n var srcW = src.width();\n var tgtW = tgt.width();\n var srcH = src.height();\n var tgtH = tgt.height();\n var radius = edge.pstyle('haystack-radius').value;\n var halfRadius = radius / 2; // b/c have to half width/height\n\n rs.haystackPts = rs.allpts = [rs.source.x * srcW * halfRadius + srcPos.x, rs.source.y * srcH * halfRadius + srcPos.y, rs.target.x * tgtW * halfRadius + tgtPos.x, rs.target.y * tgtH * halfRadius + tgtPos.y];\n rs.midX = (rs.allpts[0] + rs.allpts[2]) / 2;\n rs.midY = (rs.allpts[1] + rs.allpts[3]) / 2; // always override as haystack in case set to different type previously\n\n rs.edgeType = 'haystack';\n rs.haystack = true;\n this.storeEdgeProjections(edge);\n this.calculateArrowAngles(edge);\n this.recalculateEdgeLabelProjections(edge);\n this.calculateLabelAngles(edge);\n }\n };\n\n BRp$c.findSegmentsPoints = function (edge, pairInfo) {\n // Segments (multiple straight lines)\n var rs = edge._private.rscratch;\n var posPts = pairInfo.posPts,\n intersectionPts = pairInfo.intersectionPts,\n vectorNormInverse = pairInfo.vectorNormInverse;\n var edgeDistances = edge.pstyle('edge-distances').value;\n var segmentWs = edge.pstyle('segment-weights');\n var segmentDs = edge.pstyle('segment-distances');\n var segmentsN = Math.min(segmentWs.pfValue.length, segmentDs.pfValue.length);\n rs.edgeType = 'segments';\n rs.segpts = [];\n\n for (var s = 0; s < segmentsN; s++) {\n var w = segmentWs.pfValue[s];\n var d = segmentDs.pfValue[s];\n var w1 = 1 - w;\n var w2 = w;\n var midptPts = edgeDistances === 'node-position' ? posPts : intersectionPts;\n var adjustedMidpt = {\n x: midptPts.x1 * w1 + midptPts.x2 * w2,\n y: midptPts.y1 * w1 + midptPts.y2 * w2\n };\n rs.segpts.push(adjustedMidpt.x + vectorNormInverse.x * d, adjustedMidpt.y + vectorNormInverse.y * d);\n }\n };\n\n BRp$c.findLoopPoints = function (edge, pairInfo, i, edgeIsUnbundled) {\n // Self-edge\n var rs = edge._private.rscratch;\n var dirCounts = pairInfo.dirCounts,\n srcPos = pairInfo.srcPos;\n var ctrlptDists = edge.pstyle('control-point-distances');\n var ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[0] : undefined;\n var loopDir = edge.pstyle('loop-direction').pfValue;\n var loopSwp = edge.pstyle('loop-sweep').pfValue;\n var stepSize = edge.pstyle('control-point-step-size').pfValue;\n rs.edgeType = 'self';\n var j = i;\n var loopDist = stepSize;\n\n if (edgeIsUnbundled) {\n j = 0;\n loopDist = ctrlptDist;\n }\n\n var loopAngle = loopDir - Math.PI / 2;\n var outAngle = loopAngle - loopSwp / 2;\n var inAngle = loopAngle + loopSwp / 2; // increase by step size for overlapping loops, keyed on direction and sweep values\n\n var dc = String(loopDir + '_' + loopSwp);\n j = dirCounts[dc] === undefined ? dirCounts[dc] = 0 : ++dirCounts[dc];\n rs.ctrlpts = [srcPos.x + Math.cos(outAngle) * 1.4 * loopDist * (j / 3 + 1), srcPos.y + Math.sin(outAngle) * 1.4 * loopDist * (j / 3 + 1), srcPos.x + Math.cos(inAngle) * 1.4 * loopDist * (j / 3 + 1), srcPos.y + Math.sin(inAngle) * 1.4 * loopDist * (j / 3 + 1)];\n };\n\n BRp$c.findCompoundLoopPoints = function (edge, pairInfo, i, edgeIsUnbundled) {\n // Compound edge\n var rs = edge._private.rscratch;\n rs.edgeType = 'compound';\n var srcPos = pairInfo.srcPos,\n tgtPos = pairInfo.tgtPos,\n srcW = pairInfo.srcW,\n srcH = pairInfo.srcH,\n tgtW = pairInfo.tgtW,\n tgtH = pairInfo.tgtH;\n var stepSize = edge.pstyle('control-point-step-size').pfValue;\n var ctrlptDists = edge.pstyle('control-point-distances');\n var ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[0] : undefined;\n var j = i;\n var loopDist = stepSize;\n\n if (edgeIsUnbundled) {\n j = 0;\n loopDist = ctrlptDist;\n }\n\n var loopW = 50;\n var loopaPos = {\n x: srcPos.x - srcW / 2,\n y: srcPos.y - srcH / 2\n };\n var loopbPos = {\n x: tgtPos.x - tgtW / 2,\n y: tgtPos.y - tgtH / 2\n };\n var loopPos = {\n x: Math.min(loopaPos.x, loopbPos.x),\n y: Math.min(loopaPos.y, loopbPos.y)\n }; // avoids cases with impossible beziers\n\n var minCompoundStretch = 0.5;\n var compoundStretchA = Math.max(minCompoundStretch, Math.log(srcW * 0.01));\n var compoundStretchB = Math.max(minCompoundStretch, Math.log(tgtW * 0.01));\n rs.ctrlpts = [loopPos.x, loopPos.y - (1 + Math.pow(loopW, 1.12) / 100) * loopDist * (j / 3 + 1) * compoundStretchA, loopPos.x - (1 + Math.pow(loopW, 1.12) / 100) * loopDist * (j / 3 + 1) * compoundStretchB, loopPos.y];\n };\n\n BRp$c.findStraightEdgePoints = function (edge) {\n // Straight edge within bundle\n edge._private.rscratch.edgeType = 'straight';\n };\n\n BRp$c.findBezierPoints = function (edge, pairInfo, i, edgeIsUnbundled, edgeIsSwapped) {\n var rs = edge._private.rscratch;\n var vectorNormInverse = pairInfo.vectorNormInverse,\n posPts = pairInfo.posPts,\n intersectionPts = pairInfo.intersectionPts;\n var edgeDistances = edge.pstyle('edge-distances').value;\n var stepSize = edge.pstyle('control-point-step-size').pfValue;\n var ctrlptDists = edge.pstyle('control-point-distances');\n var ctrlptWs = edge.pstyle('control-point-weights');\n var bezierN = ctrlptDists && ctrlptWs ? Math.min(ctrlptDists.value.length, ctrlptWs.value.length) : 1;\n var ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[0] : undefined;\n var ctrlptWeight = ctrlptWs.value[0]; // (Multi)bezier\n\n var multi = edgeIsUnbundled;\n rs.edgeType = multi ? 'multibezier' : 'bezier';\n rs.ctrlpts = [];\n\n for (var b = 0; b < bezierN; b++) {\n var normctrlptDist = (0.5 - pairInfo.eles.length / 2 + i) * stepSize * (edgeIsSwapped ? -1 : 1);\n var manctrlptDist = void 0;\n var sign = signum(normctrlptDist);\n\n if (multi) {\n ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[b] : stepSize; // fall back on step size\n\n ctrlptWeight = ctrlptWs.value[b];\n }\n\n if (edgeIsUnbundled) {\n // multi or single unbundled\n manctrlptDist = ctrlptDist;\n } else {\n manctrlptDist = ctrlptDist !== undefined ? sign * ctrlptDist : undefined;\n }\n\n var distanceFromMidpoint = manctrlptDist !== undefined ? manctrlptDist : normctrlptDist;\n var w1 = 1 - ctrlptWeight;\n var w2 = ctrlptWeight;\n var midptPts = edgeDistances === 'node-position' ? posPts : intersectionPts;\n var adjustedMidpt = {\n x: midptPts.x1 * w1 + midptPts.x2 * w2,\n y: midptPts.y1 * w1 + midptPts.y2 * w2\n };\n rs.ctrlpts.push(adjustedMidpt.x + vectorNormInverse.x * distanceFromMidpoint, adjustedMidpt.y + vectorNormInverse.y * distanceFromMidpoint);\n }\n };\n\n BRp$c.findTaxiPoints = function (edge, pairInfo) {\n // Taxicab geometry with two turns maximum\n var rs = edge._private.rscratch;\n rs.edgeType = 'segments';\n var VERTICAL = 'vertical';\n var HORIZONTAL = 'horizontal';\n var LEFTWARD = 'leftward';\n var RIGHTWARD = 'rightward';\n var DOWNWARD = 'downward';\n var UPWARD = 'upward';\n var AUTO = 'auto';\n var posPts = pairInfo.posPts,\n srcW = pairInfo.srcW,\n srcH = pairInfo.srcH,\n tgtW = pairInfo.tgtW,\n tgtH = pairInfo.tgtH;\n var edgeDistances = edge.pstyle('edge-distances').value;\n var dIncludesNodeBody = edgeDistances !== 'node-position';\n var taxiDir = edge.pstyle('taxi-direction').value;\n var rawTaxiDir = taxiDir; // unprocessed value\n\n var taxiTurn = edge.pstyle('taxi-turn');\n var turnIsPercent = taxiTurn.units === '%';\n var taxiTurnPfVal = taxiTurn.pfValue;\n var turnIsNegative = taxiTurnPfVal < 0; // i.e. from target side\n\n var minD = edge.pstyle('taxi-turn-min-distance').pfValue;\n var dw = dIncludesNodeBody ? (srcW + tgtW) / 2 : 0;\n var dh = dIncludesNodeBody ? (srcH + tgtH) / 2 : 0;\n var pdx = posPts.x2 - posPts.x1;\n var pdy = posPts.y2 - posPts.y1; // take away the effective w/h from the magnitude of the delta value\n\n var subDWH = function subDWH(dxy, dwh) {\n if (dxy > 0) {\n return Math.max(dxy - dwh, 0);\n } else {\n return Math.min(dxy + dwh, 0);\n }\n };\n\n var dx = subDWH(pdx, dw);\n var dy = subDWH(pdy, dh);\n var isExplicitDir = false;\n\n if (rawTaxiDir === AUTO) {\n taxiDir = Math.abs(dx) > Math.abs(dy) ? HORIZONTAL : VERTICAL;\n } else if (rawTaxiDir === UPWARD || rawTaxiDir === DOWNWARD) {\n taxiDir = VERTICAL;\n isExplicitDir = true;\n } else if (rawTaxiDir === LEFTWARD || rawTaxiDir === RIGHTWARD) {\n taxiDir = HORIZONTAL;\n isExplicitDir = true;\n }\n\n var isVert = taxiDir === VERTICAL;\n var l = isVert ? dy : dx;\n var pl = isVert ? pdy : pdx;\n var sgnL = signum(pl);\n var forcedDir = false;\n\n if (!(isExplicitDir && (turnIsPercent || turnIsNegative)) // forcing in this case would cause weird growing in the opposite direction\n && (rawTaxiDir === DOWNWARD && pl < 0 || rawTaxiDir === UPWARD && pl > 0 || rawTaxiDir === LEFTWARD && pl > 0 || rawTaxiDir === RIGHTWARD && pl < 0)) {\n sgnL *= -1;\n l = sgnL * Math.abs(l);\n forcedDir = true;\n }\n\n var d;\n\n if (turnIsPercent) {\n var p = taxiTurnPfVal < 0 ? 1 + taxiTurnPfVal : taxiTurnPfVal;\n d = p * l;\n } else {\n var k = taxiTurnPfVal < 0 ? l : 0;\n d = k + taxiTurnPfVal * sgnL;\n }\n\n var getIsTooClose = function getIsTooClose(d) {\n return Math.abs(d) < minD || Math.abs(d) >= Math.abs(l);\n };\n\n var isTooCloseSrc = getIsTooClose(d);\n var isTooCloseTgt = getIsTooClose(Math.abs(l) - Math.abs(d));\n var isTooClose = isTooCloseSrc || isTooCloseTgt;\n\n if (isTooClose && !forcedDir) {\n // non-ideal routing\n if (isVert) {\n // vertical fallbacks\n var lShapeInsideSrc = Math.abs(pl) <= srcH / 2;\n var lShapeInsideTgt = Math.abs(pdx) <= tgtW / 2;\n\n if (lShapeInsideSrc) {\n // horizontal Z-shape (direction not respected)\n var x = (posPts.x1 + posPts.x2) / 2;\n var y1 = posPts.y1,\n y2 = posPts.y2;\n rs.segpts = [x, y1, x, y2];\n } else if (lShapeInsideTgt) {\n // vertical Z-shape (distance not respected)\n var y = (posPts.y1 + posPts.y2) / 2;\n var x1 = posPts.x1,\n x2 = posPts.x2;\n rs.segpts = [x1, y, x2, y];\n } else {\n // L-shape fallback (turn distance not respected, but works well with tree siblings)\n rs.segpts = [posPts.x1, posPts.y2];\n }\n } else {\n // horizontal fallbacks\n var _lShapeInsideSrc = Math.abs(pl) <= srcW / 2;\n\n var _lShapeInsideTgt = Math.abs(pdy) <= tgtH / 2;\n\n if (_lShapeInsideSrc) {\n // vertical Z-shape (direction not respected)\n var _y = (posPts.y1 + posPts.y2) / 2;\n\n var _x = posPts.x1,\n _x2 = posPts.x2;\n rs.segpts = [_x, _y, _x2, _y];\n } else if (_lShapeInsideTgt) {\n // horizontal Z-shape (turn distance not respected)\n var _x3 = (posPts.x1 + posPts.x2) / 2;\n\n var _y2 = posPts.y1,\n _y3 = posPts.y2;\n rs.segpts = [_x3, _y2, _x3, _y3];\n } else {\n // L-shape (turn distance not respected, but works well for tree siblings)\n rs.segpts = [posPts.x2, posPts.y1];\n }\n }\n } else {\n // ideal routing\n if (isVert) {\n var _y4 = posPts.y1 + d + (dIncludesNodeBody ? srcH / 2 * sgnL : 0);\n\n var _x4 = posPts.x1,\n _x5 = posPts.x2;\n rs.segpts = [_x4, _y4, _x5, _y4];\n } else {\n // horizontal\n var _x6 = posPts.x1 + d + (dIncludesNodeBody ? srcW / 2 * sgnL : 0);\n\n var _y5 = posPts.y1,\n _y6 = posPts.y2;\n rs.segpts = [_x6, _y5, _x6, _y6];\n }\n }\n };\n\n BRp$c.tryToCorrectInvalidPoints = function (edge, pairInfo) {\n var rs = edge._private.rscratch; // can only correct beziers for now...\n\n if (rs.edgeType === 'bezier') {\n var srcPos = pairInfo.srcPos,\n tgtPos = pairInfo.tgtPos,\n srcW = pairInfo.srcW,\n srcH = pairInfo.srcH,\n tgtW = pairInfo.tgtW,\n tgtH = pairInfo.tgtH,\n srcShape = pairInfo.srcShape,\n tgtShape = pairInfo.tgtShape;\n var badStart = !number$1(rs.startX) || !number$1(rs.startY);\n var badAStart = !number$1(rs.arrowStartX) || !number$1(rs.arrowStartY);\n var badEnd = !number$1(rs.endX) || !number$1(rs.endY);\n var badAEnd = !number$1(rs.arrowEndX) || !number$1(rs.arrowEndY);\n var minCpADistFactor = 3;\n var arrowW = this.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.arrowShapeWidth;\n var minCpADist = minCpADistFactor * arrowW;\n var startACpDist = dist({\n x: rs.ctrlpts[0],\n y: rs.ctrlpts[1]\n }, {\n x: rs.startX,\n y: rs.startY\n });\n var closeStartACp = startACpDist < minCpADist;\n var endACpDist = dist({\n x: rs.ctrlpts[0],\n y: rs.ctrlpts[1]\n }, {\n x: rs.endX,\n y: rs.endY\n });\n var closeEndACp = endACpDist < minCpADist;\n var overlapping = false;\n\n if (badStart || badAStart || closeStartACp) {\n overlapping = true; // project control point along line from src centre to outside the src shape\n // (otherwise intersection will yield nothing)\n\n var cpD = {\n // delta\n x: rs.ctrlpts[0] - srcPos.x,\n y: rs.ctrlpts[1] - srcPos.y\n };\n var cpL = Math.sqrt(cpD.x * cpD.x + cpD.y * cpD.y); // length of line\n\n var cpM = {\n // normalised delta\n x: cpD.x / cpL,\n y: cpD.y / cpL\n };\n var radius = Math.max(srcW, srcH);\n var cpProj = {\n // *2 radius guarantees outside shape\n x: rs.ctrlpts[0] + cpM.x * 2 * radius,\n y: rs.ctrlpts[1] + cpM.y * 2 * radius\n };\n var srcCtrlPtIntn = srcShape.intersectLine(srcPos.x, srcPos.y, srcW, srcH, cpProj.x, cpProj.y, 0);\n\n if (closeStartACp) {\n rs.ctrlpts[0] = rs.ctrlpts[0] + cpM.x * (minCpADist - startACpDist);\n rs.ctrlpts[1] = rs.ctrlpts[1] + cpM.y * (minCpADist - startACpDist);\n } else {\n rs.ctrlpts[0] = srcCtrlPtIntn[0] + cpM.x * minCpADist;\n rs.ctrlpts[1] = srcCtrlPtIntn[1] + cpM.y * minCpADist;\n }\n }\n\n if (badEnd || badAEnd || closeEndACp) {\n overlapping = true; // project control point along line from tgt centre to outside the tgt shape\n // (otherwise intersection will yield nothing)\n\n var _cpD = {\n // delta\n x: rs.ctrlpts[0] - tgtPos.x,\n y: rs.ctrlpts[1] - tgtPos.y\n };\n\n var _cpL = Math.sqrt(_cpD.x * _cpD.x + _cpD.y * _cpD.y); // length of line\n\n\n var _cpM = {\n // normalised delta\n x: _cpD.x / _cpL,\n y: _cpD.y / _cpL\n };\n\n var _radius = Math.max(srcW, srcH);\n\n var _cpProj = {\n // *2 radius guarantees outside shape\n x: rs.ctrlpts[0] + _cpM.x * 2 * _radius,\n y: rs.ctrlpts[1] + _cpM.y * 2 * _radius\n };\n var tgtCtrlPtIntn = tgtShape.intersectLine(tgtPos.x, tgtPos.y, tgtW, tgtH, _cpProj.x, _cpProj.y, 0);\n\n if (closeEndACp) {\n rs.ctrlpts[0] = rs.ctrlpts[0] + _cpM.x * (minCpADist - endACpDist);\n rs.ctrlpts[1] = rs.ctrlpts[1] + _cpM.y * (minCpADist - endACpDist);\n } else {\n rs.ctrlpts[0] = tgtCtrlPtIntn[0] + _cpM.x * minCpADist;\n rs.ctrlpts[1] = tgtCtrlPtIntn[1] + _cpM.y * minCpADist;\n }\n }\n\n if (overlapping) {\n // recalc endpts\n this.findEndpoints(edge);\n }\n }\n };\n\n BRp$c.storeAllpts = function (edge) {\n var rs = edge._private.rscratch;\n\n if (rs.edgeType === 'multibezier' || rs.edgeType === 'bezier' || rs.edgeType === 'self' || rs.edgeType === 'compound') {\n rs.allpts = [];\n rs.allpts.push(rs.startX, rs.startY);\n\n for (var b = 0; b + 1 < rs.ctrlpts.length; b += 2) {\n // ctrl pt itself\n rs.allpts.push(rs.ctrlpts[b], rs.ctrlpts[b + 1]); // the midpt between ctrlpts as intermediate destination pts\n\n if (b + 3 < rs.ctrlpts.length) {\n rs.allpts.push((rs.ctrlpts[b] + rs.ctrlpts[b + 2]) / 2, (rs.ctrlpts[b + 1] + rs.ctrlpts[b + 3]) / 2);\n }\n }\n\n rs.allpts.push(rs.endX, rs.endY);\n var m, mt;\n\n if (rs.ctrlpts.length / 2 % 2 === 0) {\n m = rs.allpts.length / 2 - 1;\n rs.midX = rs.allpts[m];\n rs.midY = rs.allpts[m + 1];\n } else {\n m = rs.allpts.length / 2 - 3;\n mt = 0.5;\n rs.midX = qbezierAt(rs.allpts[m], rs.allpts[m + 2], rs.allpts[m + 4], mt);\n rs.midY = qbezierAt(rs.allpts[m + 1], rs.allpts[m + 3], rs.allpts[m + 5], mt);\n }\n } else if (rs.edgeType === 'straight') {\n // need to calc these after endpts\n rs.allpts = [rs.startX, rs.startY, rs.endX, rs.endY]; // default midpt for labels etc\n\n rs.midX = (rs.startX + rs.endX + rs.arrowStartX + rs.arrowEndX) / 4;\n rs.midY = (rs.startY + rs.endY + rs.arrowStartY + rs.arrowEndY) / 4;\n } else if (rs.edgeType === 'segments') {\n rs.allpts = [];\n rs.allpts.push(rs.startX, rs.startY);\n rs.allpts.push.apply(rs.allpts, rs.segpts);\n rs.allpts.push(rs.endX, rs.endY);\n\n if (rs.segpts.length % 4 === 0) {\n var i2 = rs.segpts.length / 2;\n var i1 = i2 - 2;\n rs.midX = (rs.segpts[i1] + rs.segpts[i2]) / 2;\n rs.midY = (rs.segpts[i1 + 1] + rs.segpts[i2 + 1]) / 2;\n } else {\n var _i = rs.segpts.length / 2 - 1;\n\n rs.midX = rs.segpts[_i];\n rs.midY = rs.segpts[_i + 1];\n }\n }\n };\n\n BRp$c.checkForInvalidEdgeWarning = function (edge) {\n var rs = edge[0]._private.rscratch;\n\n if (rs.nodesOverlap || number$1(rs.startX) && number$1(rs.startY) && number$1(rs.endX) && number$1(rs.endY)) {\n rs.loggedErr = false;\n } else {\n if (!rs.loggedErr) {\n rs.loggedErr = true;\n warn('Edge `' + edge.id() + '` has invalid endpoints and so it is impossible to draw. Adjust your edge style (e.g. control points) accordingly or use an alternative edge type. This is expected behaviour when the source node and the target node overlap.');\n }\n }\n };\n\n BRp$c.findEdgeControlPoints = function (edges) {\n var _this = this;\n\n if (!edges || edges.length === 0) {\n return;\n }\n\n var r = this;\n var cy = r.cy;\n var hasCompounds = cy.hasCompoundNodes();\n var hashTable = {\n map: new Map$2(),\n get: function get(pairId) {\n var map2 = this.map.get(pairId[0]);\n\n if (map2 != null) {\n return map2.get(pairId[1]);\n } else {\n return null;\n }\n },\n set: function set(pairId, val) {\n var map2 = this.map.get(pairId[0]);\n\n if (map2 == null) {\n map2 = new Map$2();\n this.map.set(pairId[0], map2);\n }\n\n map2.set(pairId[1], val);\n }\n };\n var pairIds = [];\n var haystackEdges = []; // create a table of edge (src, tgt) => list of edges between them\n\n for (var i = 0; i < edges.length; i++) {\n var edge = edges[i];\n var _p = edge._private;\n var curveStyle = edge.pstyle('curve-style').value; // ignore edges who are not to be displayed\n // they shouldn't take up space\n\n if (edge.removed() || !edge.takesUpSpace()) {\n continue;\n }\n\n if (curveStyle === 'haystack') {\n haystackEdges.push(edge);\n continue;\n }\n\n var edgeIsUnbundled = curveStyle === 'unbundled-bezier' || curveStyle === 'segments' || curveStyle === 'straight' || curveStyle === 'straight-triangle' || curveStyle === 'taxi';\n var edgeIsBezier = curveStyle === 'unbundled-bezier' || curveStyle === 'bezier';\n var src = _p.source;\n var tgt = _p.target;\n var srcIndex = src.poolIndex();\n var tgtIndex = tgt.poolIndex();\n var pairId = [srcIndex, tgtIndex].sort();\n var tableEntry = hashTable.get(pairId);\n\n if (tableEntry == null) {\n tableEntry = {\n eles: []\n };\n hashTable.set(pairId, tableEntry);\n pairIds.push(pairId);\n }\n\n tableEntry.eles.push(edge);\n\n if (edgeIsUnbundled) {\n tableEntry.hasUnbundled = true;\n }\n\n if (edgeIsBezier) {\n tableEntry.hasBezier = true;\n }\n } // for each pair (src, tgt), create the ctrl pts\n // Nested for loop is OK; total number of iterations for both loops = edgeCount\n\n\n var _loop = function _loop(p) {\n var pairId = pairIds[p];\n var pairInfo = hashTable.get(pairId);\n var swappedpairInfo = void 0;\n\n if (!pairInfo.hasUnbundled) {\n var pllEdges = pairInfo.eles[0].parallelEdges().filter(function (e) {\n return e.isBundledBezier();\n });\n clearArray(pairInfo.eles);\n pllEdges.forEach(function (edge) {\n return pairInfo.eles.push(edge);\n }); // for each pair id, the edges should be sorted by index\n\n pairInfo.eles.sort(function (edge1, edge2) {\n return edge1.poolIndex() - edge2.poolIndex();\n });\n }\n\n var firstEdge = pairInfo.eles[0];\n var src = firstEdge.source();\n var tgt = firstEdge.target(); // make sure src/tgt distinction is consistent w.r.t. pairId\n\n if (src.poolIndex() > tgt.poolIndex()) {\n var temp = src;\n src = tgt;\n tgt = temp;\n }\n\n var srcPos = pairInfo.srcPos = src.position();\n var tgtPos = pairInfo.tgtPos = tgt.position();\n var srcW = pairInfo.srcW = src.outerWidth();\n var srcH = pairInfo.srcH = src.outerHeight();\n var tgtW = pairInfo.tgtW = tgt.outerWidth();\n var tgtH = pairInfo.tgtH = tgt.outerHeight();\n\n var srcShape = pairInfo.srcShape = r.nodeShapes[_this.getNodeShape(src)];\n\n var tgtShape = pairInfo.tgtShape = r.nodeShapes[_this.getNodeShape(tgt)];\n\n pairInfo.dirCounts = {\n 'north': 0,\n 'west': 0,\n 'south': 0,\n 'east': 0,\n 'northwest': 0,\n 'southwest': 0,\n 'northeast': 0,\n 'southeast': 0\n };\n\n for (var _i2 = 0; _i2 < pairInfo.eles.length; _i2++) {\n var _edge = pairInfo.eles[_i2];\n var rs = _edge[0]._private.rscratch;\n\n var _curveStyle = _edge.pstyle('curve-style').value;\n\n var _edgeIsUnbundled = _curveStyle === 'unbundled-bezier' || _curveStyle === 'segments' || _curveStyle === 'taxi'; // whether the normalised pair order is the reverse of the edge's src-tgt order\n\n\n var edgeIsSwapped = !src.same(_edge.source());\n\n if (!pairInfo.calculatedIntersection && src !== tgt && (pairInfo.hasBezier || pairInfo.hasUnbundled)) {\n pairInfo.calculatedIntersection = true; // pt outside src shape to calc distance/displacement from src to tgt\n\n var srcOutside = srcShape.intersectLine(srcPos.x, srcPos.y, srcW, srcH, tgtPos.x, tgtPos.y, 0);\n var srcIntn = pairInfo.srcIntn = srcOutside; // pt outside tgt shape to calc distance/displacement from src to tgt\n\n var tgtOutside = tgtShape.intersectLine(tgtPos.x, tgtPos.y, tgtW, tgtH, srcPos.x, srcPos.y, 0);\n var tgtIntn = pairInfo.tgtIntn = tgtOutside;\n var intersectionPts = pairInfo.intersectionPts = {\n x1: srcOutside[0],\n x2: tgtOutside[0],\n y1: srcOutside[1],\n y2: tgtOutside[1]\n };\n var posPts = pairInfo.posPts = {\n x1: srcPos.x,\n x2: tgtPos.x,\n y1: srcPos.y,\n y2: tgtPos.y\n };\n var dy = tgtOutside[1] - srcOutside[1];\n var dx = tgtOutside[0] - srcOutside[0];\n var l = Math.sqrt(dx * dx + dy * dy);\n var vector = pairInfo.vector = {\n x: dx,\n y: dy\n };\n var vectorNorm = pairInfo.vectorNorm = {\n x: vector.x / l,\n y: vector.y / l\n };\n var vectorNormInverse = {\n x: -vectorNorm.y,\n y: vectorNorm.x\n }; // if node shapes overlap, then no ctrl pts to draw\n\n pairInfo.nodesOverlap = !number$1(l) || tgtShape.checkPoint(srcOutside[0], srcOutside[1], 0, tgtW, tgtH, tgtPos.x, tgtPos.y) || srcShape.checkPoint(tgtOutside[0], tgtOutside[1], 0, srcW, srcH, srcPos.x, srcPos.y);\n pairInfo.vectorNormInverse = vectorNormInverse;\n swappedpairInfo = {\n nodesOverlap: pairInfo.nodesOverlap,\n dirCounts: pairInfo.dirCounts,\n calculatedIntersection: true,\n hasBezier: pairInfo.hasBezier,\n hasUnbundled: pairInfo.hasUnbundled,\n eles: pairInfo.eles,\n srcPos: tgtPos,\n tgtPos: srcPos,\n srcW: tgtW,\n srcH: tgtH,\n tgtW: srcW,\n tgtH: srcH,\n srcIntn: tgtIntn,\n tgtIntn: srcIntn,\n srcShape: tgtShape,\n tgtShape: srcShape,\n posPts: {\n x1: posPts.x2,\n y1: posPts.y2,\n x2: posPts.x1,\n y2: posPts.y1\n },\n intersectionPts: {\n x1: intersectionPts.x2,\n y1: intersectionPts.y2,\n x2: intersectionPts.x1,\n y2: intersectionPts.y1\n },\n vector: {\n x: -vector.x,\n y: -vector.y\n },\n vectorNorm: {\n x: -vectorNorm.x,\n y: -vectorNorm.y\n },\n vectorNormInverse: {\n x: -vectorNormInverse.x,\n y: -vectorNormInverse.y\n }\n };\n }\n\n var passedPairInfo = edgeIsSwapped ? swappedpairInfo : pairInfo;\n rs.nodesOverlap = passedPairInfo.nodesOverlap;\n rs.srcIntn = passedPairInfo.srcIntn;\n rs.tgtIntn = passedPairInfo.tgtIntn;\n\n if (hasCompounds && (src.isParent() || src.isChild() || tgt.isParent() || tgt.isChild()) && (src.parents().anySame(tgt) || tgt.parents().anySame(src) || src.same(tgt) && src.isParent())) {\n _this.findCompoundLoopPoints(_edge, passedPairInfo, _i2, _edgeIsUnbundled);\n } else if (src === tgt) {\n _this.findLoopPoints(_edge, passedPairInfo, _i2, _edgeIsUnbundled);\n } else if (_curveStyle === 'segments') {\n _this.findSegmentsPoints(_edge, passedPairInfo);\n } else if (_curveStyle === 'taxi') {\n _this.findTaxiPoints(_edge, passedPairInfo);\n } else if (_curveStyle === 'straight' || !_edgeIsUnbundled && pairInfo.eles.length % 2 === 1 && _i2 === Math.floor(pairInfo.eles.length / 2)) {\n _this.findStraightEdgePoints(_edge);\n } else {\n _this.findBezierPoints(_edge, passedPairInfo, _i2, _edgeIsUnbundled, edgeIsSwapped);\n }\n\n _this.findEndpoints(_edge);\n\n _this.tryToCorrectInvalidPoints(_edge, passedPairInfo);\n\n _this.checkForInvalidEdgeWarning(_edge);\n\n _this.storeAllpts(_edge);\n\n _this.storeEdgeProjections(_edge);\n\n _this.calculateArrowAngles(_edge);\n\n _this.recalculateEdgeLabelProjections(_edge);\n\n _this.calculateLabelAngles(_edge);\n } // for pair edges\n\n };\n\n for (var p = 0; p < pairIds.length; p++) {\n _loop(p);\n } // for pair ids\n // haystacks avoid the expense of pairInfo stuff (intersections etc.)\n\n\n this.findHaystackPoints(haystackEdges);\n };\n\n function getPts(pts) {\n var retPts = [];\n\n if (pts == null) {\n return;\n }\n\n for (var i = 0; i < pts.length; i += 2) {\n var x = pts[i];\n var y = pts[i + 1];\n retPts.push({\n x: x,\n y: y\n });\n }\n\n return retPts;\n }\n\n BRp$c.getSegmentPoints = function (edge) {\n var rs = edge[0]._private.rscratch;\n var type = rs.edgeType;\n\n if (type === 'segments') {\n this.recalculateRenderedStyle(edge);\n return getPts(rs.segpts);\n }\n };\n\n BRp$c.getControlPoints = function (edge) {\n var rs = edge[0]._private.rscratch;\n var type = rs.edgeType;\n\n if (type === 'bezier' || type === 'multibezier' || type === 'self' || type === 'compound') {\n this.recalculateRenderedStyle(edge);\n return getPts(rs.ctrlpts);\n }\n };\n\n BRp$c.getEdgeMidpoint = function (edge) {\n var rs = edge[0]._private.rscratch;\n this.recalculateRenderedStyle(edge);\n return {\n x: rs.midX,\n y: rs.midY\n };\n };\n\n var BRp$b = {};\n\n BRp$b.manualEndptToPx = function (node, prop) {\n var r = this;\n var npos = node.position();\n var w = node.outerWidth();\n var h = node.outerHeight();\n\n if (prop.value.length === 2) {\n var p = [prop.pfValue[0], prop.pfValue[1]];\n\n if (prop.units[0] === '%') {\n p[0] = p[0] * w;\n }\n\n if (prop.units[1] === '%') {\n p[1] = p[1] * h;\n }\n\n p[0] += npos.x;\n p[1] += npos.y;\n return p;\n } else {\n var angle = prop.pfValue[0];\n angle = -Math.PI / 2 + angle; // start at 12 o'clock\n\n var l = 2 * Math.max(w, h);\n var _p = [npos.x + Math.cos(angle) * l, npos.y + Math.sin(angle) * l];\n return r.nodeShapes[this.getNodeShape(node)].intersectLine(npos.x, npos.y, w, h, _p[0], _p[1], 0);\n }\n };\n\n BRp$b.findEndpoints = function (edge) {\n var r = this;\n var intersect;\n var source = edge.source()[0];\n var target = edge.target()[0];\n var srcPos = source.position();\n var tgtPos = target.position();\n var tgtArShape = edge.pstyle('target-arrow-shape').value;\n var srcArShape = edge.pstyle('source-arrow-shape').value;\n var tgtDist = edge.pstyle('target-distance-from-node').pfValue;\n var srcDist = edge.pstyle('source-distance-from-node').pfValue;\n var curveStyle = edge.pstyle('curve-style').value;\n var rs = edge._private.rscratch;\n var et = rs.edgeType;\n var taxi = curveStyle === 'taxi';\n var self = et === 'self' || et === 'compound';\n var bezier = et === 'bezier' || et === 'multibezier' || self;\n var multi = et !== 'bezier';\n var lines = et === 'straight' || et === 'segments';\n var segments = et === 'segments';\n var hasEndpts = bezier || multi || lines;\n var overrideEndpts = self || taxi;\n var srcManEndpt = edge.pstyle('source-endpoint');\n var srcManEndptVal = overrideEndpts ? 'outside-to-node' : srcManEndpt.value;\n var tgtManEndpt = edge.pstyle('target-endpoint');\n var tgtManEndptVal = overrideEndpts ? 'outside-to-node' : tgtManEndpt.value;\n rs.srcManEndpt = srcManEndpt;\n rs.tgtManEndpt = tgtManEndpt;\n var p1; // last known point of edge on target side\n\n var p2; // last known point of edge on source side\n\n var p1_i; // point to intersect with target shape\n\n var p2_i; // point to intersect with source shape\n\n if (bezier) {\n var cpStart = [rs.ctrlpts[0], rs.ctrlpts[1]];\n var cpEnd = multi ? [rs.ctrlpts[rs.ctrlpts.length - 2], rs.ctrlpts[rs.ctrlpts.length - 1]] : cpStart;\n p1 = cpEnd;\n p2 = cpStart;\n } else if (lines) {\n var srcArrowFromPt = !segments ? [tgtPos.x, tgtPos.y] : rs.segpts.slice(0, 2);\n var tgtArrowFromPt = !segments ? [srcPos.x, srcPos.y] : rs.segpts.slice(rs.segpts.length - 2);\n p1 = tgtArrowFromPt;\n p2 = srcArrowFromPt;\n }\n\n if (tgtManEndptVal === 'inside-to-node') {\n intersect = [tgtPos.x, tgtPos.y];\n } else if (tgtManEndpt.units) {\n intersect = this.manualEndptToPx(target, tgtManEndpt);\n } else if (tgtManEndptVal === 'outside-to-line') {\n intersect = rs.tgtIntn; // use cached value from ctrlpt calc\n } else {\n if (tgtManEndptVal === 'outside-to-node' || tgtManEndptVal === 'outside-to-node-or-label') {\n p1_i = p1;\n } else if (tgtManEndptVal === 'outside-to-line' || tgtManEndptVal === 'outside-to-line-or-label') {\n p1_i = [srcPos.x, srcPos.y];\n }\n\n intersect = r.nodeShapes[this.getNodeShape(target)].intersectLine(tgtPos.x, tgtPos.y, target.outerWidth(), target.outerHeight(), p1_i[0], p1_i[1], 0);\n\n if (tgtManEndptVal === 'outside-to-node-or-label' || tgtManEndptVal === 'outside-to-line-or-label') {\n var trs = target._private.rscratch;\n var lw = trs.labelWidth;\n var lh = trs.labelHeight;\n var lx = trs.labelX;\n var ly = trs.labelY;\n var lw2 = lw / 2;\n var lh2 = lh / 2;\n var va = target.pstyle('text-valign').value;\n\n if (va === 'top') {\n ly -= lh2;\n } else if (va === 'bottom') {\n ly += lh2;\n }\n\n var ha = target.pstyle('text-halign').value;\n\n if (ha === 'left') {\n lx -= lw2;\n } else if (ha === 'right') {\n lx += lw2;\n }\n\n var labelIntersect = polygonIntersectLine(p1_i[0], p1_i[1], [lx - lw2, ly - lh2, lx + lw2, ly - lh2, lx + lw2, ly + lh2, lx - lw2, ly + lh2], tgtPos.x, tgtPos.y);\n\n if (labelIntersect.length > 0) {\n var refPt = srcPos;\n var intSqdist = sqdist(refPt, array2point(intersect));\n var labIntSqdist = sqdist(refPt, array2point(labelIntersect));\n var minSqDist = intSqdist;\n\n if (labIntSqdist < intSqdist) {\n intersect = labelIntersect;\n minSqDist = labIntSqdist;\n }\n\n if (labelIntersect.length > 2) {\n var labInt2SqDist = sqdist(refPt, {\n x: labelIntersect[2],\n y: labelIntersect[3]\n });\n\n if (labInt2SqDist < minSqDist) {\n intersect = [labelIntersect[2], labelIntersect[3]];\n }\n }\n }\n }\n }\n\n var arrowEnd = shortenIntersection(intersect, p1, r.arrowShapes[tgtArShape].spacing(edge) + tgtDist);\n var edgeEnd = shortenIntersection(intersect, p1, r.arrowShapes[tgtArShape].gap(edge) + tgtDist);\n rs.endX = edgeEnd[0];\n rs.endY = edgeEnd[1];\n rs.arrowEndX = arrowEnd[0];\n rs.arrowEndY = arrowEnd[1];\n\n if (srcManEndptVal === 'inside-to-node') {\n intersect = [srcPos.x, srcPos.y];\n } else if (srcManEndpt.units) {\n intersect = this.manualEndptToPx(source, srcManEndpt);\n } else if (srcManEndptVal === 'outside-to-line') {\n intersect = rs.srcIntn; // use cached value from ctrlpt calc\n } else {\n if (srcManEndptVal === 'outside-to-node' || srcManEndptVal === 'outside-to-node-or-label') {\n p2_i = p2;\n } else if (srcManEndptVal === 'outside-to-line' || srcManEndptVal === 'outside-to-line-or-label') {\n p2_i = [tgtPos.x, tgtPos.y];\n }\n\n intersect = r.nodeShapes[this.getNodeShape(source)].intersectLine(srcPos.x, srcPos.y, source.outerWidth(), source.outerHeight(), p2_i[0], p2_i[1], 0);\n\n if (srcManEndptVal === 'outside-to-node-or-label' || srcManEndptVal === 'outside-to-line-or-label') {\n var srs = source._private.rscratch;\n var _lw = srs.labelWidth;\n var _lh = srs.labelHeight;\n var _lx = srs.labelX;\n var _ly = srs.labelY;\n\n var _lw2 = _lw / 2;\n\n var _lh2 = _lh / 2;\n\n var _va = source.pstyle('text-valign').value;\n\n if (_va === 'top') {\n _ly -= _lh2;\n } else if (_va === 'bottom') {\n _ly += _lh2;\n }\n\n var _ha = source.pstyle('text-halign').value;\n\n if (_ha === 'left') {\n _lx -= _lw2;\n } else if (_ha === 'right') {\n _lx += _lw2;\n }\n\n var _labelIntersect = polygonIntersectLine(p2_i[0], p2_i[1], [_lx - _lw2, _ly - _lh2, _lx + _lw2, _ly - _lh2, _lx + _lw2, _ly + _lh2, _lx - _lw2, _ly + _lh2], srcPos.x, srcPos.y);\n\n if (_labelIntersect.length > 0) {\n var _refPt = tgtPos;\n\n var _intSqdist = sqdist(_refPt, array2point(intersect));\n\n var _labIntSqdist = sqdist(_refPt, array2point(_labelIntersect));\n\n var _minSqDist = _intSqdist;\n\n if (_labIntSqdist < _intSqdist) {\n intersect = [_labelIntersect[0], _labelIntersect[1]];\n _minSqDist = _labIntSqdist;\n }\n\n if (_labelIntersect.length > 2) {\n var _labInt2SqDist = sqdist(_refPt, {\n x: _labelIntersect[2],\n y: _labelIntersect[3]\n });\n\n if (_labInt2SqDist < _minSqDist) {\n intersect = [_labelIntersect[2], _labelIntersect[3]];\n }\n }\n }\n }\n }\n\n var arrowStart = shortenIntersection(intersect, p2, r.arrowShapes[srcArShape].spacing(edge) + srcDist);\n var edgeStart = shortenIntersection(intersect, p2, r.arrowShapes[srcArShape].gap(edge) + srcDist);\n rs.startX = edgeStart[0];\n rs.startY = edgeStart[1];\n rs.arrowStartX = arrowStart[0];\n rs.arrowStartY = arrowStart[1];\n\n if (hasEndpts) {\n if (!number$1(rs.startX) || !number$1(rs.startY) || !number$1(rs.endX) || !number$1(rs.endY)) {\n rs.badLine = true;\n } else {\n rs.badLine = false;\n }\n }\n };\n\n BRp$b.getSourceEndpoint = function (edge) {\n var rs = edge[0]._private.rscratch;\n this.recalculateRenderedStyle(edge);\n\n switch (rs.edgeType) {\n case 'haystack':\n return {\n x: rs.haystackPts[0],\n y: rs.haystackPts[1]\n };\n\n default:\n return {\n x: rs.arrowStartX,\n y: rs.arrowStartY\n };\n }\n };\n\n BRp$b.getTargetEndpoint = function (edge) {\n var rs = edge[0]._private.rscratch;\n this.recalculateRenderedStyle(edge);\n\n switch (rs.edgeType) {\n case 'haystack':\n return {\n x: rs.haystackPts[2],\n y: rs.haystackPts[3]\n };\n\n default:\n return {\n x: rs.arrowEndX,\n y: rs.arrowEndY\n };\n }\n };\n\n var BRp$a = {};\n\n function pushBezierPts(r, edge, pts) {\n var qbezierAt$1 = function qbezierAt$1(p1, p2, p3, t) {\n return qbezierAt(p1, p2, p3, t);\n };\n\n var _p = edge._private;\n var bpts = _p.rstyle.bezierPts;\n\n for (var i = 0; i < r.bezierProjPcts.length; i++) {\n var p = r.bezierProjPcts[i];\n bpts.push({\n x: qbezierAt$1(pts[0], pts[2], pts[4], p),\n y: qbezierAt$1(pts[1], pts[3], pts[5], p)\n });\n }\n }\n\n BRp$a.storeEdgeProjections = function (edge) {\n var _p = edge._private;\n var rs = _p.rscratch;\n var et = rs.edgeType; // clear the cached points state\n\n _p.rstyle.bezierPts = null;\n _p.rstyle.linePts = null;\n _p.rstyle.haystackPts = null;\n\n if (et === 'multibezier' || et === 'bezier' || et === 'self' || et === 'compound') {\n _p.rstyle.bezierPts = [];\n\n for (var i = 0; i + 5 < rs.allpts.length; i += 4) {\n pushBezierPts(this, edge, rs.allpts.slice(i, i + 6));\n }\n } else if (et === 'segments') {\n var lpts = _p.rstyle.linePts = [];\n\n for (var i = 0; i + 1 < rs.allpts.length; i += 2) {\n lpts.push({\n x: rs.allpts[i],\n y: rs.allpts[i + 1]\n });\n }\n } else if (et === 'haystack') {\n var hpts = rs.haystackPts;\n _p.rstyle.haystackPts = [{\n x: hpts[0],\n y: hpts[1]\n }, {\n x: hpts[2],\n y: hpts[3]\n }];\n }\n\n _p.rstyle.arrowWidth = this.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.arrowShapeWidth;\n };\n\n BRp$a.recalculateEdgeProjections = function (edges) {\n this.findEdgeControlPoints(edges);\n };\n\n /* global document */\n\n var BRp$9 = {};\n\n BRp$9.recalculateNodeLabelProjection = function (node) {\n var content = node.pstyle('label').strValue;\n\n if (emptyString(content)) {\n return;\n }\n\n var textX, textY;\n var _p = node._private;\n var nodeWidth = node.width();\n var nodeHeight = node.height();\n var padding = node.padding();\n var nodePos = node.position();\n var textHalign = node.pstyle('text-halign').strValue;\n var textValign = node.pstyle('text-valign').strValue;\n var rs = _p.rscratch;\n var rstyle = _p.rstyle;\n\n switch (textHalign) {\n case 'left':\n textX = nodePos.x - nodeWidth / 2 - padding;\n break;\n\n case 'right':\n textX = nodePos.x + nodeWidth / 2 + padding;\n break;\n\n default:\n // e.g. center\n textX = nodePos.x;\n }\n\n switch (textValign) {\n case 'top':\n textY = nodePos.y - nodeHeight / 2 - padding;\n break;\n\n case 'bottom':\n textY = nodePos.y + nodeHeight / 2 + padding;\n break;\n\n default:\n // e.g. middle\n textY = nodePos.y;\n }\n\n rs.labelX = textX;\n rs.labelY = textY;\n rstyle.labelX = textX;\n rstyle.labelY = textY;\n this.calculateLabelAngles(node);\n this.applyLabelDimensions(node);\n };\n\n var lineAngleFromDelta = function lineAngleFromDelta(dx, dy) {\n var angle = Math.atan(dy / dx);\n\n if (dx === 0 && angle < 0) {\n angle = angle * -1;\n }\n\n return angle;\n };\n\n var lineAngle = function lineAngle(p0, p1) {\n var dx = p1.x - p0.x;\n var dy = p1.y - p0.y;\n return lineAngleFromDelta(dx, dy);\n };\n\n var bezierAngle = function bezierAngle(p0, p1, p2, t) {\n var t0 = bound(0, t - 0.001, 1);\n var t1 = bound(0, t + 0.001, 1);\n var lp0 = qbezierPtAt(p0, p1, p2, t0);\n var lp1 = qbezierPtAt(p0, p1, p2, t1);\n return lineAngle(lp0, lp1);\n };\n\n BRp$9.recalculateEdgeLabelProjections = function (edge) {\n var p;\n var _p = edge._private;\n var rs = _p.rscratch;\n var r = this;\n var content = {\n mid: edge.pstyle('label').strValue,\n source: edge.pstyle('source-label').strValue,\n target: edge.pstyle('target-label').strValue\n };\n\n if (content.mid || content.source || content.target) ; else {\n return; // no labels => no calcs\n } // add center point to style so bounding box calculations can use it\n //\n\n\n p = {\n x: rs.midX,\n y: rs.midY\n };\n\n var setRs = function setRs(propName, prefix, value) {\n setPrefixedProperty(_p.rscratch, propName, prefix, value);\n setPrefixedProperty(_p.rstyle, propName, prefix, value);\n };\n\n setRs('labelX', null, p.x);\n setRs('labelY', null, p.y);\n var midAngle = lineAngleFromDelta(rs.midDispX, rs.midDispY);\n setRs('labelAutoAngle', null, midAngle);\n\n var createControlPointInfo = function createControlPointInfo() {\n if (createControlPointInfo.cache) {\n return createControlPointInfo.cache;\n } // use cache so only 1x per edge\n\n\n var ctrlpts = []; // store each ctrlpt info init\n\n for (var i = 0; i + 5 < rs.allpts.length; i += 4) {\n var p0 = {\n x: rs.allpts[i],\n y: rs.allpts[i + 1]\n };\n var p1 = {\n x: rs.allpts[i + 2],\n y: rs.allpts[i + 3]\n }; // ctrlpt\n\n var p2 = {\n x: rs.allpts[i + 4],\n y: rs.allpts[i + 5]\n };\n ctrlpts.push({\n p0: p0,\n p1: p1,\n p2: p2,\n startDist: 0,\n length: 0,\n segments: []\n });\n }\n\n var bpts = _p.rstyle.bezierPts;\n var nProjs = r.bezierProjPcts.length;\n\n function addSegment(cp, p0, p1, t0, t1) {\n var length = dist(p0, p1);\n var prevSegment = cp.segments[cp.segments.length - 1];\n var segment = {\n p0: p0,\n p1: p1,\n t0: t0,\n t1: t1,\n startDist: prevSegment ? prevSegment.startDist + prevSegment.length : 0,\n length: length\n };\n cp.segments.push(segment);\n cp.length += length;\n } // update each ctrlpt with segment info\n\n\n for (var _i = 0; _i < ctrlpts.length; _i++) {\n var cp = ctrlpts[_i];\n var prevCp = ctrlpts[_i - 1];\n\n if (prevCp) {\n cp.startDist = prevCp.startDist + prevCp.length;\n }\n\n addSegment(cp, cp.p0, bpts[_i * nProjs], 0, r.bezierProjPcts[0]); // first\n\n for (var j = 0; j < nProjs - 1; j++) {\n addSegment(cp, bpts[_i * nProjs + j], bpts[_i * nProjs + j + 1], r.bezierProjPcts[j], r.bezierProjPcts[j + 1]);\n }\n\n addSegment(cp, bpts[_i * nProjs + nProjs - 1], cp.p2, r.bezierProjPcts[nProjs - 1], 1); // last\n }\n\n return createControlPointInfo.cache = ctrlpts;\n };\n\n var calculateEndProjection = function calculateEndProjection(prefix) {\n var angle;\n var isSrc = prefix === 'source';\n\n if (!content[prefix]) {\n return;\n }\n\n var offset = edge.pstyle(prefix + '-text-offset').pfValue;\n\n switch (rs.edgeType) {\n case 'self':\n case 'compound':\n case 'bezier':\n case 'multibezier':\n {\n var cps = createControlPointInfo();\n var selected;\n var startDist = 0;\n var totalDist = 0; // find the segment we're on\n\n for (var i = 0; i < cps.length; i++) {\n var _cp = cps[isSrc ? i : cps.length - 1 - i];\n\n for (var j = 0; j < _cp.segments.length; j++) {\n var _seg = _cp.segments[isSrc ? j : _cp.segments.length - 1 - j];\n var lastSeg = i === cps.length - 1 && j === _cp.segments.length - 1;\n startDist = totalDist;\n totalDist += _seg.length;\n\n if (totalDist >= offset || lastSeg) {\n selected = {\n cp: _cp,\n segment: _seg\n };\n break;\n }\n }\n\n if (selected) {\n break;\n }\n }\n\n var cp = selected.cp;\n var seg = selected.segment;\n var tSegment = (offset - startDist) / seg.length;\n var segDt = seg.t1 - seg.t0;\n var t = isSrc ? seg.t0 + segDt * tSegment : seg.t1 - segDt * tSegment;\n t = bound(0, t, 1);\n p = qbezierPtAt(cp.p0, cp.p1, cp.p2, t);\n angle = bezierAngle(cp.p0, cp.p1, cp.p2, t);\n break;\n }\n\n case 'straight':\n case 'segments':\n case 'haystack':\n {\n var d = 0,\n di,\n d0;\n var p0, p1;\n var l = rs.allpts.length;\n\n for (var _i2 = 0; _i2 + 3 < l; _i2 += 2) {\n if (isSrc) {\n p0 = {\n x: rs.allpts[_i2],\n y: rs.allpts[_i2 + 1]\n };\n p1 = {\n x: rs.allpts[_i2 + 2],\n y: rs.allpts[_i2 + 3]\n };\n } else {\n p0 = {\n x: rs.allpts[l - 2 - _i2],\n y: rs.allpts[l - 1 - _i2]\n };\n p1 = {\n x: rs.allpts[l - 4 - _i2],\n y: rs.allpts[l - 3 - _i2]\n };\n }\n\n di = dist(p0, p1);\n d0 = d;\n d += di;\n\n if (d >= offset) {\n break;\n }\n }\n\n var pD = offset - d0;\n\n var _t = pD / di;\n\n _t = bound(0, _t, 1);\n p = lineAt(p0, p1, _t);\n angle = lineAngle(p0, p1);\n break;\n }\n }\n\n setRs('labelX', prefix, p.x);\n setRs('labelY', prefix, p.y);\n setRs('labelAutoAngle', prefix, angle);\n };\n\n calculateEndProjection('source');\n calculateEndProjection('target');\n this.applyLabelDimensions(edge);\n };\n\n BRp$9.applyLabelDimensions = function (ele) {\n this.applyPrefixedLabelDimensions(ele);\n\n if (ele.isEdge()) {\n this.applyPrefixedLabelDimensions(ele, 'source');\n this.applyPrefixedLabelDimensions(ele, 'target');\n }\n };\n\n BRp$9.applyPrefixedLabelDimensions = function (ele, prefix) {\n var _p = ele._private;\n var text = this.getLabelText(ele, prefix);\n var labelDims = this.calculateLabelDimensions(ele, text);\n var lineHeight = ele.pstyle('line-height').pfValue;\n var textWrap = ele.pstyle('text-wrap').strValue;\n var lines = getPrefixedProperty(_p.rscratch, 'labelWrapCachedLines', prefix) || [];\n var numLines = textWrap !== 'wrap' ? 1 : Math.max(lines.length, 1);\n var normPerLineHeight = labelDims.height / numLines;\n var labelLineHeight = normPerLineHeight * lineHeight;\n var width = labelDims.width;\n var height = labelDims.height + (numLines - 1) * (lineHeight - 1) * normPerLineHeight;\n setPrefixedProperty(_p.rstyle, 'labelWidth', prefix, width);\n setPrefixedProperty(_p.rscratch, 'labelWidth', prefix, width);\n setPrefixedProperty(_p.rstyle, 'labelHeight', prefix, height);\n setPrefixedProperty(_p.rscratch, 'labelHeight', prefix, height);\n setPrefixedProperty(_p.rscratch, 'labelLineHeight', prefix, labelLineHeight);\n };\n\n BRp$9.getLabelText = function (ele, prefix) {\n var _p = ele._private;\n var pfd = prefix ? prefix + '-' : '';\n var text = ele.pstyle(pfd + 'label').strValue;\n var textTransform = ele.pstyle('text-transform').value;\n\n var rscratch = function rscratch(propName, value) {\n if (value) {\n setPrefixedProperty(_p.rscratch, propName, prefix, value);\n return value;\n } else {\n return getPrefixedProperty(_p.rscratch, propName, prefix);\n }\n }; // for empty text, skip all processing\n\n\n if (!text) {\n return '';\n }\n\n if (textTransform == 'none') ; else if (textTransform == 'uppercase') {\n text = text.toUpperCase();\n } else if (textTransform == 'lowercase') {\n text = text.toLowerCase();\n }\n\n var wrapStyle = ele.pstyle('text-wrap').value;\n\n if (wrapStyle === 'wrap') {\n var labelKey = rscratch('labelKey'); // save recalc if the label is the same as before\n\n if (labelKey != null && rscratch('labelWrapKey') === labelKey) {\n return rscratch('labelWrapCachedText');\n }\n\n var zwsp = \"\\u200B\";\n var lines = text.split('\\n');\n var maxW = ele.pstyle('text-max-width').pfValue;\n var overflow = ele.pstyle('text-overflow-wrap').value;\n var overflowAny = overflow === 'anywhere';\n var wrappedLines = [];\n var wordsRegex = /[\\s\\u200b]+/;\n var wordSeparator = overflowAny ? '' : ' ';\n\n for (var l = 0; l < lines.length; l++) {\n var line = lines[l];\n var lineDims = this.calculateLabelDimensions(ele, line);\n var lineW = lineDims.width;\n\n if (overflowAny) {\n var processedLine = line.split('').join(zwsp);\n line = processedLine;\n }\n\n if (lineW > maxW) {\n // line is too long\n var words = line.split(wordsRegex);\n var subline = '';\n\n for (var w = 0; w < words.length; w++) {\n var word = words[w];\n var testLine = subline.length === 0 ? word : subline + wordSeparator + word;\n var testDims = this.calculateLabelDimensions(ele, testLine);\n var testW = testDims.width;\n\n if (testW <= maxW) {\n // word fits on current line\n subline += word + wordSeparator;\n } else {\n // word starts new line\n if (subline) {\n wrappedLines.push(subline);\n }\n\n subline = word + wordSeparator;\n }\n } // if there's remaining text, put it in a wrapped line\n\n\n if (!subline.match(/^[\\s\\u200b]+$/)) {\n wrappedLines.push(subline);\n }\n } else {\n // line is already short enough\n wrappedLines.push(line);\n }\n } // for\n\n\n rscratch('labelWrapCachedLines', wrappedLines);\n text = rscratch('labelWrapCachedText', wrappedLines.join('\\n'));\n rscratch('labelWrapKey', labelKey);\n } else if (wrapStyle === 'ellipsis') {\n var _maxW = ele.pstyle('text-max-width').pfValue;\n var ellipsized = '';\n var ellipsis = \"\\u2026\";\n var incLastCh = false;\n\n if (this.calculateLabelDimensions(ele, text).width < _maxW) {\n // the label already fits\n return text;\n }\n\n for (var i = 0; i < text.length; i++) {\n var widthWithNextCh = this.calculateLabelDimensions(ele, ellipsized + text[i] + ellipsis).width;\n\n if (widthWithNextCh > _maxW) {\n break;\n }\n\n ellipsized += text[i];\n\n if (i === text.length - 1) {\n incLastCh = true;\n }\n }\n\n if (!incLastCh) {\n ellipsized += ellipsis;\n }\n\n return ellipsized;\n } // if ellipsize\n\n\n return text;\n };\n\n BRp$9.getLabelJustification = function (ele) {\n var justification = ele.pstyle('text-justification').strValue;\n var textHalign = ele.pstyle('text-halign').strValue;\n\n if (justification === 'auto') {\n if (ele.isNode()) {\n switch (textHalign) {\n case 'left':\n return 'right';\n\n case 'right':\n return 'left';\n\n default:\n return 'center';\n }\n } else {\n return 'center';\n }\n } else {\n return justification;\n }\n };\n\n BRp$9.calculateLabelDimensions = function (ele, text) {\n var r = this;\n var cacheKey = hashString(text, ele._private.labelDimsKey);\n var cache = r.labelDimCache || (r.labelDimCache = []);\n var existingVal = cache[cacheKey];\n\n if (existingVal != null) {\n return existingVal;\n }\n\n var padding = 0; // add padding around text dims, as the measurement isn't that accurate\n\n var fStyle = ele.pstyle('font-style').strValue;\n var size = ele.pstyle('font-size').pfValue;\n var family = ele.pstyle('font-family').strValue;\n var weight = ele.pstyle('font-weight').strValue;\n var canvas = this.labelCalcCanvas;\n var c2d = this.labelCalcCanvasContext;\n\n if (!canvas) {\n canvas = this.labelCalcCanvas = document.createElement('canvas');\n c2d = this.labelCalcCanvasContext = canvas.getContext('2d');\n var ds = canvas.style;\n ds.position = 'absolute';\n ds.left = '-9999px';\n ds.top = '-9999px';\n ds.zIndex = '-1';\n ds.visibility = 'hidden';\n ds.pointerEvents = 'none';\n }\n\n c2d.font = \"\".concat(fStyle, \" \").concat(weight, \" \").concat(size, \"px \").concat(family);\n var width = 0;\n var height = 0;\n var lines = text.split('\\n');\n\n for (var i = 0; i < lines.length; i++) {\n var line = lines[i];\n var metrics = c2d.measureText(line);\n var w = Math.ceil(metrics.width);\n var h = size;\n width = Math.max(w, width);\n height += h;\n }\n\n width += padding;\n height += padding;\n return cache[cacheKey] = {\n width: width,\n height: height\n };\n };\n\n BRp$9.calculateLabelAngle = function (ele, prefix) {\n var _p = ele._private;\n var rs = _p.rscratch;\n var isEdge = ele.isEdge();\n var prefixDash = prefix ? prefix + '-' : '';\n var rot = ele.pstyle(prefixDash + 'text-rotation');\n var rotStr = rot.strValue;\n\n if (rotStr === 'none') {\n return 0;\n } else if (isEdge && rotStr === 'autorotate') {\n return rs.labelAutoAngle;\n } else if (rotStr === 'autorotate') {\n return 0;\n } else {\n return rot.pfValue;\n }\n };\n\n BRp$9.calculateLabelAngles = function (ele) {\n var r = this;\n var isEdge = ele.isEdge();\n var _p = ele._private;\n var rs = _p.rscratch;\n rs.labelAngle = r.calculateLabelAngle(ele);\n\n if (isEdge) {\n rs.sourceLabelAngle = r.calculateLabelAngle(ele, 'source');\n rs.targetLabelAngle = r.calculateLabelAngle(ele, 'target');\n }\n };\n\n var BRp$8 = {};\n var TOO_SMALL_CUT_RECT = 28;\n var warnedCutRect = false;\n\n BRp$8.getNodeShape = function (node) {\n var r = this;\n var shape = node.pstyle('shape').value;\n\n if (shape === 'cutrectangle' && (node.width() < TOO_SMALL_CUT_RECT || node.height() < TOO_SMALL_CUT_RECT)) {\n if (!warnedCutRect) {\n warn('The `cutrectangle` node shape can not be used at small sizes so `rectangle` is used instead');\n warnedCutRect = true;\n }\n\n return 'rectangle';\n }\n\n if (node.isParent()) {\n if (shape === 'rectangle' || shape === 'roundrectangle' || shape === 'round-rectangle' || shape === 'cutrectangle' || shape === 'cut-rectangle' || shape === 'barrel') {\n return shape;\n } else {\n return 'rectangle';\n }\n }\n\n if (shape === 'polygon') {\n var points = node.pstyle('shape-polygon-points').value;\n return r.nodeShapes.makePolygon(points).name;\n }\n\n return shape;\n };\n\n var BRp$7 = {};\n\n BRp$7.registerCalculationListeners = function () {\n var cy = this.cy;\n var elesToUpdate = cy.collection();\n var r = this;\n\n var enqueue = function enqueue(eles) {\n var dirtyStyleCaches = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n elesToUpdate.merge(eles);\n\n if (dirtyStyleCaches) {\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var _p = ele._private;\n var rstyle = _p.rstyle;\n rstyle.clean = false;\n rstyle.cleanConnected = false;\n }\n }\n };\n\n r.binder(cy).on('bounds.* dirty.*', function onDirtyBounds(e) {\n var ele = e.target;\n enqueue(ele);\n }).on('style.* background.*', function onDirtyStyle(e) {\n var ele = e.target;\n enqueue(ele, false);\n });\n\n var updateEleCalcs = function updateEleCalcs(willDraw) {\n if (willDraw) {\n var fns = r.onUpdateEleCalcsFns; // because we need to have up-to-date style (e.g. stylesheet mappers)\n // before calculating rendered style (and pstyle might not be called yet)\n\n elesToUpdate.cleanStyle();\n\n for (var i = 0; i < elesToUpdate.length; i++) {\n var ele = elesToUpdate[i];\n var rstyle = ele._private.rstyle;\n\n if (ele.isNode() && !rstyle.cleanConnected) {\n enqueue(ele.connectedEdges());\n rstyle.cleanConnected = true;\n }\n }\n\n if (fns) {\n for (var _i = 0; _i < fns.length; _i++) {\n var fn = fns[_i];\n fn(willDraw, elesToUpdate);\n }\n }\n\n r.recalculateRenderedStyle(elesToUpdate);\n elesToUpdate = cy.collection();\n }\n };\n\n r.flushRenderedStyleQueue = function () {\n updateEleCalcs(true);\n };\n\n r.beforeRender(updateEleCalcs, r.beforeRenderPriorities.eleCalcs);\n };\n\n BRp$7.onUpdateEleCalcs = function (fn) {\n var fns = this.onUpdateEleCalcsFns = this.onUpdateEleCalcsFns || [];\n fns.push(fn);\n };\n\n BRp$7.recalculateRenderedStyle = function (eles, useCache) {\n var isCleanConnected = function isCleanConnected(ele) {\n return ele._private.rstyle.cleanConnected;\n };\n\n var edges = [];\n var nodes = []; // the renderer can't be used for calcs when destroyed, e.g. ele.boundingBox()\n\n if (this.destroyed) {\n return;\n } // use cache by default for perf\n\n\n if (useCache === undefined) {\n useCache = true;\n }\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var _p = ele._private;\n var rstyle = _p.rstyle; // an edge may be implicitly dirty b/c of one of its connected nodes\n // (and a request for recalc may come in between frames)\n\n if (ele.isEdge() && (!isCleanConnected(ele.source()) || !isCleanConnected(ele.target()))) {\n rstyle.clean = false;\n } // only update if dirty and in graph\n\n\n if (useCache && rstyle.clean || ele.removed()) {\n continue;\n } // only update if not display: none\n\n\n if (ele.pstyle('display').value === 'none') {\n continue;\n }\n\n if (_p.group === 'nodes') {\n nodes.push(ele);\n } else {\n // edges\n edges.push(ele);\n }\n\n rstyle.clean = true;\n } // update node data from projections\n\n\n for (var _i2 = 0; _i2 < nodes.length; _i2++) {\n var _ele = nodes[_i2];\n var _p2 = _ele._private;\n var _rstyle = _p2.rstyle;\n\n var pos = _ele.position();\n\n this.recalculateNodeLabelProjection(_ele);\n _rstyle.nodeX = pos.x;\n _rstyle.nodeY = pos.y;\n _rstyle.nodeW = _ele.pstyle('width').pfValue;\n _rstyle.nodeH = _ele.pstyle('height').pfValue;\n }\n\n this.recalculateEdgeProjections(edges); // update edge data from projections\n\n for (var _i3 = 0; _i3 < edges.length; _i3++) {\n var _ele2 = edges[_i3];\n var _p3 = _ele2._private;\n var _rstyle2 = _p3.rstyle;\n var rs = _p3.rscratch; // update rstyle positions\n\n _rstyle2.srcX = rs.arrowStartX;\n _rstyle2.srcY = rs.arrowStartY;\n _rstyle2.tgtX = rs.arrowEndX;\n _rstyle2.tgtY = rs.arrowEndY;\n _rstyle2.midX = rs.midX;\n _rstyle2.midY = rs.midY;\n _rstyle2.labelAngle = rs.labelAngle;\n _rstyle2.sourceLabelAngle = rs.sourceLabelAngle;\n _rstyle2.targetLabelAngle = rs.targetLabelAngle;\n }\n };\n\n var BRp$6 = {};\n\n BRp$6.updateCachedGrabbedEles = function () {\n var eles = this.cachedZSortedEles;\n\n if (!eles) {\n // just let this be recalculated on the next z sort tick\n return;\n }\n\n eles.drag = [];\n eles.nondrag = [];\n var grabTargets = [];\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var rs = ele._private.rscratch;\n\n if (ele.grabbed() && !ele.isParent()) {\n grabTargets.push(ele);\n } else if (rs.inDragLayer) {\n eles.drag.push(ele);\n } else {\n eles.nondrag.push(ele);\n }\n } // put the grab target nodes last so it's on top of its neighbourhood\n\n\n for (var i = 0; i < grabTargets.length; i++) {\n var ele = grabTargets[i];\n eles.drag.push(ele);\n }\n };\n\n BRp$6.invalidateCachedZSortedEles = function () {\n this.cachedZSortedEles = null;\n };\n\n BRp$6.getCachedZSortedEles = function (forceRecalc) {\n if (forceRecalc || !this.cachedZSortedEles) {\n var eles = this.cy.mutableElements().toArray();\n eles.sort(zIndexSort);\n eles.interactive = eles.filter(function (ele) {\n return ele.interactive();\n });\n this.cachedZSortedEles = eles;\n this.updateCachedGrabbedEles();\n } else {\n eles = this.cachedZSortedEles;\n }\n\n return eles;\n };\n\n var BRp$5 = {};\n [BRp$e, BRp$d, BRp$c, BRp$b, BRp$a, BRp$9, BRp$8, BRp$7, BRp$6].forEach(function (props) {\n extend(BRp$5, props);\n });\n\n var BRp$4 = {};\n\n BRp$4.getCachedImage = function (url, crossOrigin, onLoad) {\n var r = this;\n var imageCache = r.imageCache = r.imageCache || {};\n var cache = imageCache[url];\n\n if (cache) {\n if (!cache.image.complete) {\n cache.image.addEventListener('load', onLoad);\n }\n\n return cache.image;\n } else {\n cache = imageCache[url] = imageCache[url] || {};\n var image = cache.image = new Image(); // eslint-disable-line no-undef\n\n image.addEventListener('load', onLoad);\n image.addEventListener('error', function () {\n image.error = true;\n }); // #1582 safari doesn't load data uris with crossOrigin properly\n // https://bugs.webkit.org/show_bug.cgi?id=123978\n\n var dataUriPrefix = 'data:';\n var isDataUri = url.substring(0, dataUriPrefix.length).toLowerCase() === dataUriPrefix;\n\n if (!isDataUri) {\n // if crossorigin is 'null'(stringified), then manually set it to null \n crossOrigin = crossOrigin === 'null' ? null : crossOrigin;\n image.crossOrigin = crossOrigin; // prevent tainted canvas\n }\n\n image.src = url;\n return image;\n }\n };\n\n var BRp$3 = {};\n /* global document, window, ResizeObserver, MutationObserver */\n\n BRp$3.registerBinding = function (target, event, handler, useCapture) {\n // eslint-disable-line no-unused-vars\n var args = Array.prototype.slice.apply(arguments, [1]); // copy\n\n var b = this.binder(target);\n return b.on.apply(b, args);\n };\n\n BRp$3.binder = function (tgt) {\n var r = this;\n var containerWindow = r.cy.window();\n var tgtIsDom = tgt === containerWindow || tgt === containerWindow.document || tgt === containerWindow.document.body || domElement(tgt);\n\n if (r.supportsPassiveEvents == null) {\n // from https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection\n var supportsPassive = false;\n\n try {\n var opts = Object.defineProperty({}, 'passive', {\n get: function get() {\n supportsPassive = true;\n return true;\n }\n });\n containerWindow.addEventListener('test', null, opts);\n } catch (err) {// not supported\n }\n\n r.supportsPassiveEvents = supportsPassive;\n }\n\n var on = function on(event, handler, useCapture) {\n var args = Array.prototype.slice.call(arguments);\n\n if (tgtIsDom && r.supportsPassiveEvents) {\n // replace useCapture w/ opts obj\n args[2] = {\n capture: useCapture != null ? useCapture : false,\n passive: false,\n once: false\n };\n }\n\n r.bindings.push({\n target: tgt,\n args: args\n });\n (tgt.addEventListener || tgt.on).apply(tgt, args);\n return this;\n };\n\n return {\n on: on,\n addEventListener: on,\n addListener: on,\n bind: on\n };\n };\n\n BRp$3.nodeIsDraggable = function (node) {\n return node && node.isNode() && !node.locked() && node.grabbable();\n };\n\n BRp$3.nodeIsGrabbable = function (node) {\n return this.nodeIsDraggable(node) && node.interactive();\n };\n\n BRp$3.load = function () {\n var r = this;\n var containerWindow = r.cy.window();\n\n var isSelected = function isSelected(ele) {\n return ele.selected();\n };\n\n var triggerEvents = function triggerEvents(target, names, e, position) {\n if (target == null) {\n target = r.cy;\n }\n\n for (var i = 0; i < names.length; i++) {\n var name = names[i];\n target.emit({\n originalEvent: e,\n type: name,\n position: position\n });\n }\n };\n\n var isMultSelKeyDown = function isMultSelKeyDown(e) {\n return e.shiftKey || e.metaKey || e.ctrlKey; // maybe e.altKey\n };\n\n var allowPanningPassthrough = function allowPanningPassthrough(down, downs) {\n var allowPassthrough = true;\n\n if (r.cy.hasCompoundNodes() && down && down.pannable()) {\n // a grabbable compound node below the ele => no passthrough panning\n for (var i = 0; downs && i < downs.length; i++) {\n var down = downs[i]; //if any parent node in event hierarchy isn't pannable, reject passthrough\n\n if (down.isNode() && down.isParent() && !down.pannable()) {\n allowPassthrough = false;\n break;\n }\n }\n } else {\n allowPassthrough = true;\n }\n\n return allowPassthrough;\n };\n\n var setGrabbed = function setGrabbed(ele) {\n ele[0]._private.grabbed = true;\n };\n\n var setFreed = function setFreed(ele) {\n ele[0]._private.grabbed = false;\n };\n\n var setInDragLayer = function setInDragLayer(ele) {\n ele[0]._private.rscratch.inDragLayer = true;\n };\n\n var setOutDragLayer = function setOutDragLayer(ele) {\n ele[0]._private.rscratch.inDragLayer = false;\n };\n\n var setGrabTarget = function setGrabTarget(ele) {\n ele[0]._private.rscratch.isGrabTarget = true;\n };\n\n var removeGrabTarget = function removeGrabTarget(ele) {\n ele[0]._private.rscratch.isGrabTarget = false;\n };\n\n var addToDragList = function addToDragList(ele, opts) {\n var list = opts.addToList;\n var listHasEle = list.has(ele);\n\n if (!listHasEle && ele.grabbable() && !ele.locked()) {\n list.merge(ele);\n setGrabbed(ele);\n }\n }; // helper function to determine which child nodes and inner edges\n // of a compound node to be dragged as well as the grabbed and selected nodes\n\n\n var addDescendantsToDrag = function addDescendantsToDrag(node, opts) {\n if (!node.cy().hasCompoundNodes()) {\n return;\n }\n\n if (opts.inDragLayer == null && opts.addToList == null) {\n return;\n } // nothing to do\n\n\n var innerNodes = node.descendants();\n\n if (opts.inDragLayer) {\n innerNodes.forEach(setInDragLayer);\n innerNodes.connectedEdges().forEach(setInDragLayer);\n }\n\n if (opts.addToList) {\n addToDragList(innerNodes, opts);\n }\n }; // adds the given nodes and its neighbourhood to the drag layer\n\n\n var addNodesToDrag = function addNodesToDrag(nodes, opts) {\n opts = opts || {};\n var hasCompoundNodes = nodes.cy().hasCompoundNodes();\n\n if (opts.inDragLayer) {\n nodes.forEach(setInDragLayer);\n nodes.neighborhood().stdFilter(function (ele) {\n return !hasCompoundNodes || ele.isEdge();\n }).forEach(setInDragLayer);\n }\n\n if (opts.addToList) {\n nodes.forEach(function (ele) {\n addToDragList(ele, opts);\n });\n }\n\n addDescendantsToDrag(nodes, opts); // always add to drag\n // also add nodes and edges related to the topmost ancestor\n\n updateAncestorsInDragLayer(nodes, {\n inDragLayer: opts.inDragLayer\n });\n r.updateCachedGrabbedEles();\n };\n\n var addNodeToDrag = addNodesToDrag;\n\n var freeDraggedElements = function freeDraggedElements(grabbedEles) {\n if (!grabbedEles) {\n return;\n } // just go over all elements rather than doing a bunch of (possibly expensive) traversals\n\n\n r.getCachedZSortedEles().forEach(function (ele) {\n setFreed(ele);\n setOutDragLayer(ele);\n removeGrabTarget(ele);\n });\n r.updateCachedGrabbedEles();\n }; // helper function to determine which ancestor nodes and edges should go\n // to the drag layer (or should be removed from drag layer).\n\n\n var updateAncestorsInDragLayer = function updateAncestorsInDragLayer(node, opts) {\n if (opts.inDragLayer == null && opts.addToList == null) {\n return;\n } // nothing to do\n\n\n if (!node.cy().hasCompoundNodes()) {\n return;\n } // find top-level parent\n\n\n var parent = node.ancestors().orphans(); // no parent node: no nodes to add to the drag layer\n\n if (parent.same(node)) {\n return;\n }\n\n var nodes = parent.descendants().spawnSelf().merge(parent).unmerge(node).unmerge(node.descendants());\n var edges = nodes.connectedEdges();\n\n if (opts.inDragLayer) {\n edges.forEach(setInDragLayer);\n nodes.forEach(setInDragLayer);\n }\n\n if (opts.addToList) {\n nodes.forEach(function (ele) {\n addToDragList(ele, opts);\n });\n }\n };\n\n var blurActiveDomElement = function blurActiveDomElement() {\n if (document.activeElement != null && document.activeElement.blur != null) {\n document.activeElement.blur();\n }\n };\n\n var haveMutationsApi = typeof MutationObserver !== 'undefined';\n var haveResizeObserverApi = typeof ResizeObserver !== 'undefined'; // watch for when the cy container is removed from the dom\n\n if (haveMutationsApi) {\n r.removeObserver = new MutationObserver(function (mutns) {\n // eslint-disable-line no-undef\n for (var i = 0; i < mutns.length; i++) {\n var mutn = mutns[i];\n var rNodes = mutn.removedNodes;\n\n if (rNodes) {\n for (var j = 0; j < rNodes.length; j++) {\n var rNode = rNodes[j];\n\n if (rNode === r.container) {\n r.destroy();\n break;\n }\n }\n }\n }\n });\n\n if (r.container.parentNode) {\n r.removeObserver.observe(r.container.parentNode, {\n childList: true\n });\n }\n } else {\n r.registerBinding(r.container, 'DOMNodeRemoved', function (e) {\n // eslint-disable-line no-unused-vars\n r.destroy();\n });\n }\n\n var onResize = debounce_1(function () {\n r.cy.resize();\n }, 100);\n\n if (haveMutationsApi) {\n r.styleObserver = new MutationObserver(onResize); // eslint-disable-line no-undef\n\n r.styleObserver.observe(r.container, {\n attributes: true\n });\n } // auto resize\n\n\n r.registerBinding(containerWindow, 'resize', onResize); // eslint-disable-line no-undef\n\n if (haveResizeObserverApi) {\n r.resizeObserver = new ResizeObserver(onResize); // eslint-disable-line no-undef\n\n r.resizeObserver.observe(r.container);\n }\n\n var forEachUp = function forEachUp(domEle, fn) {\n while (domEle != null) {\n fn(domEle);\n domEle = domEle.parentNode;\n }\n };\n\n var invalidateCoords = function invalidateCoords() {\n r.invalidateContainerClientCoordsCache();\n };\n\n forEachUp(r.container, function (domEle) {\n r.registerBinding(domEle, 'transitionend', invalidateCoords);\n r.registerBinding(domEle, 'animationend', invalidateCoords);\n r.registerBinding(domEle, 'scroll', invalidateCoords);\n }); // stop right click menu from appearing on cy\n\n r.registerBinding(r.container, 'contextmenu', function (e) {\n e.preventDefault();\n });\n\n var inBoxSelection = function inBoxSelection() {\n return r.selection[4] !== 0;\n };\n\n var eventInContainer = function eventInContainer(e) {\n // save cycles if mouse events aren't to be captured\n var containerPageCoords = r.findContainerClientCoords();\n var x = containerPageCoords[0];\n var y = containerPageCoords[1];\n var width = containerPageCoords[2];\n var height = containerPageCoords[3];\n var positions = e.touches ? e.touches : [e];\n var atLeastOnePosInside = false;\n\n for (var i = 0; i < positions.length; i++) {\n var p = positions[i];\n\n if (x <= p.clientX && p.clientX <= x + width && y <= p.clientY && p.clientY <= y + height) {\n atLeastOnePosInside = true;\n break;\n }\n }\n\n if (!atLeastOnePosInside) {\n return false;\n }\n\n var container = r.container;\n var target = e.target;\n var tParent = target.parentNode;\n var containerIsTarget = false;\n\n while (tParent) {\n if (tParent === container) {\n containerIsTarget = true;\n break;\n }\n\n tParent = tParent.parentNode;\n }\n\n if (!containerIsTarget) {\n return false;\n } // if target is outisde cy container, then this event is not for us\n\n\n return true;\n }; // Primary key\n\n\n r.registerBinding(r.container, 'mousedown', function mousedownHandler(e) {\n if (!eventInContainer(e)) {\n return;\n }\n\n e.preventDefault();\n blurActiveDomElement();\n r.hoverData.capture = true;\n r.hoverData.which = e.which;\n var cy = r.cy;\n var gpos = [e.clientX, e.clientY];\n var pos = r.projectIntoViewport(gpos[0], gpos[1]);\n var select = r.selection;\n var nears = r.findNearestElements(pos[0], pos[1], true, false);\n var near = nears[0];\n var draggedElements = r.dragData.possibleDragElements;\n r.hoverData.mdownPos = pos;\n r.hoverData.mdownGPos = gpos;\n\n var checkForTaphold = function checkForTaphold() {\n r.hoverData.tapholdCancelled = false;\n clearTimeout(r.hoverData.tapholdTimeout);\n r.hoverData.tapholdTimeout = setTimeout(function () {\n if (r.hoverData.tapholdCancelled) {\n return;\n } else {\n var ele = r.hoverData.down;\n\n if (ele) {\n ele.emit({\n originalEvent: e,\n type: 'taphold',\n position: {\n x: pos[0],\n y: pos[1]\n }\n });\n } else {\n cy.emit({\n originalEvent: e,\n type: 'taphold',\n position: {\n x: pos[0],\n y: pos[1]\n }\n });\n }\n }\n }, r.tapholdDuration);\n }; // Right click button\n\n\n if (e.which == 3) {\n r.hoverData.cxtStarted = true;\n var cxtEvt = {\n originalEvent: e,\n type: 'cxttapstart',\n position: {\n x: pos[0],\n y: pos[1]\n }\n };\n\n if (near) {\n near.activate();\n near.emit(cxtEvt);\n r.hoverData.down = near;\n } else {\n cy.emit(cxtEvt);\n }\n\n r.hoverData.downTime = new Date().getTime();\n r.hoverData.cxtDragged = false; // Primary button\n } else if (e.which == 1) {\n if (near) {\n near.activate();\n } // Element dragging\n\n\n {\n // If something is under the cursor and it is draggable, prepare to grab it\n if (near != null) {\n if (r.nodeIsGrabbable(near)) {\n var makeEvent = function makeEvent(type) {\n return {\n originalEvent: e,\n type: type,\n position: {\n x: pos[0],\n y: pos[1]\n }\n };\n };\n\n var triggerGrab = function triggerGrab(ele) {\n ele.emit(makeEvent('grab'));\n };\n\n setGrabTarget(near);\n\n if (!near.selected()) {\n draggedElements = r.dragData.possibleDragElements = cy.collection();\n addNodeToDrag(near, {\n addToList: draggedElements\n });\n near.emit(makeEvent('grabon')).emit(makeEvent('grab'));\n } else {\n draggedElements = r.dragData.possibleDragElements = cy.collection();\n var selectedNodes = cy.$(function (ele) {\n return ele.isNode() && ele.selected() && r.nodeIsGrabbable(ele);\n });\n addNodesToDrag(selectedNodes, {\n addToList: draggedElements\n });\n near.emit(makeEvent('grabon'));\n selectedNodes.forEach(triggerGrab);\n }\n\n r.redrawHint('eles', true);\n r.redrawHint('drag', true);\n }\n }\n\n r.hoverData.down = near;\n r.hoverData.downs = nears;\n r.hoverData.downTime = new Date().getTime();\n }\n triggerEvents(near, ['mousedown', 'tapstart', 'vmousedown'], e, {\n x: pos[0],\n y: pos[1]\n });\n\n if (near == null) {\n select[4] = 1;\n r.data.bgActivePosistion = {\n x: pos[0],\n y: pos[1]\n };\n r.redrawHint('select', true);\n r.redraw();\n } else if (near.pannable()) {\n select[4] = 1; // for future pan\n }\n\n checkForTaphold();\n } // Initialize selection box coordinates\n\n\n select[0] = select[2] = pos[0];\n select[1] = select[3] = pos[1];\n }, false);\n r.registerBinding(containerWindow, 'mousemove', function mousemoveHandler(e) {\n // eslint-disable-line no-undef\n var capture = r.hoverData.capture;\n\n if (!capture && !eventInContainer(e)) {\n return;\n }\n\n var preventDefault = false;\n var cy = r.cy;\n var zoom = cy.zoom();\n var gpos = [e.clientX, e.clientY];\n var pos = r.projectIntoViewport(gpos[0], gpos[1]);\n var mdownPos = r.hoverData.mdownPos;\n var mdownGPos = r.hoverData.mdownGPos;\n var select = r.selection;\n var near = null;\n\n if (!r.hoverData.draggingEles && !r.hoverData.dragging && !r.hoverData.selecting) {\n near = r.findNearestElement(pos[0], pos[1], true, false);\n }\n\n var last = r.hoverData.last;\n var down = r.hoverData.down;\n var disp = [pos[0] - select[2], pos[1] - select[3]];\n var draggedElements = r.dragData.possibleDragElements;\n var isOverThresholdDrag;\n\n if (mdownGPos) {\n var dx = gpos[0] - mdownGPos[0];\n var dx2 = dx * dx;\n var dy = gpos[1] - mdownGPos[1];\n var dy2 = dy * dy;\n var dist2 = dx2 + dy2;\n r.hoverData.isOverThresholdDrag = isOverThresholdDrag = dist2 >= r.desktopTapThreshold2;\n }\n\n var multSelKeyDown = isMultSelKeyDown(e);\n\n if (isOverThresholdDrag) {\n r.hoverData.tapholdCancelled = true;\n }\n\n var updateDragDelta = function updateDragDelta() {\n var dragDelta = r.hoverData.dragDelta = r.hoverData.dragDelta || [];\n\n if (dragDelta.length === 0) {\n dragDelta.push(disp[0]);\n dragDelta.push(disp[1]);\n } else {\n dragDelta[0] += disp[0];\n dragDelta[1] += disp[1];\n }\n };\n\n preventDefault = true;\n triggerEvents(near, ['mousemove', 'vmousemove', 'tapdrag'], e, {\n x: pos[0],\n y: pos[1]\n });\n\n var goIntoBoxMode = function goIntoBoxMode() {\n r.data.bgActivePosistion = undefined;\n\n if (!r.hoverData.selecting) {\n cy.emit({\n originalEvent: e,\n type: 'boxstart',\n position: {\n x: pos[0],\n y: pos[1]\n }\n });\n }\n\n select[4] = 1;\n r.hoverData.selecting = true;\n r.redrawHint('select', true);\n r.redraw();\n }; // trigger context drag if rmouse down\n\n\n if (r.hoverData.which === 3) {\n // but only if over threshold\n if (isOverThresholdDrag) {\n var cxtEvt = {\n originalEvent: e,\n type: 'cxtdrag',\n position: {\n x: pos[0],\n y: pos[1]\n }\n };\n\n if (down) {\n down.emit(cxtEvt);\n } else {\n cy.emit(cxtEvt);\n }\n\n r.hoverData.cxtDragged = true;\n\n if (!r.hoverData.cxtOver || near !== r.hoverData.cxtOver) {\n if (r.hoverData.cxtOver) {\n r.hoverData.cxtOver.emit({\n originalEvent: e,\n type: 'cxtdragout',\n position: {\n x: pos[0],\n y: pos[1]\n }\n });\n }\n\n r.hoverData.cxtOver = near;\n\n if (near) {\n near.emit({\n originalEvent: e,\n type: 'cxtdragover',\n position: {\n x: pos[0],\n y: pos[1]\n }\n });\n }\n }\n } // Check if we are drag panning the entire graph\n\n } else if (r.hoverData.dragging) {\n preventDefault = true;\n\n if (cy.panningEnabled() && cy.userPanningEnabled()) {\n var deltaP;\n\n if (r.hoverData.justStartedPan) {\n var mdPos = r.hoverData.mdownPos;\n deltaP = {\n x: (pos[0] - mdPos[0]) * zoom,\n y: (pos[1] - mdPos[1]) * zoom\n };\n r.hoverData.justStartedPan = false;\n } else {\n deltaP = {\n x: disp[0] * zoom,\n y: disp[1] * zoom\n };\n }\n\n cy.panBy(deltaP);\n cy.emit('dragpan');\n r.hoverData.dragged = true;\n } // Needs reproject due to pan changing viewport\n\n\n pos = r.projectIntoViewport(e.clientX, e.clientY); // Checks primary button down & out of time & mouse not moved much\n } else if (select[4] == 1 && (down == null || down.pannable())) {\n if (isOverThresholdDrag) {\n if (!r.hoverData.dragging && cy.boxSelectionEnabled() && (multSelKeyDown || !cy.panningEnabled() || !cy.userPanningEnabled())) {\n goIntoBoxMode();\n } else if (!r.hoverData.selecting && cy.panningEnabled() && cy.userPanningEnabled()) {\n var allowPassthrough = allowPanningPassthrough(down, r.hoverData.downs);\n\n if (allowPassthrough) {\n r.hoverData.dragging = true;\n r.hoverData.justStartedPan = true;\n select[4] = 0;\n r.data.bgActivePosistion = array2point(mdownPos);\n r.redrawHint('select', true);\n r.redraw();\n }\n }\n\n if (down && down.pannable() && down.active()) {\n down.unactivate();\n }\n }\n } else {\n if (down && down.pannable() && down.active()) {\n down.unactivate();\n }\n\n if ((!down || !down.grabbed()) && near != last) {\n if (last) {\n triggerEvents(last, ['mouseout', 'tapdragout'], e, {\n x: pos[0],\n y: pos[1]\n });\n }\n\n if (near) {\n triggerEvents(near, ['mouseover', 'tapdragover'], e, {\n x: pos[0],\n y: pos[1]\n });\n }\n\n r.hoverData.last = near;\n }\n\n if (down) {\n if (isOverThresholdDrag) {\n // then we can take action\n if (cy.boxSelectionEnabled() && multSelKeyDown) {\n // then selection overrides\n if (down && down.grabbed()) {\n freeDraggedElements(draggedElements);\n down.emit('freeon');\n draggedElements.emit('free');\n\n if (r.dragData.didDrag) {\n down.emit('dragfreeon');\n draggedElements.emit('dragfree');\n }\n }\n\n goIntoBoxMode();\n } else if (down && down.grabbed() && r.nodeIsDraggable(down)) {\n // drag node\n var justStartedDrag = !r.dragData.didDrag;\n\n if (justStartedDrag) {\n r.redrawHint('eles', true);\n }\n\n r.dragData.didDrag = true; // indicate that we actually did drag the node\n // now, add the elements to the drag layer if not done already\n\n if (!r.hoverData.draggingEles) {\n addNodesToDrag(draggedElements, {\n inDragLayer: true\n });\n }\n\n var totalShift = {\n x: 0,\n y: 0\n };\n\n if (number$1(disp[0]) && number$1(disp[1])) {\n totalShift.x += disp[0];\n totalShift.y += disp[1];\n\n if (justStartedDrag) {\n var dragDelta = r.hoverData.dragDelta;\n\n if (dragDelta && number$1(dragDelta[0]) && number$1(dragDelta[1])) {\n totalShift.x += dragDelta[0];\n totalShift.y += dragDelta[1];\n }\n }\n }\n\n r.hoverData.draggingEles = true;\n draggedElements.silentShift(totalShift).emit('position drag');\n r.redrawHint('drag', true);\n r.redraw();\n }\n } else {\n // otherwise save drag delta for when we actually start dragging so the relative grab pos is constant\n updateDragDelta();\n }\n } // prevent the dragging from triggering text selection on the page\n\n\n preventDefault = true;\n }\n\n select[2] = pos[0];\n select[3] = pos[1];\n\n if (preventDefault) {\n if (e.stopPropagation) e.stopPropagation();\n if (e.preventDefault) e.preventDefault();\n return false;\n }\n }, false);\n var clickTimeout, didDoubleClick, prevClickTimeStamp;\n r.registerBinding(containerWindow, 'mouseup', function mouseupHandler(e) {\n // eslint-disable-line no-undef\n var capture = r.hoverData.capture;\n\n if (!capture) {\n return;\n }\n\n r.hoverData.capture = false;\n var cy = r.cy;\n var pos = r.projectIntoViewport(e.clientX, e.clientY);\n var select = r.selection;\n var near = r.findNearestElement(pos[0], pos[1], true, false);\n var draggedElements = r.dragData.possibleDragElements;\n var down = r.hoverData.down;\n var multSelKeyDown = isMultSelKeyDown(e);\n\n if (r.data.bgActivePosistion) {\n r.redrawHint('select', true);\n r.redraw();\n }\n\n r.hoverData.tapholdCancelled = true;\n r.data.bgActivePosistion = undefined; // not active bg now\n\n if (down) {\n down.unactivate();\n }\n\n if (r.hoverData.which === 3) {\n var cxtEvt = {\n originalEvent: e,\n type: 'cxttapend',\n position: {\n x: pos[0],\n y: pos[1]\n }\n };\n\n if (down) {\n down.emit(cxtEvt);\n } else {\n cy.emit(cxtEvt);\n }\n\n if (!r.hoverData.cxtDragged) {\n var cxtTap = {\n originalEvent: e,\n type: 'cxttap',\n position: {\n x: pos[0],\n y: pos[1]\n }\n };\n\n if (down) {\n down.emit(cxtTap);\n } else {\n cy.emit(cxtTap);\n }\n }\n\n r.hoverData.cxtDragged = false;\n r.hoverData.which = null;\n } else if (r.hoverData.which === 1) {\n triggerEvents(near, ['mouseup', 'tapend', 'vmouseup'], e, {\n x: pos[0],\n y: pos[1]\n });\n\n if (!r.dragData.didDrag && // didn't move a node around\n !r.hoverData.dragged && // didn't pan\n !r.hoverData.selecting && // not box selection\n !r.hoverData.isOverThresholdDrag // didn't move too much\n ) {\n triggerEvents(down, [\"click\", \"tap\", \"vclick\"], e, {\n x: pos[0],\n y: pos[1]\n });\n didDoubleClick = false;\n\n if (e.timeStamp - prevClickTimeStamp <= cy.multiClickDebounceTime()) {\n clickTimeout && clearTimeout(clickTimeout);\n didDoubleClick = true;\n prevClickTimeStamp = null;\n triggerEvents(down, [\"dblclick\", \"dbltap\", \"vdblclick\"], e, {\n x: pos[0],\n y: pos[1]\n });\n } else {\n clickTimeout = setTimeout(function () {\n if (didDoubleClick) return;\n triggerEvents(down, [\"oneclick\", \"onetap\", \"voneclick\"], e, {\n x: pos[0],\n y: pos[1]\n });\n }, cy.multiClickDebounceTime());\n prevClickTimeStamp = e.timeStamp;\n }\n } // Deselect all elements if nothing is currently under the mouse cursor and we aren't dragging something\n\n\n if (down == null // not mousedown on node\n && !r.dragData.didDrag // didn't move the node around\n && !r.hoverData.selecting // not box selection\n && !r.hoverData.dragged // didn't pan\n && !isMultSelKeyDown(e)) {\n cy.$(isSelected).unselect(['tapunselect']);\n\n if (draggedElements.length > 0) {\n r.redrawHint('eles', true);\n }\n\n r.dragData.possibleDragElements = draggedElements = cy.collection();\n } // Single selection\n\n\n if (near == down && !r.dragData.didDrag && !r.hoverData.selecting) {\n if (near != null && near._private.selectable) {\n if (r.hoverData.dragging) ; else if (cy.selectionType() === 'additive' || multSelKeyDown) {\n if (near.selected()) {\n near.unselect(['tapunselect']);\n } else {\n near.select(['tapselect']);\n }\n } else {\n if (!multSelKeyDown) {\n cy.$(isSelected).unmerge(near).unselect(['tapunselect']);\n near.select(['tapselect']);\n }\n }\n\n r.redrawHint('eles', true);\n }\n }\n\n if (r.hoverData.selecting) {\n var box = cy.collection(r.getAllInBox(select[0], select[1], select[2], select[3]));\n r.redrawHint('select', true);\n\n if (box.length > 0) {\n r.redrawHint('eles', true);\n }\n\n cy.emit({\n type: 'boxend',\n originalEvent: e,\n position: {\n x: pos[0],\n y: pos[1]\n }\n });\n\n var eleWouldBeSelected = function eleWouldBeSelected(ele) {\n return ele.selectable() && !ele.selected();\n };\n\n if (cy.selectionType() === 'additive') {\n box.emit('box').stdFilter(eleWouldBeSelected).select().emit('boxselect');\n } else {\n if (!multSelKeyDown) {\n cy.$(isSelected).unmerge(box).unselect();\n }\n\n box.emit('box').stdFilter(eleWouldBeSelected).select().emit('boxselect');\n } // always need redraw in case eles unselectable\n\n\n r.redraw();\n } // Cancel drag pan\n\n\n if (r.hoverData.dragging) {\n r.hoverData.dragging = false;\n r.redrawHint('select', true);\n r.redrawHint('eles', true);\n r.redraw();\n }\n\n if (!select[4]) {\n r.redrawHint('drag', true);\n r.redrawHint('eles', true);\n var downWasGrabbed = down && down.grabbed();\n freeDraggedElements(draggedElements);\n\n if (downWasGrabbed) {\n down.emit('freeon');\n draggedElements.emit('free');\n\n if (r.dragData.didDrag) {\n down.emit('dragfreeon');\n draggedElements.emit('dragfree');\n }\n }\n }\n } // else not right mouse\n\n\n select[4] = 0;\n r.hoverData.down = null;\n r.hoverData.cxtStarted = false;\n r.hoverData.draggingEles = false;\n r.hoverData.selecting = false;\n r.hoverData.isOverThresholdDrag = false;\n r.dragData.didDrag = false;\n r.hoverData.dragged = false;\n r.hoverData.dragDelta = [];\n r.hoverData.mdownPos = null;\n r.hoverData.mdownGPos = null;\n }, false);\n\n var wheelHandler = function wheelHandler(e) {\n if (r.scrollingPage) {\n return;\n } // while scrolling, ignore wheel-to-zoom\n\n\n var cy = r.cy;\n var zoom = cy.zoom();\n var pan = cy.pan();\n var pos = r.projectIntoViewport(e.clientX, e.clientY);\n var rpos = [pos[0] * zoom + pan.x, pos[1] * zoom + pan.y];\n\n if (r.hoverData.draggingEles || r.hoverData.dragging || r.hoverData.cxtStarted || inBoxSelection()) {\n // if pan dragging or cxt dragging, wheel movements make no zoom\n e.preventDefault();\n return;\n }\n\n if (cy.panningEnabled() && cy.userPanningEnabled() && cy.zoomingEnabled() && cy.userZoomingEnabled()) {\n e.preventDefault();\n r.data.wheelZooming = true;\n clearTimeout(r.data.wheelTimeout);\n r.data.wheelTimeout = setTimeout(function () {\n r.data.wheelZooming = false;\n r.redrawHint('eles', true);\n r.redraw();\n }, 150);\n var diff;\n\n if (e.deltaY != null) {\n diff = e.deltaY / -250;\n } else if (e.wheelDeltaY != null) {\n diff = e.wheelDeltaY / 1000;\n } else {\n diff = e.wheelDelta / 1000;\n }\n\n diff = diff * r.wheelSensitivity;\n var needsWheelFix = e.deltaMode === 1;\n\n if (needsWheelFix) {\n // fixes slow wheel events on ff/linux and ff/windows\n diff *= 33;\n }\n\n var newZoom = cy.zoom() * Math.pow(10, diff);\n\n if (e.type === 'gesturechange') {\n newZoom = r.gestureStartZoom * e.scale;\n }\n\n cy.zoom({\n level: newZoom,\n renderedPosition: {\n x: rpos[0],\n y: rpos[1]\n }\n });\n cy.emit(e.type === 'gesturechange' ? 'pinchzoom' : 'scrollzoom');\n }\n }; // Functions to help with whether mouse wheel should trigger zooming\n // --\n\n\n r.registerBinding(r.container, 'wheel', wheelHandler, true); // disable nonstandard wheel events\n // r.registerBinding(r.container, 'mousewheel', wheelHandler, true);\n // r.registerBinding(r.container, 'DOMMouseScroll', wheelHandler, true);\n // r.registerBinding(r.container, 'MozMousePixelScroll', wheelHandler, true); // older firefox\n\n r.registerBinding(containerWindow, 'scroll', function scrollHandler(e) {\n // eslint-disable-line no-unused-vars\n r.scrollingPage = true;\n clearTimeout(r.scrollingPageTimeout);\n r.scrollingPageTimeout = setTimeout(function () {\n r.scrollingPage = false;\n }, 250);\n }, true); // desktop safari pinch to zoom start\n\n r.registerBinding(r.container, 'gesturestart', function gestureStartHandler(e) {\n r.gestureStartZoom = r.cy.zoom();\n\n if (!r.hasTouchStarted) {\n // don't affect touch devices like iphone\n e.preventDefault();\n }\n }, true);\n r.registerBinding(r.container, 'gesturechange', function (e) {\n if (!r.hasTouchStarted) {\n // don't affect touch devices like iphone\n wheelHandler(e);\n }\n }, true); // Functions to help with handling mouseout/mouseover on the Cytoscape container\n // Handle mouseout on Cytoscape container\n\n r.registerBinding(r.container, 'mouseout', function mouseOutHandler(e) {\n var pos = r.projectIntoViewport(e.clientX, e.clientY);\n r.cy.emit({\n originalEvent: e,\n type: 'mouseout',\n position: {\n x: pos[0],\n y: pos[1]\n }\n });\n }, false);\n r.registerBinding(r.container, 'mouseover', function mouseOverHandler(e) {\n var pos = r.projectIntoViewport(e.clientX, e.clientY);\n r.cy.emit({\n originalEvent: e,\n type: 'mouseover',\n position: {\n x: pos[0],\n y: pos[1]\n }\n });\n }, false);\n var f1x1, f1y1, f2x1, f2y1; // starting points for pinch-to-zoom\n\n var distance1, distance1Sq; // initial distance between finger 1 and finger 2 for pinch-to-zoom\n\n var center1, modelCenter1; // center point on start pinch to zoom\n\n var offsetLeft, offsetTop;\n var containerWidth, containerHeight;\n var twoFingersStartInside;\n\n var distance = function distance(x1, y1, x2, y2) {\n return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n };\n\n var distanceSq = function distanceSq(x1, y1, x2, y2) {\n return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);\n };\n\n var touchstartHandler;\n r.registerBinding(r.container, 'touchstart', touchstartHandler = function touchstartHandler(e) {\n r.hasTouchStarted = true;\n\n if (!eventInContainer(e)) {\n return;\n }\n\n blurActiveDomElement();\n r.touchData.capture = true;\n r.data.bgActivePosistion = undefined;\n var cy = r.cy;\n var now = r.touchData.now;\n var earlier = r.touchData.earlier;\n\n if (e.touches[0]) {\n var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);\n now[0] = pos[0];\n now[1] = pos[1];\n }\n\n if (e.touches[1]) {\n var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY);\n now[2] = pos[0];\n now[3] = pos[1];\n }\n\n if (e.touches[2]) {\n var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY);\n now[4] = pos[0];\n now[5] = pos[1];\n } // record starting points for pinch-to-zoom\n\n\n if (e.touches[1]) {\n r.touchData.singleTouchMoved = true;\n freeDraggedElements(r.dragData.touchDragEles);\n var offsets = r.findContainerClientCoords();\n offsetLeft = offsets[0];\n offsetTop = offsets[1];\n containerWidth = offsets[2];\n containerHeight = offsets[3];\n f1x1 = e.touches[0].clientX - offsetLeft;\n f1y1 = e.touches[0].clientY - offsetTop;\n f2x1 = e.touches[1].clientX - offsetLeft;\n f2y1 = e.touches[1].clientY - offsetTop;\n twoFingersStartInside = 0 <= f1x1 && f1x1 <= containerWidth && 0 <= f2x1 && f2x1 <= containerWidth && 0 <= f1y1 && f1y1 <= containerHeight && 0 <= f2y1 && f2y1 <= containerHeight;\n var pan = cy.pan();\n var zoom = cy.zoom();\n distance1 = distance(f1x1, f1y1, f2x1, f2y1);\n distance1Sq = distanceSq(f1x1, f1y1, f2x1, f2y1);\n center1 = [(f1x1 + f2x1) / 2, (f1y1 + f2y1) / 2];\n modelCenter1 = [(center1[0] - pan.x) / zoom, (center1[1] - pan.y) / zoom]; // consider context tap\n\n var cxtDistThreshold = 200;\n var cxtDistThresholdSq = cxtDistThreshold * cxtDistThreshold;\n\n if (distance1Sq < cxtDistThresholdSq && !e.touches[2]) {\n var near1 = r.findNearestElement(now[0], now[1], true, true);\n var near2 = r.findNearestElement(now[2], now[3], true, true);\n\n if (near1 && near1.isNode()) {\n near1.activate().emit({\n originalEvent: e,\n type: 'cxttapstart',\n position: {\n x: now[0],\n y: now[1]\n }\n });\n r.touchData.start = near1;\n } else if (near2 && near2.isNode()) {\n near2.activate().emit({\n originalEvent: e,\n type: 'cxttapstart',\n position: {\n x: now[0],\n y: now[1]\n }\n });\n r.touchData.start = near2;\n } else {\n cy.emit({\n originalEvent: e,\n type: 'cxttapstart',\n position: {\n x: now[0],\n y: now[1]\n }\n });\n }\n\n if (r.touchData.start) {\n r.touchData.start._private.grabbed = false;\n }\n\n r.touchData.cxt = true;\n r.touchData.cxtDragged = false;\n r.data.bgActivePosistion = undefined;\n r.redraw();\n return;\n }\n }\n\n if (e.touches[2]) {\n // ignore\n // safari on ios pans the page otherwise (normally you should be able to preventdefault on touchmove...)\n if (cy.boxSelectionEnabled()) {\n e.preventDefault();\n }\n } else if (e.touches[1]) ; else if (e.touches[0]) {\n var nears = r.findNearestElements(now[0], now[1], true, true);\n var near = nears[0];\n\n if (near != null) {\n near.activate();\n r.touchData.start = near;\n r.touchData.starts = nears;\n\n if (r.nodeIsGrabbable(near)) {\n var draggedEles = r.dragData.touchDragEles = cy.collection();\n var selectedNodes = null;\n r.redrawHint('eles', true);\n r.redrawHint('drag', true);\n\n if (near.selected()) {\n // reset drag elements, since near will be added again\n selectedNodes = cy.$(function (ele) {\n return ele.selected() && r.nodeIsGrabbable(ele);\n });\n addNodesToDrag(selectedNodes, {\n addToList: draggedEles\n });\n } else {\n addNodeToDrag(near, {\n addToList: draggedEles\n });\n }\n\n setGrabTarget(near);\n\n var makeEvent = function makeEvent(type) {\n return {\n originalEvent: e,\n type: type,\n position: {\n x: now[0],\n y: now[1]\n }\n };\n };\n\n near.emit(makeEvent('grabon'));\n\n if (selectedNodes) {\n selectedNodes.forEach(function (n) {\n n.emit(makeEvent('grab'));\n });\n } else {\n near.emit(makeEvent('grab'));\n }\n }\n }\n\n triggerEvents(near, ['touchstart', 'tapstart', 'vmousedown'], e, {\n x: now[0],\n y: now[1]\n });\n\n if (near == null) {\n r.data.bgActivePosistion = {\n x: pos[0],\n y: pos[1]\n };\n r.redrawHint('select', true);\n r.redraw();\n } // Tap, taphold\n // -----\n\n\n r.touchData.singleTouchMoved = false;\n r.touchData.singleTouchStartTime = +new Date();\n clearTimeout(r.touchData.tapholdTimeout);\n r.touchData.tapholdTimeout = setTimeout(function () {\n if (r.touchData.singleTouchMoved === false && !r.pinching // if pinching, then taphold unselect shouldn't take effect\n && !r.touchData.selecting // box selection shouldn't allow taphold through\n ) {\n triggerEvents(r.touchData.start, ['taphold'], e, {\n x: now[0],\n y: now[1]\n });\n }\n }, r.tapholdDuration);\n }\n\n if (e.touches.length >= 1) {\n var sPos = r.touchData.startPosition = [null, null, null, null, null, null];\n\n for (var i = 0; i < now.length; i++) {\n sPos[i] = earlier[i] = now[i];\n }\n\n var touch0 = e.touches[0];\n r.touchData.startGPosition = [touch0.clientX, touch0.clientY];\n }\n }, false);\n var touchmoveHandler;\n r.registerBinding(window, 'touchmove', touchmoveHandler = function touchmoveHandler(e) {\n // eslint-disable-line no-undef\n var capture = r.touchData.capture;\n\n if (!capture && !eventInContainer(e)) {\n return;\n }\n\n var select = r.selection;\n var cy = r.cy;\n var now = r.touchData.now;\n var earlier = r.touchData.earlier;\n var zoom = cy.zoom();\n\n if (e.touches[0]) {\n var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);\n now[0] = pos[0];\n now[1] = pos[1];\n }\n\n if (e.touches[1]) {\n var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY);\n now[2] = pos[0];\n now[3] = pos[1];\n }\n\n if (e.touches[2]) {\n var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY);\n now[4] = pos[0];\n now[5] = pos[1];\n }\n\n var startGPos = r.touchData.startGPosition;\n var isOverThresholdDrag;\n\n if (capture && e.touches[0] && startGPos) {\n var disp = [];\n\n for (var j = 0; j < now.length; j++) {\n disp[j] = now[j] - earlier[j];\n }\n\n var dx = e.touches[0].clientX - startGPos[0];\n var dx2 = dx * dx;\n var dy = e.touches[0].clientY - startGPos[1];\n var dy2 = dy * dy;\n var dist2 = dx2 + dy2;\n isOverThresholdDrag = dist2 >= r.touchTapThreshold2;\n } // context swipe cancelling\n\n\n if (capture && r.touchData.cxt) {\n e.preventDefault();\n var f1x2 = e.touches[0].clientX - offsetLeft,\n f1y2 = e.touches[0].clientY - offsetTop;\n var f2x2 = e.touches[1].clientX - offsetLeft,\n f2y2 = e.touches[1].clientY - offsetTop; // var distance2 = distance( f1x2, f1y2, f2x2, f2y2 );\n\n var distance2Sq = distanceSq(f1x2, f1y2, f2x2, f2y2);\n var factorSq = distance2Sq / distance1Sq;\n var distThreshold = 150;\n var distThresholdSq = distThreshold * distThreshold;\n var factorThreshold = 1.5;\n var factorThresholdSq = factorThreshold * factorThreshold; // cancel ctx gestures if the distance b/t the fingers increases\n\n if (factorSq >= factorThresholdSq || distance2Sq >= distThresholdSq) {\n r.touchData.cxt = false;\n r.data.bgActivePosistion = undefined;\n r.redrawHint('select', true);\n var cxtEvt = {\n originalEvent: e,\n type: 'cxttapend',\n position: {\n x: now[0],\n y: now[1]\n }\n };\n\n if (r.touchData.start) {\n r.touchData.start.unactivate().emit(cxtEvt);\n r.touchData.start = null;\n } else {\n cy.emit(cxtEvt);\n }\n }\n } // context swipe\n\n\n if (capture && r.touchData.cxt) {\n var cxtEvt = {\n originalEvent: e,\n type: 'cxtdrag',\n position: {\n x: now[0],\n y: now[1]\n }\n };\n r.data.bgActivePosistion = undefined;\n r.redrawHint('select', true);\n\n if (r.touchData.start) {\n r.touchData.start.emit(cxtEvt);\n } else {\n cy.emit(cxtEvt);\n }\n\n if (r.touchData.start) {\n r.touchData.start._private.grabbed = false;\n }\n\n r.touchData.cxtDragged = true;\n var near = r.findNearestElement(now[0], now[1], true, true);\n\n if (!r.touchData.cxtOver || near !== r.touchData.cxtOver) {\n if (r.touchData.cxtOver) {\n r.touchData.cxtOver.emit({\n originalEvent: e,\n type: 'cxtdragout',\n position: {\n x: now[0],\n y: now[1]\n }\n });\n }\n\n r.touchData.cxtOver = near;\n\n if (near) {\n near.emit({\n originalEvent: e,\n type: 'cxtdragover',\n position: {\n x: now[0],\n y: now[1]\n }\n });\n }\n } // box selection\n\n } else if (capture && e.touches[2] && cy.boxSelectionEnabled()) {\n e.preventDefault();\n r.data.bgActivePosistion = undefined;\n this.lastThreeTouch = +new Date();\n\n if (!r.touchData.selecting) {\n cy.emit({\n originalEvent: e,\n type: 'boxstart',\n position: {\n x: now[0],\n y: now[1]\n }\n });\n }\n\n r.touchData.selecting = true;\n r.touchData.didSelect = true;\n select[4] = 1;\n\n if (!select || select.length === 0 || select[0] === undefined) {\n select[0] = (now[0] + now[2] + now[4]) / 3;\n select[1] = (now[1] + now[3] + now[5]) / 3;\n select[2] = (now[0] + now[2] + now[4]) / 3 + 1;\n select[3] = (now[1] + now[3] + now[5]) / 3 + 1;\n } else {\n select[2] = (now[0] + now[2] + now[4]) / 3;\n select[3] = (now[1] + now[3] + now[5]) / 3;\n }\n\n r.redrawHint('select', true);\n r.redraw(); // pinch to zoom\n } else if (capture && e.touches[1] && !r.touchData.didSelect // don't allow box selection to degrade to pinch-to-zoom\n && cy.zoomingEnabled() && cy.panningEnabled() && cy.userZoomingEnabled() && cy.userPanningEnabled()) {\n // two fingers => pinch to zoom\n e.preventDefault();\n r.data.bgActivePosistion = undefined;\n r.redrawHint('select', true);\n var draggedEles = r.dragData.touchDragEles;\n\n if (draggedEles) {\n r.redrawHint('drag', true);\n\n for (var i = 0; i < draggedEles.length; i++) {\n var de_p = draggedEles[i]._private;\n de_p.grabbed = false;\n de_p.rscratch.inDragLayer = false;\n }\n }\n\n var _start = r.touchData.start; // (x2, y2) for fingers 1 and 2\n\n var f1x2 = e.touches[0].clientX - offsetLeft,\n f1y2 = e.touches[0].clientY - offsetTop;\n var f2x2 = e.touches[1].clientX - offsetLeft,\n f2y2 = e.touches[1].clientY - offsetTop;\n var distance2 = distance(f1x2, f1y2, f2x2, f2y2); // var distance2Sq = distanceSq( f1x2, f1y2, f2x2, f2y2 );\n // var factor = Math.sqrt( distance2Sq ) / Math.sqrt( distance1Sq );\n\n var factor = distance2 / distance1;\n\n if (twoFingersStartInside) {\n // delta finger1\n var df1x = f1x2 - f1x1;\n var df1y = f1y2 - f1y1; // delta finger 2\n\n var df2x = f2x2 - f2x1;\n var df2y = f2y2 - f2y1; // translation is the normalised vector of the two fingers movement\n // i.e. so pinching cancels out and moving together pans\n\n var tx = (df1x + df2x) / 2;\n var ty = (df1y + df2y) / 2; // now calculate the zoom\n\n var zoom1 = cy.zoom();\n var zoom2 = zoom1 * factor;\n var pan1 = cy.pan(); // the model center point converted to the current rendered pos\n\n var ctrx = modelCenter1[0] * zoom1 + pan1.x;\n var ctry = modelCenter1[1] * zoom1 + pan1.y;\n var pan2 = {\n x: -zoom2 / zoom1 * (ctrx - pan1.x - tx) + ctrx,\n y: -zoom2 / zoom1 * (ctry - pan1.y - ty) + ctry\n }; // remove dragged eles\n\n if (_start && _start.active()) {\n var draggedEles = r.dragData.touchDragEles;\n freeDraggedElements(draggedEles);\n r.redrawHint('drag', true);\n r.redrawHint('eles', true);\n\n _start.unactivate().emit('freeon');\n\n draggedEles.emit('free');\n\n if (r.dragData.didDrag) {\n _start.emit('dragfreeon');\n\n draggedEles.emit('dragfree');\n }\n }\n\n cy.viewport({\n zoom: zoom2,\n pan: pan2,\n cancelOnFailedZoom: true\n });\n cy.emit('pinchzoom');\n distance1 = distance2;\n f1x1 = f1x2;\n f1y1 = f1y2;\n f2x1 = f2x2;\n f2y1 = f2y2;\n r.pinching = true;\n } // Re-project\n\n\n if (e.touches[0]) {\n var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);\n now[0] = pos[0];\n now[1] = pos[1];\n }\n\n if (e.touches[1]) {\n var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY);\n now[2] = pos[0];\n now[3] = pos[1];\n }\n\n if (e.touches[2]) {\n var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY);\n now[4] = pos[0];\n now[5] = pos[1];\n }\n } else if (e.touches[0] && !r.touchData.didSelect // don't allow box selection to degrade to single finger events like panning\n ) {\n var start = r.touchData.start;\n var last = r.touchData.last;\n var near;\n\n if (!r.hoverData.draggingEles && !r.swipePanning) {\n near = r.findNearestElement(now[0], now[1], true, true);\n }\n\n if (capture && start != null) {\n e.preventDefault();\n } // dragging nodes\n\n\n if (capture && start != null && r.nodeIsDraggable(start)) {\n if (isOverThresholdDrag) {\n // then dragging can happen\n var draggedEles = r.dragData.touchDragEles;\n var justStartedDrag = !r.dragData.didDrag;\n\n if (justStartedDrag) {\n addNodesToDrag(draggedEles, {\n inDragLayer: true\n });\n }\n\n r.dragData.didDrag = true;\n var totalShift = {\n x: 0,\n y: 0\n };\n\n if (number$1(disp[0]) && number$1(disp[1])) {\n totalShift.x += disp[0];\n totalShift.y += disp[1];\n\n if (justStartedDrag) {\n r.redrawHint('eles', true);\n var dragDelta = r.touchData.dragDelta;\n\n if (dragDelta && number$1(dragDelta[0]) && number$1(dragDelta[1])) {\n totalShift.x += dragDelta[0];\n totalShift.y += dragDelta[1];\n }\n }\n }\n\n r.hoverData.draggingEles = true;\n draggedEles.silentShift(totalShift).emit('position drag');\n r.redrawHint('drag', true);\n\n if (r.touchData.startPosition[0] == earlier[0] && r.touchData.startPosition[1] == earlier[1]) {\n r.redrawHint('eles', true);\n }\n\n r.redraw();\n } else {\n // otherwise keep track of drag delta for later\n var dragDelta = r.touchData.dragDelta = r.touchData.dragDelta || [];\n\n if (dragDelta.length === 0) {\n dragDelta.push(disp[0]);\n dragDelta.push(disp[1]);\n } else {\n dragDelta[0] += disp[0];\n dragDelta[1] += disp[1];\n }\n }\n } // touchmove\n\n\n {\n triggerEvents(start || near, ['touchmove', 'tapdrag', 'vmousemove'], e, {\n x: now[0],\n y: now[1]\n });\n\n if ((!start || !start.grabbed()) && near != last) {\n if (last) {\n last.emit({\n originalEvent: e,\n type: 'tapdragout',\n position: {\n x: now[0],\n y: now[1]\n }\n });\n }\n\n if (near) {\n near.emit({\n originalEvent: e,\n type: 'tapdragover',\n position: {\n x: now[0],\n y: now[1]\n }\n });\n }\n }\n\n r.touchData.last = near;\n } // check to cancel taphold\n\n if (capture) {\n for (var i = 0; i < now.length; i++) {\n if (now[i] && r.touchData.startPosition[i] && isOverThresholdDrag) {\n r.touchData.singleTouchMoved = true;\n }\n }\n } // panning\n\n\n if (capture && (start == null || start.pannable()) && cy.panningEnabled() && cy.userPanningEnabled()) {\n var allowPassthrough = allowPanningPassthrough(start, r.touchData.starts);\n\n if (allowPassthrough) {\n e.preventDefault();\n\n if (!r.data.bgActivePosistion) {\n r.data.bgActivePosistion = array2point(r.touchData.startPosition);\n }\n\n if (r.swipePanning) {\n cy.panBy({\n x: disp[0] * zoom,\n y: disp[1] * zoom\n });\n cy.emit('dragpan');\n } else if (isOverThresholdDrag) {\n r.swipePanning = true;\n cy.panBy({\n x: dx * zoom,\n y: dy * zoom\n });\n cy.emit('dragpan');\n\n if (start) {\n start.unactivate();\n r.redrawHint('select', true);\n r.touchData.start = null;\n }\n }\n } // Re-project\n\n\n var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);\n now[0] = pos[0];\n now[1] = pos[1];\n }\n }\n\n for (var j = 0; j < now.length; j++) {\n earlier[j] = now[j];\n } // the active bg indicator should be removed when making a swipe that is neither for dragging nodes or panning\n\n\n if (capture && e.touches.length > 0 && !r.hoverData.draggingEles && !r.swipePanning && r.data.bgActivePosistion != null) {\n r.data.bgActivePosistion = undefined;\n r.redrawHint('select', true);\n r.redraw();\n }\n }, false);\n var touchcancelHandler;\n r.registerBinding(containerWindow, 'touchcancel', touchcancelHandler = function touchcancelHandler(e) {\n // eslint-disable-line no-unused-vars\n var start = r.touchData.start;\n r.touchData.capture = false;\n\n if (start) {\n start.unactivate();\n }\n });\n var touchendHandler, didDoubleTouch, touchTimeout, prevTouchTimeStamp;\n r.registerBinding(containerWindow, 'touchend', touchendHandler = function touchendHandler(e) {\n // eslint-disable-line no-unused-vars\n var start = r.touchData.start;\n var capture = r.touchData.capture;\n\n if (capture) {\n if (e.touches.length === 0) {\n r.touchData.capture = false;\n }\n\n e.preventDefault();\n } else {\n return;\n }\n\n var select = r.selection;\n r.swipePanning = false;\n r.hoverData.draggingEles = false;\n var cy = r.cy;\n var zoom = cy.zoom();\n var now = r.touchData.now;\n var earlier = r.touchData.earlier;\n\n if (e.touches[0]) {\n var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);\n now[0] = pos[0];\n now[1] = pos[1];\n }\n\n if (e.touches[1]) {\n var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY);\n now[2] = pos[0];\n now[3] = pos[1];\n }\n\n if (e.touches[2]) {\n var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY);\n now[4] = pos[0];\n now[5] = pos[1];\n }\n\n if (start) {\n start.unactivate();\n }\n\n var ctxTapend;\n\n if (r.touchData.cxt) {\n ctxTapend = {\n originalEvent: e,\n type: 'cxttapend',\n position: {\n x: now[0],\n y: now[1]\n }\n };\n\n if (start) {\n start.emit(ctxTapend);\n } else {\n cy.emit(ctxTapend);\n }\n\n if (!r.touchData.cxtDragged) {\n var ctxTap = {\n originalEvent: e,\n type: 'cxttap',\n position: {\n x: now[0],\n y: now[1]\n }\n };\n\n if (start) {\n start.emit(ctxTap);\n } else {\n cy.emit(ctxTap);\n }\n }\n\n if (r.touchData.start) {\n r.touchData.start._private.grabbed = false;\n }\n\n r.touchData.cxt = false;\n r.touchData.start = null;\n r.redraw();\n return;\n } // no more box selection if we don't have three fingers\n\n\n if (!e.touches[2] && cy.boxSelectionEnabled() && r.touchData.selecting) {\n r.touchData.selecting = false;\n var box = cy.collection(r.getAllInBox(select[0], select[1], select[2], select[3]));\n select[0] = undefined;\n select[1] = undefined;\n select[2] = undefined;\n select[3] = undefined;\n select[4] = 0;\n r.redrawHint('select', true);\n cy.emit({\n type: 'boxend',\n originalEvent: e,\n position: {\n x: now[0],\n y: now[1]\n }\n });\n\n var eleWouldBeSelected = function eleWouldBeSelected(ele) {\n return ele.selectable() && !ele.selected();\n };\n\n box.emit('box').stdFilter(eleWouldBeSelected).select().emit('boxselect');\n\n if (box.nonempty()) {\n r.redrawHint('eles', true);\n }\n\n r.redraw();\n }\n\n if (start != null) {\n start.unactivate();\n }\n\n if (e.touches[2]) {\n r.data.bgActivePosistion = undefined;\n r.redrawHint('select', true);\n } else if (e.touches[1]) ; else if (e.touches[0]) ; else if (!e.touches[0]) {\n r.data.bgActivePosistion = undefined;\n r.redrawHint('select', true);\n var draggedEles = r.dragData.touchDragEles;\n\n if (start != null) {\n var startWasGrabbed = start._private.grabbed;\n freeDraggedElements(draggedEles);\n r.redrawHint('drag', true);\n r.redrawHint('eles', true);\n\n if (startWasGrabbed) {\n start.emit('freeon');\n draggedEles.emit('free');\n\n if (r.dragData.didDrag) {\n start.emit('dragfreeon');\n draggedEles.emit('dragfree');\n }\n }\n\n triggerEvents(start, ['touchend', 'tapend', 'vmouseup', 'tapdragout'], e, {\n x: now[0],\n y: now[1]\n });\n start.unactivate();\n r.touchData.start = null;\n } else {\n var near = r.findNearestElement(now[0], now[1], true, true);\n triggerEvents(near, ['touchend', 'tapend', 'vmouseup', 'tapdragout'], e, {\n x: now[0],\n y: now[1]\n });\n }\n\n var dx = r.touchData.startPosition[0] - now[0];\n var dx2 = dx * dx;\n var dy = r.touchData.startPosition[1] - now[1];\n var dy2 = dy * dy;\n var dist2 = dx2 + dy2;\n var rdist2 = dist2 * zoom * zoom; // Tap event, roughly same as mouse click event for touch\n\n if (!r.touchData.singleTouchMoved) {\n if (!start) {\n cy.$(':selected').unselect(['tapunselect']);\n }\n\n triggerEvents(start, ['tap', 'vclick'], e, {\n x: now[0],\n y: now[1]\n });\n didDoubleTouch = false;\n\n if (e.timeStamp - prevTouchTimeStamp <= cy.multiClickDebounceTime()) {\n touchTimeout && clearTimeout(touchTimeout);\n didDoubleTouch = true;\n prevTouchTimeStamp = null;\n triggerEvents(start, ['dbltap', 'vdblclick'], e, {\n x: now[0],\n y: now[1]\n });\n } else {\n touchTimeout = setTimeout(function () {\n if (didDoubleTouch) return;\n triggerEvents(start, ['onetap', 'voneclick'], e, {\n x: now[0],\n y: now[1]\n });\n }, cy.multiClickDebounceTime());\n prevTouchTimeStamp = e.timeStamp;\n }\n } // Prepare to select the currently touched node, only if it hasn't been dragged past a certain distance\n\n\n if (start != null && !r.dragData.didDrag // didn't drag nodes around\n && start._private.selectable && rdist2 < r.touchTapThreshold2 && !r.pinching // pinch to zoom should not affect selection\n ) {\n if (cy.selectionType() === 'single') {\n cy.$(isSelected).unmerge(start).unselect(['tapunselect']);\n start.select(['tapselect']);\n } else {\n if (start.selected()) {\n start.unselect(['tapunselect']);\n } else {\n start.select(['tapselect']);\n }\n }\n\n r.redrawHint('eles', true);\n }\n\n r.touchData.singleTouchMoved = true;\n }\n\n for (var j = 0; j < now.length; j++) {\n earlier[j] = now[j];\n }\n\n r.dragData.didDrag = false; // reset for next touchstart\n\n if (e.touches.length === 0) {\n r.touchData.dragDelta = [];\n r.touchData.startPosition = [null, null, null, null, null, null];\n r.touchData.startGPosition = null;\n r.touchData.didSelect = false;\n }\n\n if (e.touches.length < 2) {\n if (e.touches.length === 1) {\n // the old start global pos'n may not be the same finger that remains\n r.touchData.startGPosition = [e.touches[0].clientX, e.touches[0].clientY];\n }\n\n r.pinching = false;\n r.redrawHint('eles', true);\n r.redraw();\n } //r.redraw();\n\n }, false); // fallback compatibility layer for ms pointer events\n\n if (typeof TouchEvent === 'undefined') {\n var pointers = [];\n\n var makeTouch = function makeTouch(e) {\n return {\n clientX: e.clientX,\n clientY: e.clientY,\n force: 1,\n identifier: e.pointerId,\n pageX: e.pageX,\n pageY: e.pageY,\n radiusX: e.width / 2,\n radiusY: e.height / 2,\n screenX: e.screenX,\n screenY: e.screenY,\n target: e.target\n };\n };\n\n var makePointer = function makePointer(e) {\n return {\n event: e,\n touch: makeTouch(e)\n };\n };\n\n var addPointer = function addPointer(e) {\n pointers.push(makePointer(e));\n };\n\n var removePointer = function removePointer(e) {\n for (var i = 0; i < pointers.length; i++) {\n var p = pointers[i];\n\n if (p.event.pointerId === e.pointerId) {\n pointers.splice(i, 1);\n return;\n }\n }\n };\n\n var updatePointer = function updatePointer(e) {\n var p = pointers.filter(function (p) {\n return p.event.pointerId === e.pointerId;\n })[0];\n p.event = e;\n p.touch = makeTouch(e);\n };\n\n var addTouchesToEvent = function addTouchesToEvent(e) {\n e.touches = pointers.map(function (p) {\n return p.touch;\n });\n };\n\n var pointerIsMouse = function pointerIsMouse(e) {\n return e.pointerType === 'mouse' || e.pointerType === 4;\n };\n\n r.registerBinding(r.container, 'pointerdown', function (e) {\n if (pointerIsMouse(e)) {\n return;\n } // mouse already handled\n\n\n e.preventDefault();\n addPointer(e);\n addTouchesToEvent(e);\n touchstartHandler(e);\n });\n r.registerBinding(r.container, 'pointerup', function (e) {\n if (pointerIsMouse(e)) {\n return;\n } // mouse already handled\n\n\n removePointer(e);\n addTouchesToEvent(e);\n touchendHandler(e);\n });\n r.registerBinding(r.container, 'pointercancel', function (e) {\n if (pointerIsMouse(e)) {\n return;\n } // mouse already handled\n\n\n removePointer(e);\n addTouchesToEvent(e);\n touchcancelHandler(e);\n });\n r.registerBinding(r.container, 'pointermove', function (e) {\n if (pointerIsMouse(e)) {\n return;\n } // mouse already handled\n\n\n e.preventDefault();\n updatePointer(e);\n addTouchesToEvent(e);\n touchmoveHandler(e);\n });\n }\n };\n\n var BRp$2 = {};\n\n BRp$2.generatePolygon = function (name, points) {\n return this.nodeShapes[name] = {\n renderer: this,\n name: name,\n points: points,\n draw: function draw(context, centerX, centerY, width, height) {\n this.renderer.nodeShapeImpl('polygon', context, centerX, centerY, width, height, this.points);\n },\n intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) {\n return polygonIntersectLine(x, y, this.points, nodeX, nodeY, width / 2, height / 2, padding);\n },\n checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) {\n return pointInsidePolygon(x, y, this.points, centerX, centerY, width, height, [0, -1], padding);\n }\n };\n };\n\n BRp$2.generateEllipse = function () {\n return this.nodeShapes['ellipse'] = {\n renderer: this,\n name: 'ellipse',\n draw: function draw(context, centerX, centerY, width, height) {\n this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height);\n },\n intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) {\n return intersectLineEllipse(x, y, nodeX, nodeY, width / 2 + padding, height / 2 + padding);\n },\n checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) {\n return checkInEllipse(x, y, width, height, centerX, centerY, padding);\n }\n };\n };\n\n BRp$2.generateRoundPolygon = function (name, points) {\n // Pre-compute control points\n // Since these points depend on the radius length (which in turns depend on the width/height of the node) we will only pre-compute\n // the unit vectors.\n // For simplicity the layout will be:\n // [ p0, UnitVectorP0P1, p1, UniVectorP1P2, ..., pn, UnitVectorPnP0 ]\n var allPoints = new Array(points.length * 2);\n\n for (var i = 0; i < points.length / 2; i++) {\n var sourceIndex = i * 2;\n var destIndex = void 0;\n\n if (i < points.length / 2 - 1) {\n destIndex = (i + 1) * 2;\n } else {\n destIndex = 0;\n }\n\n allPoints[i * 4] = points[sourceIndex];\n allPoints[i * 4 + 1] = points[sourceIndex + 1];\n var xDest = points[destIndex] - points[sourceIndex];\n var yDest = points[destIndex + 1] - points[sourceIndex + 1];\n var norm = Math.sqrt(xDest * xDest + yDest * yDest);\n allPoints[i * 4 + 2] = xDest / norm;\n allPoints[i * 4 + 3] = yDest / norm;\n }\n\n return this.nodeShapes[name] = {\n renderer: this,\n name: name,\n points: allPoints,\n draw: function draw(context, centerX, centerY, width, height) {\n this.renderer.nodeShapeImpl('round-polygon', context, centerX, centerY, width, height, this.points);\n },\n intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) {\n return roundPolygonIntersectLine(x, y, this.points, nodeX, nodeY, width, height);\n },\n checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) {\n return pointInsideRoundPolygon(x, y, this.points, centerX, centerY, width, height);\n }\n };\n };\n\n BRp$2.generateRoundRectangle = function () {\n return this.nodeShapes['round-rectangle'] = this.nodeShapes['roundrectangle'] = {\n renderer: this,\n name: 'round-rectangle',\n points: generateUnitNgonPointsFitToSquare(4, 0),\n draw: function draw(context, centerX, centerY, width, height) {\n this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height);\n },\n intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) {\n return roundRectangleIntersectLine(x, y, nodeX, nodeY, width, height, padding);\n },\n checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) {\n var cornerRadius = getRoundRectangleRadius(width, height);\n var diam = cornerRadius * 2; // Check hBox\n\n if (pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - diam, [0, -1], padding)) {\n return true;\n } // Check vBox\n\n\n if (pointInsidePolygon(x, y, this.points, centerX, centerY, width - diam, height, [0, -1], padding)) {\n return true;\n } // Check top left quarter circle\n\n\n if (checkInEllipse(x, y, diam, diam, centerX - width / 2 + cornerRadius, centerY - height / 2 + cornerRadius, padding)) {\n return true;\n } // Check top right quarter circle\n\n\n if (checkInEllipse(x, y, diam, diam, centerX + width / 2 - cornerRadius, centerY - height / 2 + cornerRadius, padding)) {\n return true;\n } // Check bottom right quarter circle\n\n\n if (checkInEllipse(x, y, diam, diam, centerX + width / 2 - cornerRadius, centerY + height / 2 - cornerRadius, padding)) {\n return true;\n } // Check bottom left quarter circle\n\n\n if (checkInEllipse(x, y, diam, diam, centerX - width / 2 + cornerRadius, centerY + height / 2 - cornerRadius, padding)) {\n return true;\n }\n\n return false;\n }\n };\n };\n\n BRp$2.generateCutRectangle = function () {\n return this.nodeShapes['cut-rectangle'] = this.nodeShapes['cutrectangle'] = {\n renderer: this,\n name: 'cut-rectangle',\n cornerLength: getCutRectangleCornerLength(),\n points: generateUnitNgonPointsFitToSquare(4, 0),\n draw: function draw(context, centerX, centerY, width, height) {\n this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height);\n },\n generateCutTrianglePts: function generateCutTrianglePts(width, height, centerX, centerY) {\n var cl = this.cornerLength;\n var hh = height / 2;\n var hw = width / 2;\n var xBegin = centerX - hw;\n var xEnd = centerX + hw;\n var yBegin = centerY - hh;\n var yEnd = centerY + hh; // points are in clockwise order, inner (imaginary) triangle pt on [4, 5]\n\n return {\n topLeft: [xBegin, yBegin + cl, xBegin + cl, yBegin, xBegin + cl, yBegin + cl],\n topRight: [xEnd - cl, yBegin, xEnd, yBegin + cl, xEnd - cl, yBegin + cl],\n bottomRight: [xEnd, yEnd - cl, xEnd - cl, yEnd, xEnd - cl, yEnd - cl],\n bottomLeft: [xBegin + cl, yEnd, xBegin, yEnd - cl, xBegin + cl, yEnd - cl]\n };\n },\n intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) {\n var cPts = this.generateCutTrianglePts(width + 2 * padding, height + 2 * padding, nodeX, nodeY);\n var pts = [].concat.apply([], [cPts.topLeft.splice(0, 4), cPts.topRight.splice(0, 4), cPts.bottomRight.splice(0, 4), cPts.bottomLeft.splice(0, 4)]);\n return polygonIntersectLine(x, y, pts, nodeX, nodeY);\n },\n checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) {\n // Check hBox\n if (pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - 2 * this.cornerLength, [0, -1], padding)) {\n return true;\n } // Check vBox\n\n\n if (pointInsidePolygon(x, y, this.points, centerX, centerY, width - 2 * this.cornerLength, height, [0, -1], padding)) {\n return true;\n }\n\n var cutTrianglePts = this.generateCutTrianglePts(width, height, centerX, centerY);\n return pointInsidePolygonPoints(x, y, cutTrianglePts.topLeft) || pointInsidePolygonPoints(x, y, cutTrianglePts.topRight) || pointInsidePolygonPoints(x, y, cutTrianglePts.bottomRight) || pointInsidePolygonPoints(x, y, cutTrianglePts.bottomLeft);\n }\n };\n };\n\n BRp$2.generateBarrel = function () {\n return this.nodeShapes['barrel'] = {\n renderer: this,\n name: 'barrel',\n points: generateUnitNgonPointsFitToSquare(4, 0),\n draw: function draw(context, centerX, centerY, width, height) {\n this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height);\n },\n intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) {\n // use two fixed t values for the bezier curve approximation\n var t0 = 0.15;\n var t1 = 0.5;\n var t2 = 0.85;\n var bPts = this.generateBarrelBezierPts(width + 2 * padding, height + 2 * padding, nodeX, nodeY);\n\n var approximateBarrelCurvePts = function approximateBarrelCurvePts(pts) {\n // approximate curve pts based on the two t values\n var m0 = qbezierPtAt({\n x: pts[0],\n y: pts[1]\n }, {\n x: pts[2],\n y: pts[3]\n }, {\n x: pts[4],\n y: pts[5]\n }, t0);\n var m1 = qbezierPtAt({\n x: pts[0],\n y: pts[1]\n }, {\n x: pts[2],\n y: pts[3]\n }, {\n x: pts[4],\n y: pts[5]\n }, t1);\n var m2 = qbezierPtAt({\n x: pts[0],\n y: pts[1]\n }, {\n x: pts[2],\n y: pts[3]\n }, {\n x: pts[4],\n y: pts[5]\n }, t2);\n return [pts[0], pts[1], m0.x, m0.y, m1.x, m1.y, m2.x, m2.y, pts[4], pts[5]];\n };\n\n var pts = [].concat(approximateBarrelCurvePts(bPts.topLeft), approximateBarrelCurvePts(bPts.topRight), approximateBarrelCurvePts(bPts.bottomRight), approximateBarrelCurvePts(bPts.bottomLeft));\n return polygonIntersectLine(x, y, pts, nodeX, nodeY);\n },\n generateBarrelBezierPts: function generateBarrelBezierPts(width, height, centerX, centerY) {\n var hh = height / 2;\n var hw = width / 2;\n var xBegin = centerX - hw;\n var xEnd = centerX + hw;\n var yBegin = centerY - hh;\n var yEnd = centerY + hh;\n var curveConstants = getBarrelCurveConstants(width, height);\n var hOffset = curveConstants.heightOffset;\n var wOffset = curveConstants.widthOffset;\n var ctrlPtXOffset = curveConstants.ctrlPtOffsetPct * width; // points are in clockwise order, inner (imaginary) control pt on [4, 5]\n\n var pts = {\n topLeft: [xBegin, yBegin + hOffset, xBegin + ctrlPtXOffset, yBegin, xBegin + wOffset, yBegin],\n topRight: [xEnd - wOffset, yBegin, xEnd - ctrlPtXOffset, yBegin, xEnd, yBegin + hOffset],\n bottomRight: [xEnd, yEnd - hOffset, xEnd - ctrlPtXOffset, yEnd, xEnd - wOffset, yEnd],\n bottomLeft: [xBegin + wOffset, yEnd, xBegin + ctrlPtXOffset, yEnd, xBegin, yEnd - hOffset]\n };\n pts.topLeft.isTop = true;\n pts.topRight.isTop = true;\n pts.bottomLeft.isBottom = true;\n pts.bottomRight.isBottom = true;\n return pts;\n },\n checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) {\n var curveConstants = getBarrelCurveConstants(width, height);\n var hOffset = curveConstants.heightOffset;\n var wOffset = curveConstants.widthOffset; // Check hBox\n\n if (pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - 2 * hOffset, [0, -1], padding)) {\n return true;\n } // Check vBox\n\n\n if (pointInsidePolygon(x, y, this.points, centerX, centerY, width - 2 * wOffset, height, [0, -1], padding)) {\n return true;\n }\n\n var barrelCurvePts = this.generateBarrelBezierPts(width, height, centerX, centerY);\n\n var getCurveT = function getCurveT(x, y, curvePts) {\n var x0 = curvePts[4];\n var x1 = curvePts[2];\n var x2 = curvePts[0];\n var y0 = curvePts[5]; // var y1 = curvePts[ 3 ];\n\n var y2 = curvePts[1];\n var xMin = Math.min(x0, x2);\n var xMax = Math.max(x0, x2);\n var yMin = Math.min(y0, y2);\n var yMax = Math.max(y0, y2);\n\n if (xMin <= x && x <= xMax && yMin <= y && y <= yMax) {\n var coeff = bezierPtsToQuadCoeff(x0, x1, x2);\n var roots = solveQuadratic(coeff[0], coeff[1], coeff[2], x);\n var validRoots = roots.filter(function (r) {\n return 0 <= r && r <= 1;\n });\n\n if (validRoots.length > 0) {\n return validRoots[0];\n }\n }\n\n return null;\n };\n\n var curveRegions = Object.keys(barrelCurvePts);\n\n for (var i = 0; i < curveRegions.length; i++) {\n var corner = curveRegions[i];\n var cornerPts = barrelCurvePts[corner];\n var t = getCurveT(x, y, cornerPts);\n\n if (t == null) {\n continue;\n }\n\n var y0 = cornerPts[5];\n var y1 = cornerPts[3];\n var y2 = cornerPts[1];\n var bezY = qbezierAt(y0, y1, y2, t);\n\n if (cornerPts.isTop && bezY <= y) {\n return true;\n }\n\n if (cornerPts.isBottom && y <= bezY) {\n return true;\n }\n }\n\n return false;\n }\n };\n };\n\n BRp$2.generateBottomRoundrectangle = function () {\n return this.nodeShapes['bottom-round-rectangle'] = this.nodeShapes['bottomroundrectangle'] = {\n renderer: this,\n name: 'bottom-round-rectangle',\n points: generateUnitNgonPointsFitToSquare(4, 0),\n draw: function draw(context, centerX, centerY, width, height) {\n this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height);\n },\n intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) {\n var topStartX = nodeX - (width / 2 + padding);\n var topStartY = nodeY - (height / 2 + padding);\n var topEndY = topStartY;\n var topEndX = nodeX + (width / 2 + padding);\n var topIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, topStartX, topStartY, topEndX, topEndY, false);\n\n if (topIntersections.length > 0) {\n return topIntersections;\n }\n\n return roundRectangleIntersectLine(x, y, nodeX, nodeY, width, height, padding);\n },\n checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) {\n var cornerRadius = getRoundRectangleRadius(width, height);\n var diam = 2 * cornerRadius; // Check hBox\n\n if (pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - diam, [0, -1], padding)) {\n return true;\n } // Check vBox\n\n\n if (pointInsidePolygon(x, y, this.points, centerX, centerY, width - diam, height, [0, -1], padding)) {\n return true;\n } // check non-rounded top side\n\n\n var outerWidth = width / 2 + 2 * padding;\n var outerHeight = height / 2 + 2 * padding;\n var points = [centerX - outerWidth, centerY - outerHeight, centerX - outerWidth, centerY, centerX + outerWidth, centerY, centerX + outerWidth, centerY - outerHeight];\n\n if (pointInsidePolygonPoints(x, y, points)) {\n return true;\n } // Check bottom right quarter circle\n\n\n if (checkInEllipse(x, y, diam, diam, centerX + width / 2 - cornerRadius, centerY + height / 2 - cornerRadius, padding)) {\n return true;\n } // Check bottom left quarter circle\n\n\n if (checkInEllipse(x, y, diam, diam, centerX - width / 2 + cornerRadius, centerY + height / 2 - cornerRadius, padding)) {\n return true;\n }\n\n return false;\n }\n };\n };\n\n BRp$2.registerNodeShapes = function () {\n var nodeShapes = this.nodeShapes = {};\n var renderer = this;\n this.generateEllipse();\n this.generatePolygon('triangle', generateUnitNgonPointsFitToSquare(3, 0));\n this.generateRoundPolygon('round-triangle', generateUnitNgonPointsFitToSquare(3, 0));\n this.generatePolygon('rectangle', generateUnitNgonPointsFitToSquare(4, 0));\n nodeShapes['square'] = nodeShapes['rectangle'];\n this.generateRoundRectangle();\n this.generateCutRectangle();\n this.generateBarrel();\n this.generateBottomRoundrectangle();\n {\n var diamondPoints = [0, 1, 1, 0, 0, -1, -1, 0];\n this.generatePolygon('diamond', diamondPoints);\n this.generateRoundPolygon('round-diamond', diamondPoints);\n }\n this.generatePolygon('pentagon', generateUnitNgonPointsFitToSquare(5, 0));\n this.generateRoundPolygon('round-pentagon', generateUnitNgonPointsFitToSquare(5, 0));\n this.generatePolygon('hexagon', generateUnitNgonPointsFitToSquare(6, 0));\n this.generateRoundPolygon('round-hexagon', generateUnitNgonPointsFitToSquare(6, 0));\n this.generatePolygon('heptagon', generateUnitNgonPointsFitToSquare(7, 0));\n this.generateRoundPolygon('round-heptagon', generateUnitNgonPointsFitToSquare(7, 0));\n this.generatePolygon('octagon', generateUnitNgonPointsFitToSquare(8, 0));\n this.generateRoundPolygon('round-octagon', generateUnitNgonPointsFitToSquare(8, 0));\n var star5Points = new Array(20);\n {\n var outerPoints = generateUnitNgonPoints(5, 0);\n var innerPoints = generateUnitNgonPoints(5, Math.PI / 5); // Outer radius is 1; inner radius of star is smaller\n\n var innerRadius = 0.5 * (3 - Math.sqrt(5));\n innerRadius *= 1.57;\n\n for (var i = 0; i < innerPoints.length / 2; i++) {\n innerPoints[i * 2] *= innerRadius;\n innerPoints[i * 2 + 1] *= innerRadius;\n }\n\n for (var i = 0; i < 20 / 4; i++) {\n star5Points[i * 4] = outerPoints[i * 2];\n star5Points[i * 4 + 1] = outerPoints[i * 2 + 1];\n star5Points[i * 4 + 2] = innerPoints[i * 2];\n star5Points[i * 4 + 3] = innerPoints[i * 2 + 1];\n }\n }\n star5Points = fitPolygonToSquare(star5Points);\n this.generatePolygon('star', star5Points);\n this.generatePolygon('vee', [-1, -1, 0, -0.333, 1, -1, 0, 1]);\n this.generatePolygon('rhomboid', [-1, -1, 0.333, -1, 1, 1, -0.333, 1]);\n this.generatePolygon('right-rhomboid', [-0.333, -1, 1, -1, 0.333, 1, -1, 1]);\n this.nodeShapes['concavehexagon'] = this.generatePolygon('concave-hexagon', [-1, -0.95, -0.75, 0, -1, 0.95, 1, 0.95, 0.75, 0, 1, -0.95]);\n {\n var tagPoints = [-1, -1, 0.25, -1, 1, 0, 0.25, 1, -1, 1];\n this.generatePolygon('tag', tagPoints);\n this.generateRoundPolygon('round-tag', tagPoints);\n }\n\n nodeShapes.makePolygon = function (points) {\n // use caching on user-specified polygons so they are as fast as native shapes\n var key = points.join('$');\n var name = 'polygon-' + key;\n var shape;\n\n if (shape = this[name]) {\n // got cached shape\n return shape;\n } // create and cache new shape\n\n\n return renderer.generatePolygon(name, points);\n };\n };\n\n var BRp$1 = {};\n\n BRp$1.timeToRender = function () {\n return this.redrawTotalTime / this.redrawCount;\n };\n\n BRp$1.redraw = function (options) {\n options = options || staticEmptyObject();\n var r = this;\n\n if (r.averageRedrawTime === undefined) {\n r.averageRedrawTime = 0;\n }\n\n if (r.lastRedrawTime === undefined) {\n r.lastRedrawTime = 0;\n }\n\n if (r.lastDrawTime === undefined) {\n r.lastDrawTime = 0;\n }\n\n r.requestedFrame = true;\n r.renderOptions = options;\n };\n\n BRp$1.beforeRender = function (fn, priority) {\n // the renderer can't add tick callbacks when destroyed\n if (this.destroyed) {\n return;\n }\n\n if (priority == null) {\n error('Priority is not optional for beforeRender');\n }\n\n var cbs = this.beforeRenderCallbacks;\n cbs.push({\n fn: fn,\n priority: priority\n }); // higher priority callbacks executed first\n\n cbs.sort(function (a, b) {\n return b.priority - a.priority;\n });\n };\n\n var beforeRenderCallbacks = function beforeRenderCallbacks(r, willDraw, startTime) {\n var cbs = r.beforeRenderCallbacks;\n\n for (var i = 0; i < cbs.length; i++) {\n cbs[i].fn(willDraw, startTime);\n }\n };\n\n BRp$1.startRenderLoop = function () {\n var r = this;\n var cy = r.cy;\n\n if (r.renderLoopStarted) {\n return;\n } else {\n r.renderLoopStarted = true;\n }\n\n var renderFn = function renderFn(requestTime) {\n if (r.destroyed) {\n return;\n }\n\n if (cy.batching()) ; else if (r.requestedFrame && !r.skipFrame) {\n beforeRenderCallbacks(r, true, requestTime);\n var startTime = performanceNow();\n r.render(r.renderOptions);\n var endTime = r.lastDrawTime = performanceNow();\n\n if (r.averageRedrawTime === undefined) {\n r.averageRedrawTime = endTime - startTime;\n }\n\n if (r.redrawCount === undefined) {\n r.redrawCount = 0;\n }\n\n r.redrawCount++;\n\n if (r.redrawTotalTime === undefined) {\n r.redrawTotalTime = 0;\n }\n\n var duration = endTime - startTime;\n r.redrawTotalTime += duration;\n r.lastRedrawTime = duration; // use a weighted average with a bias from the previous average so we don't spike so easily\n\n r.averageRedrawTime = r.averageRedrawTime / 2 + duration / 2;\n r.requestedFrame = false;\n } else {\n beforeRenderCallbacks(r, false, requestTime);\n }\n\n r.skipFrame = false;\n requestAnimationFrame(renderFn);\n };\n\n requestAnimationFrame(renderFn);\n };\n\n var BaseRenderer = function BaseRenderer(options) {\n this.init(options);\n };\n\n var BR = BaseRenderer;\n var BRp = BR.prototype;\n BRp.clientFunctions = ['redrawHint', 'render', 'renderTo', 'matchCanvasSize', 'nodeShapeImpl', 'arrowShapeImpl'];\n\n BRp.init = function (options) {\n var r = this;\n r.options = options;\n r.cy = options.cy;\n var ctr = r.container = options.cy.container();\n var containerWindow = r.cy.window(); // prepend a stylesheet in the head such that\n\n if (containerWindow) {\n var document = containerWindow.document;\n var head = document.head;\n var stylesheetId = '__________cytoscape_stylesheet';\n var className = '__________cytoscape_container';\n var stylesheetAlreadyExists = document.getElementById(stylesheetId) != null;\n\n if (ctr.className.indexOf(className) < 0) {\n ctr.className = (ctr.className || '') + ' ' + className;\n }\n\n if (!stylesheetAlreadyExists) {\n var stylesheet = document.createElement('style');\n stylesheet.id = stylesheetId;\n stylesheet.textContent = '.' + className + ' { position: relative; }';\n head.insertBefore(stylesheet, head.children[0]); // first so lowest priority\n }\n\n var computedStyle = containerWindow.getComputedStyle(ctr);\n var position = computedStyle.getPropertyValue('position');\n\n if (position === 'static') {\n warn('A Cytoscape container has style position:static and so can not use UI extensions properly');\n }\n }\n\n r.selection = [undefined, undefined, undefined, undefined, 0]; // Coordinates for selection box, plus enabled flag\n\n r.bezierProjPcts = [0.05, 0.225, 0.4, 0.5, 0.6, 0.775, 0.95]; //--Pointer-related data\n\n r.hoverData = {\n down: null,\n last: null,\n downTime: null,\n triggerMode: null,\n dragging: false,\n initialPan: [null, null],\n capture: false\n };\n r.dragData = {\n possibleDragElements: []\n };\n r.touchData = {\n start: null,\n capture: false,\n // These 3 fields related to tap, taphold events\n startPosition: [null, null, null, null, null, null],\n singleTouchStartTime: null,\n singleTouchMoved: true,\n now: [null, null, null, null, null, null],\n earlier: [null, null, null, null, null, null]\n };\n r.redraws = 0;\n r.showFps = options.showFps;\n r.debug = options.debug;\n r.hideEdgesOnViewport = options.hideEdgesOnViewport;\n r.textureOnViewport = options.textureOnViewport;\n r.wheelSensitivity = options.wheelSensitivity;\n r.motionBlurEnabled = options.motionBlur; // on by default\n\n r.forcedPixelRatio = number$1(options.pixelRatio) ? options.pixelRatio : null;\n r.motionBlur = options.motionBlur; // for initial kick off\n\n r.motionBlurOpacity = options.motionBlurOpacity;\n r.motionBlurTransparency = 1 - r.motionBlurOpacity;\n r.motionBlurPxRatio = 1;\n r.mbPxRBlurry = 1; //0.8;\n\n r.minMbLowQualFrames = 4;\n r.fullQualityMb = false;\n r.clearedForMotionBlur = [];\n r.desktopTapThreshold = options.desktopTapThreshold;\n r.desktopTapThreshold2 = options.desktopTapThreshold * options.desktopTapThreshold;\n r.touchTapThreshold = options.touchTapThreshold;\n r.touchTapThreshold2 = options.touchTapThreshold * options.touchTapThreshold;\n r.tapholdDuration = 500;\n r.bindings = [];\n r.beforeRenderCallbacks = [];\n r.beforeRenderPriorities = {\n // higher priority execs before lower one\n animations: 400,\n eleCalcs: 300,\n eleTxrDeq: 200,\n lyrTxrDeq: 150,\n lyrTxrSkip: 100\n };\n r.registerNodeShapes();\n r.registerArrowShapes();\n r.registerCalculationListeners();\n };\n\n BRp.notify = function (eventName, eles) {\n var r = this;\n var cy = r.cy; // the renderer can't be notified after it's destroyed\n\n if (this.destroyed) {\n return;\n }\n\n if (eventName === 'init') {\n r.load();\n return;\n }\n\n if (eventName === 'destroy') {\n r.destroy();\n return;\n }\n\n if (eventName === 'add' || eventName === 'remove' || eventName === 'move' && cy.hasCompoundNodes() || eventName === 'load' || eventName === 'zorder' || eventName === 'mount') {\n r.invalidateCachedZSortedEles();\n }\n\n if (eventName === 'viewport') {\n r.redrawHint('select', true);\n }\n\n if (eventName === 'load' || eventName === 'resize' || eventName === 'mount') {\n r.invalidateContainerClientCoordsCache();\n r.matchCanvasSize(r.container);\n }\n\n r.redrawHint('eles', true);\n r.redrawHint('drag', true);\n this.startRenderLoop();\n this.redraw();\n };\n\n BRp.destroy = function () {\n var r = this;\n r.destroyed = true;\n r.cy.stopAnimationLoop();\n\n for (var i = 0; i < r.bindings.length; i++) {\n var binding = r.bindings[i];\n var b = binding;\n var tgt = b.target;\n (tgt.off || tgt.removeEventListener).apply(tgt, b.args);\n }\n\n r.bindings = [];\n r.beforeRenderCallbacks = [];\n r.onUpdateEleCalcsFns = [];\n\n if (r.removeObserver) {\n r.removeObserver.disconnect();\n }\n\n if (r.styleObserver) {\n r.styleObserver.disconnect();\n }\n\n if (r.resizeObserver) {\n r.resizeObserver.disconnect();\n }\n\n if (r.labelCalcDiv) {\n try {\n document.body.removeChild(r.labelCalcDiv); // eslint-disable-line no-undef\n } catch (e) {// ie10 issue #1014\n }\n }\n };\n\n BRp.isHeadless = function () {\n return false;\n };\n\n [BRp$f, BRp$5, BRp$4, BRp$3, BRp$2, BRp$1].forEach(function (props) {\n extend(BRp, props);\n });\n\n var fullFpsTime = 1000 / 60; // assume 60 frames per second\n\n var defs = {\n setupDequeueing: function setupDequeueing(opts) {\n return function setupDequeueingImpl() {\n var self = this;\n var r = this.renderer;\n\n if (self.dequeueingSetup) {\n return;\n } else {\n self.dequeueingSetup = true;\n }\n\n var queueRedraw = debounce_1(function () {\n r.redrawHint('eles', true);\n r.redrawHint('drag', true);\n r.redraw();\n }, opts.deqRedrawThreshold);\n\n var dequeue = function dequeue(willDraw, frameStartTime) {\n var startTime = performanceNow();\n var avgRenderTime = r.averageRedrawTime;\n var renderTime = r.lastRedrawTime;\n var deqd = [];\n var extent = r.cy.extent();\n var pixelRatio = r.getPixelRatio(); // if we aren't in a tick that causes a draw, then the rendered style\n // queue won't automatically be flushed before dequeueing starts\n\n if (!willDraw) {\n r.flushRenderedStyleQueue();\n }\n\n while (true) {\n // eslint-disable-line no-constant-condition\n var now = performanceNow();\n var duration = now - startTime;\n var frameDuration = now - frameStartTime;\n\n if (renderTime < fullFpsTime) {\n // if we're rendering faster than the ideal fps, then do dequeueing\n // during all of the remaining frame time\n var timeAvailable = fullFpsTime - (willDraw ? avgRenderTime : 0);\n\n if (frameDuration >= opts.deqFastCost * timeAvailable) {\n break;\n }\n } else {\n if (willDraw) {\n if (duration >= opts.deqCost * renderTime || duration >= opts.deqAvgCost * avgRenderTime) {\n break;\n }\n } else if (frameDuration >= opts.deqNoDrawCost * fullFpsTime) {\n break;\n }\n }\n\n var thisDeqd = opts.deq(self, pixelRatio, extent);\n\n if (thisDeqd.length > 0) {\n for (var i = 0; i < thisDeqd.length; i++) {\n deqd.push(thisDeqd[i]);\n }\n } else {\n break;\n }\n } // callbacks on dequeue\n\n\n if (deqd.length > 0) {\n opts.onDeqd(self, deqd);\n\n if (!willDraw && opts.shouldRedraw(self, deqd, pixelRatio, extent)) {\n queueRedraw();\n }\n }\n };\n\n var priority = opts.priority || noop$1;\n r.beforeRender(dequeue, priority(self));\n };\n }\n };\n\n // Uses keys so elements may share the same cache.\n\n var ElementTextureCacheLookup = /*#__PURE__*/function () {\n function ElementTextureCacheLookup(getKey) {\n var doesEleInvalidateKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : falsify;\n\n _classCallCheck(this, ElementTextureCacheLookup);\n\n this.idsByKey = new Map$2();\n this.keyForId = new Map$2();\n this.cachesByLvl = new Map$2();\n this.lvls = [];\n this.getKey = getKey;\n this.doesEleInvalidateKey = doesEleInvalidateKey;\n }\n\n _createClass(ElementTextureCacheLookup, [{\n key: \"getIdsFor\",\n value: function getIdsFor(key) {\n if (key == null) {\n error(\"Can not get id list for null key\");\n }\n\n var idsByKey = this.idsByKey;\n var ids = this.idsByKey.get(key);\n\n if (!ids) {\n ids = new Set$1();\n idsByKey.set(key, ids);\n }\n\n return ids;\n }\n }, {\n key: \"addIdForKey\",\n value: function addIdForKey(key, id) {\n if (key != null) {\n this.getIdsFor(key).add(id);\n }\n }\n }, {\n key: \"deleteIdForKey\",\n value: function deleteIdForKey(key, id) {\n if (key != null) {\n this.getIdsFor(key)[\"delete\"](id);\n }\n }\n }, {\n key: \"getNumberOfIdsForKey\",\n value: function getNumberOfIdsForKey(key) {\n if (key == null) {\n return 0;\n } else {\n return this.getIdsFor(key).size;\n }\n }\n }, {\n key: \"updateKeyMappingFor\",\n value: function updateKeyMappingFor(ele) {\n var id = ele.id();\n var prevKey = this.keyForId.get(id);\n var currKey = this.getKey(ele);\n this.deleteIdForKey(prevKey, id);\n this.addIdForKey(currKey, id);\n this.keyForId.set(id, currKey);\n }\n }, {\n key: \"deleteKeyMappingFor\",\n value: function deleteKeyMappingFor(ele) {\n var id = ele.id();\n var prevKey = this.keyForId.get(id);\n this.deleteIdForKey(prevKey, id);\n this.keyForId[\"delete\"](id);\n }\n }, {\n key: \"keyHasChangedFor\",\n value: function keyHasChangedFor(ele) {\n var id = ele.id();\n var prevKey = this.keyForId.get(id);\n var newKey = this.getKey(ele);\n return prevKey !== newKey;\n }\n }, {\n key: \"isInvalid\",\n value: function isInvalid(ele) {\n return this.keyHasChangedFor(ele) || this.doesEleInvalidateKey(ele);\n }\n }, {\n key: \"getCachesAt\",\n value: function getCachesAt(lvl) {\n var cachesByLvl = this.cachesByLvl,\n lvls = this.lvls;\n var caches = cachesByLvl.get(lvl);\n\n if (!caches) {\n caches = new Map$2();\n cachesByLvl.set(lvl, caches);\n lvls.push(lvl);\n }\n\n return caches;\n }\n }, {\n key: \"getCache\",\n value: function getCache(key, lvl) {\n return this.getCachesAt(lvl).get(key);\n }\n }, {\n key: \"get\",\n value: function get(ele, lvl) {\n var key = this.getKey(ele);\n var cache = this.getCache(key, lvl); // getting for an element may need to add to the id list b/c eles can share keys\n\n if (cache != null) {\n this.updateKeyMappingFor(ele);\n }\n\n return cache;\n }\n }, {\n key: \"getForCachedKey\",\n value: function getForCachedKey(ele, lvl) {\n var key = this.keyForId.get(ele.id()); // n.b. use cached key, not newly computed key\n\n var cache = this.getCache(key, lvl);\n return cache;\n }\n }, {\n key: \"hasCache\",\n value: function hasCache(key, lvl) {\n return this.getCachesAt(lvl).has(key);\n }\n }, {\n key: \"has\",\n value: function has(ele, lvl) {\n var key = this.getKey(ele);\n return this.hasCache(key, lvl);\n }\n }, {\n key: \"setCache\",\n value: function setCache(key, lvl, cache) {\n cache.key = key;\n this.getCachesAt(lvl).set(key, cache);\n }\n }, {\n key: \"set\",\n value: function set(ele, lvl, cache) {\n var key = this.getKey(ele);\n this.setCache(key, lvl, cache);\n this.updateKeyMappingFor(ele);\n }\n }, {\n key: \"deleteCache\",\n value: function deleteCache(key, lvl) {\n this.getCachesAt(lvl)[\"delete\"](key);\n }\n }, {\n key: \"delete\",\n value: function _delete(ele, lvl) {\n var key = this.getKey(ele);\n this.deleteCache(key, lvl);\n }\n }, {\n key: \"invalidateKey\",\n value: function invalidateKey(key) {\n var _this = this;\n\n this.lvls.forEach(function (lvl) {\n return _this.deleteCache(key, lvl);\n });\n } // returns true if no other eles reference the invalidated cache (n.b. other eles may need the cache with the same key)\n\n }, {\n key: \"invalidate\",\n value: function invalidate(ele) {\n var id = ele.id();\n var key = this.keyForId.get(id); // n.b. use stored key rather than current (potential key)\n\n this.deleteKeyMappingFor(ele);\n var entireKeyInvalidated = this.doesEleInvalidateKey(ele);\n\n if (entireKeyInvalidated) {\n // clear mapping for current key\n this.invalidateKey(key);\n }\n\n return entireKeyInvalidated || this.getNumberOfIdsForKey(key) === 0;\n }\n }]);\n\n return ElementTextureCacheLookup;\n }();\n\n var minTxrH = 25; // the size of the texture cache for small height eles (special case)\n\n var txrStepH = 50; // the min size of the regular cache, and the size it increases with each step up\n\n var minLvl$1 = -4; // when scaling smaller than that we don't need to re-render\n\n var maxLvl$1 = 3; // when larger than this scale just render directly (caching is not helpful)\n\n var maxZoom$1 = 7.99; // beyond this zoom level, layered textures are not used\n\n var eleTxrSpacing = 8; // spacing between elements on textures to avoid blitting overlaps\n\n var defTxrWidth = 1024; // default/minimum texture width\n\n var maxTxrW = 1024; // the maximum width of a texture\n\n var maxTxrH = 1024; // the maximum height of a texture\n\n var minUtility = 0.2; // if usage of texture is less than this, it is retired\n\n var maxFullness = 0.8; // fullness of texture after which queue removal is checked\n\n var maxFullnessChecks = 10; // dequeued after this many checks\n\n var deqCost$1 = 0.15; // % of add'l rendering cost allowed for dequeuing ele caches each frame\n\n var deqAvgCost$1 = 0.1; // % of add'l rendering cost compared to average overall redraw time\n\n var deqNoDrawCost$1 = 0.9; // % of avg frame time that can be used for dequeueing when not drawing\n\n var deqFastCost$1 = 0.9; // % of frame time to be used when >60fps\n\n var deqRedrawThreshold$1 = 100; // time to batch redraws together from dequeueing to allow more dequeueing calcs to happen in the meanwhile\n\n var maxDeqSize$1 = 1; // number of eles to dequeue and render at higher texture in each batch\n\n var getTxrReasons = {\n dequeue: 'dequeue',\n downscale: 'downscale',\n highQuality: 'highQuality'\n };\n var initDefaults = defaults$g({\n getKey: null,\n doesEleInvalidateKey: falsify,\n drawElement: null,\n getBoundingBox: null,\n getRotationPoint: null,\n getRotationOffset: null,\n isVisible: trueify,\n allowEdgeTxrCaching: true,\n allowParentTxrCaching: true\n });\n\n var ElementTextureCache = function ElementTextureCache(renderer, initOptions) {\n var self = this;\n self.renderer = renderer;\n self.onDequeues = [];\n var opts = initDefaults(initOptions);\n extend(self, opts);\n self.lookup = new ElementTextureCacheLookup(opts.getKey, opts.doesEleInvalidateKey);\n self.setupDequeueing();\n };\n\n var ETCp = ElementTextureCache.prototype;\n ETCp.reasons = getTxrReasons; // the list of textures in which new subtextures for elements can be placed\n\n ETCp.getTextureQueue = function (txrH) {\n var self = this;\n self.eleImgCaches = self.eleImgCaches || {};\n return self.eleImgCaches[txrH] = self.eleImgCaches[txrH] || [];\n }; // the list of usused textures which can be recycled (in use in texture queue)\n\n\n ETCp.getRetiredTextureQueue = function (txrH) {\n var self = this;\n var rtxtrQs = self.eleImgCaches.retired = self.eleImgCaches.retired || {};\n var rtxtrQ = rtxtrQs[txrH] = rtxtrQs[txrH] || [];\n return rtxtrQ;\n }; // queue of element draw requests at different scale levels\n\n\n ETCp.getElementQueue = function () {\n var self = this;\n var q = self.eleCacheQueue = self.eleCacheQueue || new heap(function (a, b) {\n return b.reqs - a.reqs;\n });\n return q;\n }; // queue of element draw requests at different scale levels (element id lookup)\n\n\n ETCp.getElementKeyToQueue = function () {\n var self = this;\n var k2q = self.eleKeyToCacheQueue = self.eleKeyToCacheQueue || {};\n return k2q;\n };\n\n ETCp.getElement = function (ele, bb, pxRatio, lvl, reason) {\n var self = this;\n var r = this.renderer;\n var zoom = r.cy.zoom();\n var lookup = this.lookup;\n\n if (!bb || bb.w === 0 || bb.h === 0 || isNaN(bb.w) || isNaN(bb.h) || !ele.visible() || ele.removed()) {\n return null;\n }\n\n if (!self.allowEdgeTxrCaching && ele.isEdge() || !self.allowParentTxrCaching && ele.isParent()) {\n return null;\n }\n\n if (lvl == null) {\n lvl = Math.ceil(log2(zoom * pxRatio));\n }\n\n if (lvl < minLvl$1) {\n lvl = minLvl$1;\n } else if (zoom >= maxZoom$1 || lvl > maxLvl$1) {\n return null;\n }\n\n var scale = Math.pow(2, lvl);\n var eleScaledH = bb.h * scale;\n var eleScaledW = bb.w * scale;\n var scaledLabelShown = r.eleTextBiggerThanMin(ele, scale);\n\n if (!this.isVisible(ele, scaledLabelShown)) {\n return null;\n }\n\n var eleCache = lookup.get(ele, lvl); // if this get was on an unused/invalidated cache, then restore the texture usage metric\n\n if (eleCache && eleCache.invalidated) {\n eleCache.invalidated = false;\n eleCache.texture.invalidatedWidth -= eleCache.width;\n }\n\n if (eleCache) {\n return eleCache;\n }\n\n var txrH; // which texture height this ele belongs to\n\n if (eleScaledH <= minTxrH) {\n txrH = minTxrH;\n } else if (eleScaledH <= txrStepH) {\n txrH = txrStepH;\n } else {\n txrH = Math.ceil(eleScaledH / txrStepH) * txrStepH;\n }\n\n if (eleScaledH > maxTxrH || eleScaledW > maxTxrW) {\n return null; // caching large elements is not efficient\n }\n\n var txrQ = self.getTextureQueue(txrH); // first try the second last one in case it has space at the end\n\n var txr = txrQ[txrQ.length - 2];\n\n var addNewTxr = function addNewTxr() {\n return self.recycleTexture(txrH, eleScaledW) || self.addTexture(txrH, eleScaledW);\n }; // try the last one if there is no second last one\n\n\n if (!txr) {\n txr = txrQ[txrQ.length - 1];\n } // if the last one doesn't exist, we need a first one\n\n\n if (!txr) {\n txr = addNewTxr();\n } // if there's no room in the current texture, we need a new one\n\n\n if (txr.width - txr.usedWidth < eleScaledW) {\n txr = addNewTxr();\n }\n\n var scalableFrom = function scalableFrom(otherCache) {\n return otherCache && otherCache.scaledLabelShown === scaledLabelShown;\n };\n\n var deqing = reason && reason === getTxrReasons.dequeue;\n var highQualityReq = reason && reason === getTxrReasons.highQuality;\n var downscaleReq = reason && reason === getTxrReasons.downscale;\n var higherCache; // the nearest cache with a higher level\n\n for (var l = lvl + 1; l <= maxLvl$1; l++) {\n var c = lookup.get(ele, l);\n\n if (c) {\n higherCache = c;\n break;\n }\n }\n\n var oneUpCache = higherCache && higherCache.level === lvl + 1 ? higherCache : null;\n\n var downscale = function downscale() {\n txr.context.drawImage(oneUpCache.texture.canvas, oneUpCache.x, 0, oneUpCache.width, oneUpCache.height, txr.usedWidth, 0, eleScaledW, eleScaledH);\n }; // reset ele area in texture\n\n\n txr.context.setTransform(1, 0, 0, 1, 0, 0);\n txr.context.clearRect(txr.usedWidth, 0, eleScaledW, txrH);\n\n if (scalableFrom(oneUpCache)) {\n // then we can relatively cheaply rescale the existing image w/o rerendering\n downscale();\n } else if (scalableFrom(higherCache)) {\n // then use the higher cache for now and queue the next level down\n // to cheaply scale towards the smaller level\n if (highQualityReq) {\n for (var _l = higherCache.level; _l > lvl; _l--) {\n oneUpCache = self.getElement(ele, bb, pxRatio, _l, getTxrReasons.downscale);\n }\n\n downscale();\n } else {\n self.queueElement(ele, higherCache.level - 1);\n return higherCache;\n }\n } else {\n var lowerCache; // the nearest cache with a lower level\n\n if (!deqing && !highQualityReq && !downscaleReq) {\n for (var _l2 = lvl - 1; _l2 >= minLvl$1; _l2--) {\n var _c = lookup.get(ele, _l2);\n\n if (_c) {\n lowerCache = _c;\n break;\n }\n }\n }\n\n if (scalableFrom(lowerCache)) {\n // then use the lower quality cache for now and queue the better one for later\n self.queueElement(ele, lvl);\n return lowerCache;\n }\n\n txr.context.translate(txr.usedWidth, 0);\n txr.context.scale(scale, scale);\n this.drawElement(txr.context, ele, bb, scaledLabelShown, false);\n txr.context.scale(1 / scale, 1 / scale);\n txr.context.translate(-txr.usedWidth, 0);\n }\n\n eleCache = {\n x: txr.usedWidth,\n texture: txr,\n level: lvl,\n scale: scale,\n width: eleScaledW,\n height: eleScaledH,\n scaledLabelShown: scaledLabelShown\n };\n txr.usedWidth += Math.ceil(eleScaledW + eleTxrSpacing);\n txr.eleCaches.push(eleCache);\n lookup.set(ele, lvl, eleCache);\n self.checkTextureFullness(txr);\n return eleCache;\n };\n\n ETCp.invalidateElements = function (eles) {\n for (var i = 0; i < eles.length; i++) {\n this.invalidateElement(eles[i]);\n }\n };\n\n ETCp.invalidateElement = function (ele) {\n var self = this;\n var lookup = self.lookup;\n var caches = [];\n var invalid = lookup.isInvalid(ele);\n\n if (!invalid) {\n return; // override the invalidation request if the element key has not changed\n }\n\n for (var lvl = minLvl$1; lvl <= maxLvl$1; lvl++) {\n var cache = lookup.getForCachedKey(ele, lvl);\n\n if (cache) {\n caches.push(cache);\n }\n }\n\n var noOtherElesUseCache = lookup.invalidate(ele);\n\n if (noOtherElesUseCache) {\n for (var i = 0; i < caches.length; i++) {\n var _cache = caches[i];\n var txr = _cache.texture; // remove space from the texture it belongs to\n\n txr.invalidatedWidth += _cache.width; // mark the cache as invalidated\n\n _cache.invalidated = true; // retire the texture if its utility is low\n\n self.checkTextureUtility(txr);\n }\n } // remove from queue since the old req was for the old state\n\n\n self.removeFromQueue(ele);\n };\n\n ETCp.checkTextureUtility = function (txr) {\n // invalidate all entries in the cache if the cache size is small\n if (txr.invalidatedWidth >= minUtility * txr.width) {\n this.retireTexture(txr);\n }\n };\n\n ETCp.checkTextureFullness = function (txr) {\n // if texture has been mostly filled and passed over several times, remove\n // it from the queue so we don't need to waste time looking at it to put new things\n var self = this;\n var txrQ = self.getTextureQueue(txr.height);\n\n if (txr.usedWidth / txr.width > maxFullness && txr.fullnessChecks >= maxFullnessChecks) {\n removeFromArray(txrQ, txr);\n } else {\n txr.fullnessChecks++;\n }\n };\n\n ETCp.retireTexture = function (txr) {\n var self = this;\n var txrH = txr.height;\n var txrQ = self.getTextureQueue(txrH);\n var lookup = this.lookup; // retire the texture from the active / searchable queue:\n\n removeFromArray(txrQ, txr);\n txr.retired = true; // remove the refs from the eles to the caches:\n\n var eleCaches = txr.eleCaches;\n\n for (var i = 0; i < eleCaches.length; i++) {\n var eleCache = eleCaches[i];\n lookup.deleteCache(eleCache.key, eleCache.level);\n }\n\n clearArray(eleCaches); // add the texture to a retired queue so it can be recycled in future:\n\n var rtxtrQ = self.getRetiredTextureQueue(txrH);\n rtxtrQ.push(txr);\n };\n\n ETCp.addTexture = function (txrH, minW) {\n var self = this;\n var txrQ = self.getTextureQueue(txrH);\n var txr = {};\n txrQ.push(txr);\n txr.eleCaches = [];\n txr.height = txrH;\n txr.width = Math.max(defTxrWidth, minW);\n txr.usedWidth = 0;\n txr.invalidatedWidth = 0;\n txr.fullnessChecks = 0;\n txr.canvas = self.renderer.makeOffscreenCanvas(txr.width, txr.height);\n txr.context = txr.canvas.getContext('2d');\n return txr;\n };\n\n ETCp.recycleTexture = function (txrH, minW) {\n var self = this;\n var txrQ = self.getTextureQueue(txrH);\n var rtxtrQ = self.getRetiredTextureQueue(txrH);\n\n for (var i = 0; i < rtxtrQ.length; i++) {\n var txr = rtxtrQ[i];\n\n if (txr.width >= minW) {\n txr.retired = false;\n txr.usedWidth = 0;\n txr.invalidatedWidth = 0;\n txr.fullnessChecks = 0;\n clearArray(txr.eleCaches);\n txr.context.setTransform(1, 0, 0, 1, 0, 0);\n txr.context.clearRect(0, 0, txr.width, txr.height);\n removeFromArray(rtxtrQ, txr);\n txrQ.push(txr);\n return txr;\n }\n }\n };\n\n ETCp.queueElement = function (ele, lvl) {\n var self = this;\n var q = self.getElementQueue();\n var k2q = self.getElementKeyToQueue();\n var key = this.getKey(ele);\n var existingReq = k2q[key];\n\n if (existingReq) {\n // use the max lvl b/c in between lvls are cheap to make\n existingReq.level = Math.max(existingReq.level, lvl);\n existingReq.eles.merge(ele);\n existingReq.reqs++;\n q.updateItem(existingReq);\n } else {\n var req = {\n eles: ele.spawn().merge(ele),\n level: lvl,\n reqs: 1,\n key: key\n };\n q.push(req);\n k2q[key] = req;\n }\n };\n\n ETCp.dequeue = function (pxRatio\n /*, extent*/\n ) {\n var self = this;\n var q = self.getElementQueue();\n var k2q = self.getElementKeyToQueue();\n var dequeued = [];\n var lookup = self.lookup;\n\n for (var i = 0; i < maxDeqSize$1; i++) {\n if (q.size() > 0) {\n var req = q.pop();\n var key = req.key;\n var ele = req.eles[0]; // all eles have the same key\n\n var cacheExists = lookup.hasCache(ele, req.level); // clear out the key to req lookup\n\n k2q[key] = null; // dequeueing isn't necessary with an existing cache\n\n if (cacheExists) {\n continue;\n }\n\n dequeued.push(req);\n var bb = self.getBoundingBox(ele);\n self.getElement(ele, bb, pxRatio, req.level, getTxrReasons.dequeue);\n } else {\n break;\n }\n }\n\n return dequeued;\n };\n\n ETCp.removeFromQueue = function (ele) {\n var self = this;\n var q = self.getElementQueue();\n var k2q = self.getElementKeyToQueue();\n var key = this.getKey(ele);\n var req = k2q[key];\n\n if (req != null) {\n if (req.eles.length === 1) {\n // remove if last ele in the req\n // bring to front of queue\n req.reqs = MAX_INT$1;\n q.updateItem(req);\n q.pop(); // remove from queue\n\n k2q[key] = null; // remove from lookup map\n } else {\n // otherwise just remove ele from req\n req.eles.unmerge(ele);\n }\n }\n };\n\n ETCp.onDequeue = function (fn) {\n this.onDequeues.push(fn);\n };\n\n ETCp.offDequeue = function (fn) {\n removeFromArray(this.onDequeues, fn);\n };\n\n ETCp.setupDequeueing = defs.setupDequeueing({\n deqRedrawThreshold: deqRedrawThreshold$1,\n deqCost: deqCost$1,\n deqAvgCost: deqAvgCost$1,\n deqNoDrawCost: deqNoDrawCost$1,\n deqFastCost: deqFastCost$1,\n deq: function deq(self, pxRatio, extent) {\n return self.dequeue(pxRatio, extent);\n },\n onDeqd: function onDeqd(self, deqd) {\n for (var i = 0; i < self.onDequeues.length; i++) {\n var fn = self.onDequeues[i];\n fn(deqd);\n }\n },\n shouldRedraw: function shouldRedraw(self, deqd, pxRatio, extent) {\n for (var i = 0; i < deqd.length; i++) {\n var eles = deqd[i].eles;\n\n for (var j = 0; j < eles.length; j++) {\n var bb = eles[j].boundingBox();\n\n if (boundingBoxesIntersect(bb, extent)) {\n return true;\n }\n }\n }\n\n return false;\n },\n priority: function priority(self) {\n return self.renderer.beforeRenderPriorities.eleTxrDeq;\n }\n });\n\n var defNumLayers = 1; // default number of layers to use\n\n var minLvl = -4; // when scaling smaller than that we don't need to re-render\n\n var maxLvl = 2; // when larger than this scale just render directly (caching is not helpful)\n\n var maxZoom = 3.99; // beyond this zoom level, layered textures are not used\n\n var deqRedrawThreshold = 50; // time to batch redraws together from dequeueing to allow more dequeueing calcs to happen in the meanwhile\n\n var refineEleDebounceTime = 50; // time to debounce sharper ele texture updates\n\n var deqCost = 0.15; // % of add'l rendering cost allowed for dequeuing ele caches each frame\n\n var deqAvgCost = 0.1; // % of add'l rendering cost compared to average overall redraw time\n\n var deqNoDrawCost = 0.9; // % of avg frame time that can be used for dequeueing when not drawing\n\n var deqFastCost = 0.9; // % of frame time to be used when >60fps\n\n var maxDeqSize = 1; // number of eles to dequeue and render at higher texture in each batch\n\n var invalidThreshold = 250; // time threshold for disabling b/c of invalidations\n\n var maxLayerArea = 4000 * 4000; // layers can't be bigger than this\n\n var useHighQualityEleTxrReqs = true; // whether to use high quality ele txr requests (generally faster and cheaper in the longterm)\n // var log = function(){ console.log.apply( console, arguments ); };\n\n var LayeredTextureCache = function LayeredTextureCache(renderer) {\n var self = this;\n var r = self.renderer = renderer;\n var cy = r.cy;\n self.layersByLevel = {}; // e.g. 2 => [ layer1, layer2, ..., layerN ]\n\n self.firstGet = true;\n self.lastInvalidationTime = performanceNow() - 2 * invalidThreshold;\n self.skipping = false;\n self.eleTxrDeqs = cy.collection();\n self.scheduleElementRefinement = debounce_1(function () {\n self.refineElementTextures(self.eleTxrDeqs);\n self.eleTxrDeqs.unmerge(self.eleTxrDeqs);\n }, refineEleDebounceTime);\n r.beforeRender(function (willDraw, now) {\n if (now - self.lastInvalidationTime <= invalidThreshold) {\n self.skipping = true;\n } else {\n self.skipping = false;\n }\n }, r.beforeRenderPriorities.lyrTxrSkip);\n\n var qSort = function qSort(a, b) {\n return b.reqs - a.reqs;\n };\n\n self.layersQueue = new heap(qSort);\n self.setupDequeueing();\n };\n\n var LTCp = LayeredTextureCache.prototype;\n var layerIdPool = 0;\n var MAX_INT = Math.pow(2, 53) - 1;\n\n LTCp.makeLayer = function (bb, lvl) {\n var scale = Math.pow(2, lvl);\n var w = Math.ceil(bb.w * scale);\n var h = Math.ceil(bb.h * scale);\n var canvas = this.renderer.makeOffscreenCanvas(w, h);\n var layer = {\n id: layerIdPool = ++layerIdPool % MAX_INT,\n bb: bb,\n level: lvl,\n width: w,\n height: h,\n canvas: canvas,\n context: canvas.getContext('2d'),\n eles: [],\n elesQueue: [],\n reqs: 0\n }; // log('make layer %s with w %s and h %s and lvl %s', layer.id, layer.width, layer.height, layer.level);\n\n var cxt = layer.context;\n var dx = -layer.bb.x1;\n var dy = -layer.bb.y1; // do the transform on creation to save cycles (it's the same for all eles)\n\n cxt.scale(scale, scale);\n cxt.translate(dx, dy);\n return layer;\n };\n\n LTCp.getLayers = function (eles, pxRatio, lvl) {\n var self = this;\n var r = self.renderer;\n var cy = r.cy;\n var zoom = cy.zoom();\n var firstGet = self.firstGet;\n self.firstGet = false; // log('--\\nget layers with %s eles', eles.length);\n //log eles.map(function(ele){ return ele.id() }) );\n\n if (lvl == null) {\n lvl = Math.ceil(log2(zoom * pxRatio));\n\n if (lvl < minLvl) {\n lvl = minLvl;\n } else if (zoom >= maxZoom || lvl > maxLvl) {\n return null;\n }\n }\n\n self.validateLayersElesOrdering(lvl, eles);\n var layersByLvl = self.layersByLevel;\n var scale = Math.pow(2, lvl);\n var layers = layersByLvl[lvl] = layersByLvl[lvl] || [];\n var bb;\n var lvlComplete = self.levelIsComplete(lvl, eles);\n var tmpLayers;\n\n var checkTempLevels = function checkTempLevels() {\n var canUseAsTmpLvl = function canUseAsTmpLvl(l) {\n self.validateLayersElesOrdering(l, eles);\n\n if (self.levelIsComplete(l, eles)) {\n tmpLayers = layersByLvl[l];\n return true;\n }\n };\n\n var checkLvls = function checkLvls(dir) {\n if (tmpLayers) {\n return;\n }\n\n for (var l = lvl + dir; minLvl <= l && l <= maxLvl; l += dir) {\n if (canUseAsTmpLvl(l)) {\n break;\n }\n }\n };\n\n checkLvls(+1);\n checkLvls(-1); // remove the invalid layers; they will be replaced as needed later in this function\n\n for (var i = layers.length - 1; i >= 0; i--) {\n var layer = layers[i];\n\n if (layer.invalid) {\n removeFromArray(layers, layer);\n }\n }\n };\n\n if (!lvlComplete) {\n // if the current level is incomplete, then use the closest, best quality layerset temporarily\n // and later queue the current layerset so we can get the proper quality level soon\n checkTempLevels();\n } else {\n // log('level complete, using existing layers\\n--');\n return layers;\n }\n\n var getBb = function getBb() {\n if (!bb) {\n bb = makeBoundingBox();\n\n for (var i = 0; i < eles.length; i++) {\n updateBoundingBox(bb, eles[i].boundingBox());\n }\n }\n\n return bb;\n };\n\n var makeLayer = function makeLayer(opts) {\n opts = opts || {};\n var after = opts.after;\n getBb();\n var area = bb.w * scale * (bb.h * scale);\n\n if (area > maxLayerArea) {\n return null;\n }\n\n var layer = self.makeLayer(bb, lvl);\n\n if (after != null) {\n var index = layers.indexOf(after) + 1;\n layers.splice(index, 0, layer);\n } else if (opts.insert === undefined || opts.insert) {\n // no after specified => first layer made so put at start\n layers.unshift(layer);\n } // if( tmpLayers ){\n //self.queueLayer( layer );\n // }\n\n\n return layer;\n };\n\n if (self.skipping && !firstGet) {\n // log('skip layers');\n return null;\n } // log('do layers');\n\n\n var layer = null;\n var maxElesPerLayer = eles.length / defNumLayers;\n var allowLazyQueueing = !firstGet;\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n var rs = ele._private.rscratch;\n var caches = rs.imgLayerCaches = rs.imgLayerCaches || {}; // log('look at ele', ele.id());\n\n var existingLayer = caches[lvl];\n\n if (existingLayer) {\n // reuse layer for later eles\n // log('reuse layer for', ele.id());\n layer = existingLayer;\n continue;\n }\n\n if (!layer || layer.eles.length >= maxElesPerLayer || !boundingBoxInBoundingBox(layer.bb, ele.boundingBox())) {\n // log('make new layer for ele %s', ele.id());\n layer = makeLayer({\n insert: true,\n after: layer\n }); // if now layer can be built then we can't use layers at this level\n\n if (!layer) {\n return null;\n } // log('new layer with id %s', layer.id);\n\n }\n\n if (tmpLayers || allowLazyQueueing) {\n // log('queue ele %s in layer %s', ele.id(), layer.id);\n self.queueLayer(layer, ele);\n } else {\n // log('draw ele %s in layer %s', ele.id(), layer.id);\n self.drawEleInLayer(layer, ele, lvl, pxRatio);\n }\n\n layer.eles.push(ele);\n caches[lvl] = layer;\n } // log('--');\n\n\n if (tmpLayers) {\n // then we only queued the current layerset and can't draw it yet\n return tmpLayers;\n }\n\n if (allowLazyQueueing) {\n // log('lazy queue level', lvl);\n return null;\n }\n\n return layers;\n }; // a layer may want to use an ele cache of a higher level to avoid blurriness\n // so the layer level might not equal the ele level\n\n\n LTCp.getEleLevelForLayerLevel = function (lvl, pxRatio) {\n return lvl;\n };\n\n LTCp.drawEleInLayer = function (layer, ele, lvl, pxRatio) {\n var self = this;\n var r = this.renderer;\n var context = layer.context;\n var bb = ele.boundingBox();\n\n if (bb.w === 0 || bb.h === 0 || !ele.visible()) {\n return;\n }\n\n lvl = self.getEleLevelForLayerLevel(lvl, pxRatio);\n\n {\n r.setImgSmoothing(context, false);\n }\n\n {\n r.drawCachedElement(context, ele, null, null, lvl, useHighQualityEleTxrReqs);\n }\n\n {\n r.setImgSmoothing(context, true);\n }\n };\n\n LTCp.levelIsComplete = function (lvl, eles) {\n var self = this;\n var layers = self.layersByLevel[lvl];\n\n if (!layers || layers.length === 0) {\n return false;\n }\n\n var numElesInLayers = 0;\n\n for (var i = 0; i < layers.length; i++) {\n var layer = layers[i]; // if there are any eles needed to be drawn yet, the level is not complete\n\n if (layer.reqs > 0) {\n return false;\n } // if the layer is invalid, the level is not complete\n\n\n if (layer.invalid) {\n return false;\n }\n\n numElesInLayers += layer.eles.length;\n } // we should have exactly the number of eles passed in to be complete\n\n\n if (numElesInLayers !== eles.length) {\n return false;\n }\n\n return true;\n };\n\n LTCp.validateLayersElesOrdering = function (lvl, eles) {\n var layers = this.layersByLevel[lvl];\n\n if (!layers) {\n return;\n } // if in a layer the eles are not in the same order, then the layer is invalid\n // (i.e. there is an ele in between the eles in the layer)\n\n\n for (var i = 0; i < layers.length; i++) {\n var layer = layers[i];\n var offset = -1; // find the offset\n\n for (var j = 0; j < eles.length; j++) {\n if (layer.eles[0] === eles[j]) {\n offset = j;\n break;\n }\n }\n\n if (offset < 0) {\n // then the layer has nonexistent elements and is invalid\n this.invalidateLayer(layer);\n continue;\n } // the eles in the layer must be in the same continuous order, else the layer is invalid\n\n\n var o = offset;\n\n for (var j = 0; j < layer.eles.length; j++) {\n if (layer.eles[j] !== eles[o + j]) {\n // log('invalidate based on ordering', layer.id);\n this.invalidateLayer(layer);\n break;\n }\n }\n }\n };\n\n LTCp.updateElementsInLayers = function (eles, update) {\n var self = this;\n var isEles = element(eles[0]); // collect udpated elements (cascaded from the layers) and update each\n // layer itself along the way\n\n for (var i = 0; i < eles.length; i++) {\n var req = isEles ? null : eles[i];\n var ele = isEles ? eles[i] : eles[i].ele;\n var rs = ele._private.rscratch;\n var caches = rs.imgLayerCaches = rs.imgLayerCaches || {};\n\n for (var l = minLvl; l <= maxLvl; l++) {\n var layer = caches[l];\n\n if (!layer) {\n continue;\n } // if update is a request from the ele cache, then it affects only\n // the matching level\n\n\n if (req && self.getEleLevelForLayerLevel(layer.level) !== req.level) {\n continue;\n }\n\n update(layer, ele, req);\n }\n }\n };\n\n LTCp.haveLayers = function () {\n var self = this;\n var haveLayers = false;\n\n for (var l = minLvl; l <= maxLvl; l++) {\n var layers = self.layersByLevel[l];\n\n if (layers && layers.length > 0) {\n haveLayers = true;\n break;\n }\n }\n\n return haveLayers;\n };\n\n LTCp.invalidateElements = function (eles) {\n var self = this;\n\n if (eles.length === 0) {\n return;\n }\n\n self.lastInvalidationTime = performanceNow(); // log('update invalidate layer time from eles');\n\n if (eles.length === 0 || !self.haveLayers()) {\n return;\n }\n\n self.updateElementsInLayers(eles, function invalAssocLayers(layer, ele, req) {\n self.invalidateLayer(layer);\n });\n };\n\n LTCp.invalidateLayer = function (layer) {\n // log('update invalidate layer time');\n this.lastInvalidationTime = performanceNow();\n\n if (layer.invalid) {\n return;\n } // save cycles\n\n\n var lvl = layer.level;\n var eles = layer.eles;\n var layers = this.layersByLevel[lvl]; // log('invalidate layer', layer.id );\n\n removeFromArray(layers, layer); // layer.eles = [];\n\n layer.elesQueue = [];\n layer.invalid = true;\n\n if (layer.replacement) {\n layer.replacement.invalid = true;\n }\n\n for (var i = 0; i < eles.length; i++) {\n var caches = eles[i]._private.rscratch.imgLayerCaches;\n\n if (caches) {\n caches[lvl] = null;\n }\n }\n };\n\n LTCp.refineElementTextures = function (eles) {\n var self = this; // log('refine', eles.length);\n\n self.updateElementsInLayers(eles, function refineEachEle(layer, ele, req) {\n var rLyr = layer.replacement;\n\n if (!rLyr) {\n rLyr = layer.replacement = self.makeLayer(layer.bb, layer.level);\n rLyr.replaces = layer;\n rLyr.eles = layer.eles; // log('make replacement layer %s for %s with level %s', rLyr.id, layer.id, rLyr.level);\n }\n\n if (!rLyr.reqs) {\n for (var i = 0; i < rLyr.eles.length; i++) {\n self.queueLayer(rLyr, rLyr.eles[i]);\n } // log('queue replacement layer refinement', rLyr.id);\n\n }\n });\n };\n\n LTCp.enqueueElementRefinement = function (ele) {\n\n this.eleTxrDeqs.merge(ele);\n this.scheduleElementRefinement();\n };\n\n LTCp.queueLayer = function (layer, ele) {\n var self = this;\n var q = self.layersQueue;\n var elesQ = layer.elesQueue;\n var hasId = elesQ.hasId = elesQ.hasId || {}; // if a layer is going to be replaced, queuing is a waste of time\n\n if (layer.replacement) {\n return;\n }\n\n if (ele) {\n if (hasId[ele.id()]) {\n return;\n }\n\n elesQ.push(ele);\n hasId[ele.id()] = true;\n }\n\n if (layer.reqs) {\n layer.reqs++;\n q.updateItem(layer);\n } else {\n layer.reqs = 1;\n q.push(layer);\n }\n };\n\n LTCp.dequeue = function (pxRatio) {\n var self = this;\n var q = self.layersQueue;\n var deqd = [];\n var eleDeqs = 0;\n\n while (eleDeqs < maxDeqSize) {\n if (q.size() === 0) {\n break;\n }\n\n var layer = q.peek(); // if a layer has been or will be replaced, then don't waste time with it\n\n if (layer.replacement) {\n // log('layer %s in queue skipped b/c it already has a replacement', layer.id);\n q.pop();\n continue;\n } // if this is a replacement layer that has been superceded, then forget it\n\n\n if (layer.replaces && layer !== layer.replaces.replacement) {\n // log('layer is no longer the most uptodate replacement; dequeued', layer.id)\n q.pop();\n continue;\n }\n\n if (layer.invalid) {\n // log('replacement layer %s is invalid; dequeued', layer.id);\n q.pop();\n continue;\n }\n\n var ele = layer.elesQueue.shift();\n\n if (ele) {\n // log('dequeue layer %s', layer.id);\n self.drawEleInLayer(layer, ele, layer.level, pxRatio);\n eleDeqs++;\n }\n\n if (deqd.length === 0) {\n // we need only one entry in deqd to queue redrawing etc\n deqd.push(true);\n } // if the layer has all its eles done, then remove from the queue\n\n\n if (layer.elesQueue.length === 0) {\n q.pop();\n layer.reqs = 0; // log('dequeue of layer %s complete', layer.id);\n // when a replacement layer is dequeued, it replaces the old layer in the level\n\n if (layer.replaces) {\n self.applyLayerReplacement(layer);\n }\n\n self.requestRedraw();\n }\n }\n\n return deqd;\n };\n\n LTCp.applyLayerReplacement = function (layer) {\n var self = this;\n var layersInLevel = self.layersByLevel[layer.level];\n var replaced = layer.replaces;\n var index = layersInLevel.indexOf(replaced); // if the replaced layer is not in the active list for the level, then replacing\n // refs would be a mistake (i.e. overwriting the true active layer)\n\n if (index < 0 || replaced.invalid) {\n // log('replacement layer would have no effect', layer.id);\n return;\n }\n\n layersInLevel[index] = layer; // replace level ref\n // replace refs in eles\n\n for (var i = 0; i < layer.eles.length; i++) {\n var _p = layer.eles[i]._private;\n var cache = _p.imgLayerCaches = _p.imgLayerCaches || {};\n\n if (cache) {\n cache[layer.level] = layer;\n }\n } // log('apply replacement layer %s over %s', layer.id, replaced.id);\n\n\n self.requestRedraw();\n };\n\n LTCp.requestRedraw = debounce_1(function () {\n var r = this.renderer;\n r.redrawHint('eles', true);\n r.redrawHint('drag', true);\n r.redraw();\n }, 100);\n LTCp.setupDequeueing = defs.setupDequeueing({\n deqRedrawThreshold: deqRedrawThreshold,\n deqCost: deqCost,\n deqAvgCost: deqAvgCost,\n deqNoDrawCost: deqNoDrawCost,\n deqFastCost: deqFastCost,\n deq: function deq(self, pxRatio) {\n return self.dequeue(pxRatio);\n },\n onDeqd: noop$1,\n shouldRedraw: trueify,\n priority: function priority(self) {\n return self.renderer.beforeRenderPriorities.lyrTxrDeq;\n }\n });\n\n var CRp$a = {};\n var impl;\n\n function polygon(context, points) {\n for (var i = 0; i < points.length; i++) {\n var pt = points[i];\n context.lineTo(pt.x, pt.y);\n }\n }\n\n function triangleBackcurve(context, points, controlPoint) {\n var firstPt;\n\n for (var i = 0; i < points.length; i++) {\n var pt = points[i];\n\n if (i === 0) {\n firstPt = pt;\n }\n\n context.lineTo(pt.x, pt.y);\n }\n\n context.quadraticCurveTo(controlPoint.x, controlPoint.y, firstPt.x, firstPt.y);\n }\n\n function triangleTee(context, trianglePoints, teePoints) {\n if (context.beginPath) {\n context.beginPath();\n }\n\n var triPts = trianglePoints;\n\n for (var i = 0; i < triPts.length; i++) {\n var pt = triPts[i];\n context.lineTo(pt.x, pt.y);\n }\n\n var teePts = teePoints;\n var firstTeePt = teePoints[0];\n context.moveTo(firstTeePt.x, firstTeePt.y);\n\n for (var i = 1; i < teePts.length; i++) {\n var pt = teePts[i];\n context.lineTo(pt.x, pt.y);\n }\n\n if (context.closePath) {\n context.closePath();\n }\n }\n\n function circleTriangle(context, trianglePoints, rx, ry, r) {\n if (context.beginPath) {\n context.beginPath();\n }\n\n context.arc(rx, ry, r, 0, Math.PI * 2, false);\n var triPts = trianglePoints;\n var firstTrPt = triPts[0];\n context.moveTo(firstTrPt.x, firstTrPt.y);\n\n for (var i = 0; i < triPts.length; i++) {\n var pt = triPts[i];\n context.lineTo(pt.x, pt.y);\n }\n\n if (context.closePath) {\n context.closePath();\n }\n }\n\n function circle(context, rx, ry, r) {\n context.arc(rx, ry, r, 0, Math.PI * 2, false);\n }\n\n CRp$a.arrowShapeImpl = function (name) {\n return (impl || (impl = {\n 'polygon': polygon,\n 'triangle-backcurve': triangleBackcurve,\n 'triangle-tee': triangleTee,\n 'circle-triangle': circleTriangle,\n 'triangle-cross': triangleTee,\n 'circle': circle\n }))[name];\n };\n\n var CRp$9 = {};\n\n CRp$9.drawElement = function (context, ele, shiftToOriginWithBb, showLabel, showOverlay, showOpacity) {\n var r = this;\n\n if (ele.isNode()) {\n r.drawNode(context, ele, shiftToOriginWithBb, showLabel, showOverlay, showOpacity);\n } else {\n r.drawEdge(context, ele, shiftToOriginWithBb, showLabel, showOverlay, showOpacity);\n }\n };\n\n CRp$9.drawElementOverlay = function (context, ele) {\n var r = this;\n\n if (ele.isNode()) {\n r.drawNodeOverlay(context, ele);\n } else {\n r.drawEdgeOverlay(context, ele);\n }\n };\n\n CRp$9.drawElementUnderlay = function (context, ele) {\n var r = this;\n\n if (ele.isNode()) {\n r.drawNodeUnderlay(context, ele);\n } else {\n r.drawEdgeUnderlay(context, ele);\n }\n };\n\n CRp$9.drawCachedElementPortion = function (context, ele, eleTxrCache, pxRatio, lvl, reason, getRotation, getOpacity) {\n var r = this;\n var bb = eleTxrCache.getBoundingBox(ele);\n\n if (bb.w === 0 || bb.h === 0) {\n return;\n } // ignore zero size case\n\n\n var eleCache = eleTxrCache.getElement(ele, bb, pxRatio, lvl, reason);\n\n if (eleCache != null) {\n var opacity = getOpacity(r, ele);\n\n if (opacity === 0) {\n return;\n }\n\n var theta = getRotation(r, ele);\n var x1 = bb.x1,\n y1 = bb.y1,\n w = bb.w,\n h = bb.h;\n var x, y, sx, sy, smooth;\n\n if (theta !== 0) {\n var rotPt = eleTxrCache.getRotationPoint(ele);\n sx = rotPt.x;\n sy = rotPt.y;\n context.translate(sx, sy);\n context.rotate(theta);\n smooth = r.getImgSmoothing(context);\n\n if (!smooth) {\n r.setImgSmoothing(context, true);\n }\n\n var off = eleTxrCache.getRotationOffset(ele);\n x = off.x;\n y = off.y;\n } else {\n x = x1;\n y = y1;\n }\n\n var oldGlobalAlpha;\n\n if (opacity !== 1) {\n oldGlobalAlpha = context.globalAlpha;\n context.globalAlpha = oldGlobalAlpha * opacity;\n }\n\n context.drawImage(eleCache.texture.canvas, eleCache.x, 0, eleCache.width, eleCache.height, x, y, w, h);\n\n if (opacity !== 1) {\n context.globalAlpha = oldGlobalAlpha;\n }\n\n if (theta !== 0) {\n context.rotate(-theta);\n context.translate(-sx, -sy);\n\n if (!smooth) {\n r.setImgSmoothing(context, false);\n }\n }\n } else {\n eleTxrCache.drawElement(context, ele); // direct draw fallback\n }\n };\n\n var getZeroRotation = function getZeroRotation() {\n return 0;\n };\n\n var getLabelRotation = function getLabelRotation(r, ele) {\n return r.getTextAngle(ele, null);\n };\n\n var getSourceLabelRotation = function getSourceLabelRotation(r, ele) {\n return r.getTextAngle(ele, 'source');\n };\n\n var getTargetLabelRotation = function getTargetLabelRotation(r, ele) {\n return r.getTextAngle(ele, 'target');\n };\n\n var getOpacity = function getOpacity(r, ele) {\n return ele.effectiveOpacity();\n };\n\n var getTextOpacity = function getTextOpacity(e, ele) {\n return ele.pstyle('text-opacity').pfValue * ele.effectiveOpacity();\n };\n\n CRp$9.drawCachedElement = function (context, ele, pxRatio, extent, lvl, requestHighQuality) {\n var r = this;\n var _r$data = r.data,\n eleTxrCache = _r$data.eleTxrCache,\n lblTxrCache = _r$data.lblTxrCache,\n slbTxrCache = _r$data.slbTxrCache,\n tlbTxrCache = _r$data.tlbTxrCache;\n var bb = ele.boundingBox();\n var reason = requestHighQuality === true ? eleTxrCache.reasons.highQuality : null;\n\n if (bb.w === 0 || bb.h === 0 || !ele.visible()) {\n return;\n }\n\n if (!extent || boundingBoxesIntersect(bb, extent)) {\n var isEdge = ele.isEdge();\n\n var badLine = ele.element()._private.rscratch.badLine;\n\n r.drawElementUnderlay(context, ele);\n r.drawCachedElementPortion(context, ele, eleTxrCache, pxRatio, lvl, reason, getZeroRotation, getOpacity);\n\n if (!isEdge || !badLine) {\n r.drawCachedElementPortion(context, ele, lblTxrCache, pxRatio, lvl, reason, getLabelRotation, getTextOpacity);\n }\n\n if (isEdge && !badLine) {\n r.drawCachedElementPortion(context, ele, slbTxrCache, pxRatio, lvl, reason, getSourceLabelRotation, getTextOpacity);\n r.drawCachedElementPortion(context, ele, tlbTxrCache, pxRatio, lvl, reason, getTargetLabelRotation, getTextOpacity);\n }\n\n r.drawElementOverlay(context, ele);\n }\n };\n\n CRp$9.drawElements = function (context, eles) {\n var r = this;\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n r.drawElement(context, ele);\n }\n };\n\n CRp$9.drawCachedElements = function (context, eles, pxRatio, extent) {\n var r = this;\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n r.drawCachedElement(context, ele, pxRatio, extent);\n }\n };\n\n CRp$9.drawCachedNodes = function (context, eles, pxRatio, extent) {\n var r = this;\n\n for (var i = 0; i < eles.length; i++) {\n var ele = eles[i];\n\n if (!ele.isNode()) {\n continue;\n }\n\n r.drawCachedElement(context, ele, pxRatio, extent);\n }\n };\n\n CRp$9.drawLayeredElements = function (context, eles, pxRatio, extent) {\n var r = this;\n var layers = r.data.lyrTxrCache.getLayers(eles, pxRatio);\n\n if (layers) {\n for (var i = 0; i < layers.length; i++) {\n var layer = layers[i];\n var bb = layer.bb;\n\n if (bb.w === 0 || bb.h === 0) {\n continue;\n }\n\n context.drawImage(layer.canvas, bb.x1, bb.y1, bb.w, bb.h);\n }\n } else {\n // fall back on plain caching if no layers\n r.drawCachedElements(context, eles, pxRatio, extent);\n }\n };\n\n /* global Path2D */\n var CRp$8 = {};\n\n CRp$8.drawEdge = function (context, edge, shiftToOriginWithBb) {\n var drawLabel = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;\n var shouldDrawOverlay = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;\n var shouldDrawOpacity = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true;\n var r = this;\n var rs = edge._private.rscratch;\n\n if (shouldDrawOpacity && !edge.visible()) {\n return;\n } // if bezier ctrl pts can not be calculated, then die\n\n\n if (rs.badLine || rs.allpts == null || isNaN(rs.allpts[0])) {\n // isNaN in case edge is impossible and browser bugs (e.g. safari)\n return;\n }\n\n var bb;\n\n if (shiftToOriginWithBb) {\n bb = shiftToOriginWithBb;\n context.translate(-bb.x1, -bb.y1);\n }\n\n var opacity = shouldDrawOpacity ? edge.pstyle('opacity').value : 1;\n var lineOpacity = shouldDrawOpacity ? edge.pstyle('line-opacity').value : 1;\n var curveStyle = edge.pstyle('curve-style').value;\n var lineStyle = edge.pstyle('line-style').value;\n var edgeWidth = edge.pstyle('width').pfValue;\n var lineCap = edge.pstyle('line-cap').value;\n var effectiveLineOpacity = opacity * lineOpacity; // separate arrow opacity would require arrow-opacity property\n\n var effectiveArrowOpacity = opacity * lineOpacity;\n\n var drawLine = function drawLine() {\n var strokeOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : effectiveLineOpacity;\n\n if (curveStyle === 'straight-triangle') {\n r.eleStrokeStyle(context, edge, strokeOpacity);\n r.drawEdgeTrianglePath(edge, context, rs.allpts);\n } else {\n context.lineWidth = edgeWidth;\n context.lineCap = lineCap;\n r.eleStrokeStyle(context, edge, strokeOpacity);\n r.drawEdgePath(edge, context, rs.allpts, lineStyle);\n context.lineCap = 'butt'; // reset for other drawing functions\n }\n };\n\n var drawOverlay = function drawOverlay() {\n if (!shouldDrawOverlay) {\n return;\n }\n\n r.drawEdgeOverlay(context, edge);\n };\n\n var drawUnderlay = function drawUnderlay() {\n if (!shouldDrawOverlay) {\n return;\n }\n\n r.drawEdgeUnderlay(context, edge);\n };\n\n var drawArrows = function drawArrows() {\n var arrowOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : effectiveArrowOpacity;\n r.drawArrowheads(context, edge, arrowOpacity);\n };\n\n var drawText = function drawText() {\n r.drawElementText(context, edge, null, drawLabel);\n };\n\n context.lineJoin = 'round';\n var ghost = edge.pstyle('ghost').value === 'yes';\n\n if (ghost) {\n var gx = edge.pstyle('ghost-offset-x').pfValue;\n var gy = edge.pstyle('ghost-offset-y').pfValue;\n var ghostOpacity = edge.pstyle('ghost-opacity').value;\n var effectiveGhostOpacity = effectiveLineOpacity * ghostOpacity;\n context.translate(gx, gy);\n drawLine(effectiveGhostOpacity);\n drawArrows(effectiveGhostOpacity);\n context.translate(-gx, -gy);\n }\n\n drawUnderlay();\n drawLine();\n drawArrows();\n drawOverlay();\n drawText();\n\n if (shiftToOriginWithBb) {\n context.translate(bb.x1, bb.y1);\n }\n };\n\n var drawEdgeOverlayUnderlay = function drawEdgeOverlayUnderlay(overlayOrUnderlay) {\n if (!['overlay', 'underlay'].includes(overlayOrUnderlay)) {\n throw new Error('Invalid state');\n }\n\n return function (context, edge) {\n if (!edge.visible()) {\n return;\n }\n\n var opacity = edge.pstyle(\"\".concat(overlayOrUnderlay, \"-opacity\")).value;\n\n if (opacity === 0) {\n return;\n }\n\n var r = this;\n var usePaths = r.usePaths();\n var rs = edge._private.rscratch;\n var padding = edge.pstyle(\"\".concat(overlayOrUnderlay, \"-padding\")).pfValue;\n var width = 2 * padding;\n var color = edge.pstyle(\"\".concat(overlayOrUnderlay, \"-color\")).value;\n context.lineWidth = width;\n\n if (rs.edgeType === 'self' && !usePaths) {\n context.lineCap = 'butt';\n } else {\n context.lineCap = 'round';\n }\n\n r.colorStrokeStyle(context, color[0], color[1], color[2], opacity);\n r.drawEdgePath(edge, context, rs.allpts, 'solid');\n };\n };\n\n CRp$8.drawEdgeOverlay = drawEdgeOverlayUnderlay('overlay');\n CRp$8.drawEdgeUnderlay = drawEdgeOverlayUnderlay('underlay');\n\n CRp$8.drawEdgePath = function (edge, context, pts, type) {\n var rs = edge._private.rscratch;\n var canvasCxt = context;\n var path;\n var pathCacheHit = false;\n var usePaths = this.usePaths();\n var lineDashPattern = edge.pstyle('line-dash-pattern').pfValue;\n var lineDashOffset = edge.pstyle('line-dash-offset').pfValue;\n\n if (usePaths) {\n var pathCacheKey = pts.join('$');\n var keyMatches = rs.pathCacheKey && rs.pathCacheKey === pathCacheKey;\n\n if (keyMatches) {\n path = context = rs.pathCache;\n pathCacheHit = true;\n } else {\n path = context = new Path2D();\n rs.pathCacheKey = pathCacheKey;\n rs.pathCache = path;\n }\n }\n\n if (canvasCxt.setLineDash) {\n // for very outofdate browsers\n switch (type) {\n case 'dotted':\n canvasCxt.setLineDash([1, 1]);\n break;\n\n case 'dashed':\n canvasCxt.setLineDash(lineDashPattern);\n canvasCxt.lineDashOffset = lineDashOffset;\n break;\n\n case 'solid':\n canvasCxt.setLineDash([]);\n break;\n }\n }\n\n if (!pathCacheHit && !rs.badLine) {\n if (context.beginPath) {\n context.beginPath();\n }\n\n context.moveTo(pts[0], pts[1]);\n\n switch (rs.edgeType) {\n case 'bezier':\n case 'self':\n case 'compound':\n case 'multibezier':\n for (var i = 2; i + 3 < pts.length; i += 4) {\n context.quadraticCurveTo(pts[i], pts[i + 1], pts[i + 2], pts[i + 3]);\n }\n\n break;\n\n case 'straight':\n case 'segments':\n case 'haystack':\n for (var _i = 2; _i + 1 < pts.length; _i += 2) {\n context.lineTo(pts[_i], pts[_i + 1]);\n }\n\n break;\n }\n }\n\n context = canvasCxt;\n\n if (usePaths) {\n context.stroke(path);\n } else {\n context.stroke();\n } // reset any line dashes\n\n\n if (context.setLineDash) {\n // for very outofdate browsers\n context.setLineDash([]);\n }\n };\n\n CRp$8.drawEdgeTrianglePath = function (edge, context, pts) {\n // use line stroke style for triangle fill style\n context.fillStyle = context.strokeStyle;\n var edgeWidth = edge.pstyle('width').pfValue;\n\n for (var i = 0; i + 1 < pts.length; i += 2) {\n var vector = [pts[i + 2] - pts[i], pts[i + 3] - pts[i + 1]];\n var length = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]);\n var normal = [vector[1] / length, -vector[0] / length];\n var triangleHead = [normal[0] * edgeWidth / 2, normal[1] * edgeWidth / 2];\n context.beginPath();\n context.moveTo(pts[i] - triangleHead[0], pts[i + 1] - triangleHead[1]);\n context.lineTo(pts[i] + triangleHead[0], pts[i + 1] + triangleHead[1]);\n context.lineTo(pts[i + 2], pts[i + 3]);\n context.closePath();\n context.fill();\n }\n };\n\n CRp$8.drawArrowheads = function (context, edge, opacity) {\n var rs = edge._private.rscratch;\n var isHaystack = rs.edgeType === 'haystack';\n\n if (!isHaystack) {\n this.drawArrowhead(context, edge, 'source', rs.arrowStartX, rs.arrowStartY, rs.srcArrowAngle, opacity);\n }\n\n this.drawArrowhead(context, edge, 'mid-target', rs.midX, rs.midY, rs.midtgtArrowAngle, opacity);\n this.drawArrowhead(context, edge, 'mid-source', rs.midX, rs.midY, rs.midsrcArrowAngle, opacity);\n\n if (!isHaystack) {\n this.drawArrowhead(context, edge, 'target', rs.arrowEndX, rs.arrowEndY, rs.tgtArrowAngle, opacity);\n }\n };\n\n CRp$8.drawArrowhead = function (context, edge, prefix, x, y, angle, opacity) {\n if (isNaN(x) || x == null || isNaN(y) || y == null || isNaN(angle) || angle == null) {\n return;\n }\n\n var self = this;\n var arrowShape = edge.pstyle(prefix + '-arrow-shape').value;\n\n if (arrowShape === 'none') {\n return;\n }\n\n var arrowClearFill = edge.pstyle(prefix + '-arrow-fill').value === 'hollow' ? 'both' : 'filled';\n var arrowFill = edge.pstyle(prefix + '-arrow-fill').value;\n var edgeWidth = edge.pstyle('width').pfValue;\n var edgeOpacity = edge.pstyle('opacity').value;\n\n if (opacity === undefined) {\n opacity = edgeOpacity;\n }\n\n var gco = context.globalCompositeOperation;\n\n if (opacity !== 1 || arrowFill === 'hollow') {\n // then extra clear is needed\n context.globalCompositeOperation = 'destination-out';\n self.colorFillStyle(context, 255, 255, 255, 1);\n self.colorStrokeStyle(context, 255, 255, 255, 1);\n self.drawArrowShape(edge, context, arrowClearFill, edgeWidth, arrowShape, x, y, angle);\n context.globalCompositeOperation = gco;\n } // otherwise, the opaque arrow clears it for free :)\n\n\n var color = edge.pstyle(prefix + '-arrow-color').value;\n self.colorFillStyle(context, color[0], color[1], color[2], opacity);\n self.colorStrokeStyle(context, color[0], color[1], color[2], opacity);\n self.drawArrowShape(edge, context, arrowFill, edgeWidth, arrowShape, x, y, angle);\n };\n\n CRp$8.drawArrowShape = function (edge, context, fill, edgeWidth, shape, x, y, angle) {\n var r = this;\n var usePaths = this.usePaths() && shape !== 'triangle-cross';\n var pathCacheHit = false;\n var path;\n var canvasContext = context;\n var translation = {\n x: x,\n y: y\n };\n var scale = edge.pstyle('arrow-scale').value;\n var size = this.getArrowWidth(edgeWidth, scale);\n var shapeImpl = r.arrowShapes[shape];\n\n if (usePaths) {\n var cache = r.arrowPathCache = r.arrowPathCache || [];\n var key = hashString(shape);\n var cachedPath = cache[key];\n\n if (cachedPath != null) {\n path = context = cachedPath;\n pathCacheHit = true;\n } else {\n path = context = new Path2D();\n cache[key] = path;\n }\n }\n\n if (!pathCacheHit) {\n if (context.beginPath) {\n context.beginPath();\n }\n\n if (usePaths) {\n // store in the path cache with values easily manipulated later\n shapeImpl.draw(context, 1, 0, {\n x: 0,\n y: 0\n }, 1);\n } else {\n shapeImpl.draw(context, size, angle, translation, edgeWidth);\n }\n\n if (context.closePath) {\n context.closePath();\n }\n }\n\n context = canvasContext;\n\n if (usePaths) {\n // set transform to arrow position/orientation\n context.translate(x, y);\n context.rotate(angle);\n context.scale(size, size);\n }\n\n if (fill === 'filled' || fill === 'both') {\n if (usePaths) {\n context.fill(path);\n } else {\n context.fill();\n }\n }\n\n if (fill === 'hollow' || fill === 'both') {\n context.lineWidth = (shapeImpl.matchEdgeWidth ? edgeWidth : 1) / (usePaths ? size : 1);\n context.lineJoin = 'miter';\n\n if (usePaths) {\n context.stroke(path);\n } else {\n context.stroke();\n }\n }\n\n if (usePaths) {\n // reset transform by applying inverse\n context.scale(1 / size, 1 / size);\n context.rotate(-angle);\n context.translate(-x, -y);\n }\n };\n\n var CRp$7 = {};\n\n CRp$7.safeDrawImage = function (context, img, ix, iy, iw, ih, x, y, w, h) {\n // detect problematic cases for old browsers with bad images (cheaper than try-catch)\n if (iw <= 0 || ih <= 0 || w <= 0 || h <= 0) {\n return;\n }\n\n try {\n context.drawImage(img, ix, iy, iw, ih, x, y, w, h);\n } catch (e) {\n warn(e);\n }\n };\n\n CRp$7.drawInscribedImage = function (context, img, node, index, nodeOpacity) {\n var r = this;\n var pos = node.position();\n var nodeX = pos.x;\n var nodeY = pos.y;\n var styleObj = node.cy().style();\n var getIndexedStyle = styleObj.getIndexedStyle.bind(styleObj);\n var fit = getIndexedStyle(node, 'background-fit', 'value', index);\n var repeat = getIndexedStyle(node, 'background-repeat', 'value', index);\n var nodeW = node.width();\n var nodeH = node.height();\n var paddingX2 = node.padding() * 2;\n var nodeTW = nodeW + (getIndexedStyle(node, 'background-width-relative-to', 'value', index) === 'inner' ? 0 : paddingX2);\n var nodeTH = nodeH + (getIndexedStyle(node, 'background-height-relative-to', 'value', index) === 'inner' ? 0 : paddingX2);\n var rs = node._private.rscratch;\n var clip = getIndexedStyle(node, 'background-clip', 'value', index);\n var shouldClip = clip === 'node';\n var imgOpacity = getIndexedStyle(node, 'background-image-opacity', 'value', index) * nodeOpacity;\n var smooth = getIndexedStyle(node, 'background-image-smoothing', 'value', index);\n var imgW = img.width || img.cachedW;\n var imgH = img.height || img.cachedH; // workaround for broken browsers like ie\n\n if (null == imgW || null == imgH) {\n document.body.appendChild(img); // eslint-disable-line no-undef\n\n imgW = img.cachedW = img.width || img.offsetWidth;\n imgH = img.cachedH = img.height || img.offsetHeight;\n document.body.removeChild(img); // eslint-disable-line no-undef\n }\n\n var w = imgW;\n var h = imgH;\n\n if (getIndexedStyle(node, 'background-width', 'value', index) !== 'auto') {\n if (getIndexedStyle(node, 'background-width', 'units', index) === '%') {\n w = getIndexedStyle(node, 'background-width', 'pfValue', index) * nodeTW;\n } else {\n w = getIndexedStyle(node, 'background-width', 'pfValue', index);\n }\n }\n\n if (getIndexedStyle(node, 'background-height', 'value', index) !== 'auto') {\n if (getIndexedStyle(node, 'background-height', 'units', index) === '%') {\n h = getIndexedStyle(node, 'background-height', 'pfValue', index) * nodeTH;\n } else {\n h = getIndexedStyle(node, 'background-height', 'pfValue', index);\n }\n }\n\n if (w === 0 || h === 0) {\n return; // no point in drawing empty image (and chrome is broken in this case)\n }\n\n if (fit === 'contain') {\n var scale = Math.min(nodeTW / w, nodeTH / h);\n w *= scale;\n h *= scale;\n } else if (fit === 'cover') {\n var scale = Math.max(nodeTW / w, nodeTH / h);\n w *= scale;\n h *= scale;\n }\n\n var x = nodeX - nodeTW / 2; // left\n\n var posXUnits = getIndexedStyle(node, 'background-position-x', 'units', index);\n var posXPfVal = getIndexedStyle(node, 'background-position-x', 'pfValue', index);\n\n if (posXUnits === '%') {\n x += (nodeTW - w) * posXPfVal;\n } else {\n x += posXPfVal;\n }\n\n var offXUnits = getIndexedStyle(node, 'background-offset-x', 'units', index);\n var offXPfVal = getIndexedStyle(node, 'background-offset-x', 'pfValue', index);\n\n if (offXUnits === '%') {\n x += (nodeTW - w) * offXPfVal;\n } else {\n x += offXPfVal;\n }\n\n var y = nodeY - nodeTH / 2; // top\n\n var posYUnits = getIndexedStyle(node, 'background-position-y', 'units', index);\n var posYPfVal = getIndexedStyle(node, 'background-position-y', 'pfValue', index);\n\n if (posYUnits === '%') {\n y += (nodeTH - h) * posYPfVal;\n } else {\n y += posYPfVal;\n }\n\n var offYUnits = getIndexedStyle(node, 'background-offset-y', 'units', index);\n var offYPfVal = getIndexedStyle(node, 'background-offset-y', 'pfValue', index);\n\n if (offYUnits === '%') {\n y += (nodeTH - h) * offYPfVal;\n } else {\n y += offYPfVal;\n }\n\n if (rs.pathCache) {\n x -= nodeX;\n y -= nodeY;\n nodeX = 0;\n nodeY = 0;\n }\n\n var gAlpha = context.globalAlpha;\n context.globalAlpha = imgOpacity;\n var smoothingEnabled = r.getImgSmoothing(context);\n var isSmoothingSwitched = false;\n\n if (smooth === 'no' && smoothingEnabled) {\n r.setImgSmoothing(context, false);\n isSmoothingSwitched = true;\n } else if (smooth === 'yes' && !smoothingEnabled) {\n r.setImgSmoothing(context, true);\n isSmoothingSwitched = true;\n }\n\n if (repeat === 'no-repeat') {\n if (shouldClip) {\n context.save();\n\n if (rs.pathCache) {\n context.clip(rs.pathCache);\n } else {\n r.nodeShapes[r.getNodeShape(node)].draw(context, nodeX, nodeY, nodeTW, nodeTH);\n context.clip();\n }\n }\n\n r.safeDrawImage(context, img, 0, 0, imgW, imgH, x, y, w, h);\n\n if (shouldClip) {\n context.restore();\n }\n } else {\n var pattern = context.createPattern(img, repeat);\n context.fillStyle = pattern;\n r.nodeShapes[r.getNodeShape(node)].draw(context, nodeX, nodeY, nodeTW, nodeTH);\n context.translate(x, y);\n context.fill();\n context.translate(-x, -y);\n }\n\n context.globalAlpha = gAlpha;\n\n if (isSmoothingSwitched) {\n r.setImgSmoothing(context, smoothingEnabled);\n }\n };\n\n var CRp$6 = {};\n\n CRp$6.eleTextBiggerThanMin = function (ele, scale) {\n if (!scale) {\n var zoom = ele.cy().zoom();\n var pxRatio = this.getPixelRatio();\n var lvl = Math.ceil(log2(zoom * pxRatio)); // the effective texture level\n\n scale = Math.pow(2, lvl);\n }\n\n var computedSize = ele.pstyle('font-size').pfValue * scale;\n var minSize = ele.pstyle('min-zoomed-font-size').pfValue;\n\n if (computedSize < minSize) {\n return false;\n }\n\n return true;\n };\n\n CRp$6.drawElementText = function (context, ele, shiftToOriginWithBb, force, prefix) {\n var useEleOpacity = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true;\n var r = this;\n\n if (force == null) {\n if (useEleOpacity && !r.eleTextBiggerThanMin(ele)) {\n return;\n }\n } else if (force === false) {\n return;\n }\n\n if (ele.isNode()) {\n var label = ele.pstyle('label');\n\n if (!label || !label.value) {\n return;\n }\n\n var justification = r.getLabelJustification(ele);\n context.textAlign = justification;\n context.textBaseline = 'bottom';\n } else {\n var badLine = ele.element()._private.rscratch.badLine;\n\n var _label = ele.pstyle('label');\n\n var srcLabel = ele.pstyle('source-label');\n var tgtLabel = ele.pstyle('target-label');\n\n if (badLine || (!_label || !_label.value) && (!srcLabel || !srcLabel.value) && (!tgtLabel || !tgtLabel.value)) {\n return;\n }\n\n context.textAlign = 'center';\n context.textBaseline = 'bottom';\n }\n\n var applyRotation = !shiftToOriginWithBb;\n var bb;\n\n if (shiftToOriginWithBb) {\n bb = shiftToOriginWithBb;\n context.translate(-bb.x1, -bb.y1);\n }\n\n if (prefix == null) {\n r.drawText(context, ele, null, applyRotation, useEleOpacity);\n\n if (ele.isEdge()) {\n r.drawText(context, ele, 'source', applyRotation, useEleOpacity);\n r.drawText(context, ele, 'target', applyRotation, useEleOpacity);\n }\n } else {\n r.drawText(context, ele, prefix, applyRotation, useEleOpacity);\n }\n\n if (shiftToOriginWithBb) {\n context.translate(bb.x1, bb.y1);\n }\n };\n\n CRp$6.getFontCache = function (context) {\n var cache;\n this.fontCaches = this.fontCaches || [];\n\n for (var i = 0; i < this.fontCaches.length; i++) {\n cache = this.fontCaches[i];\n\n if (cache.context === context) {\n return cache;\n }\n }\n\n cache = {\n context: context\n };\n this.fontCaches.push(cache);\n return cache;\n }; // set up canvas context with font\n // returns transformed text string\n\n\n CRp$6.setupTextStyle = function (context, ele) {\n var useEleOpacity = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n // Font style\n var labelStyle = ele.pstyle('font-style').strValue;\n var labelSize = ele.pstyle('font-size').pfValue + 'px';\n var labelFamily = ele.pstyle('font-family').strValue;\n var labelWeight = ele.pstyle('font-weight').strValue;\n var opacity = useEleOpacity ? ele.effectiveOpacity() * ele.pstyle('text-opacity').value : 1;\n var outlineOpacity = ele.pstyle('text-outline-opacity').value * opacity;\n var color = ele.pstyle('color').value;\n var outlineColor = ele.pstyle('text-outline-color').value;\n context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily;\n context.lineJoin = 'round'; // so text outlines aren't jagged\n\n this.colorFillStyle(context, color[0], color[1], color[2], opacity);\n this.colorStrokeStyle(context, outlineColor[0], outlineColor[1], outlineColor[2], outlineOpacity);\n }; // TODO ensure re-used\n\n\n function roundRect(ctx, x, y, width, height) {\n var radius = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 5;\n ctx.beginPath();\n ctx.moveTo(x + radius, y);\n ctx.lineTo(x + width - radius, y);\n ctx.quadraticCurveTo(x + width, y, x + width, y + radius);\n ctx.lineTo(x + width, y + height - radius);\n ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);\n ctx.lineTo(x + radius, y + height);\n ctx.quadraticCurveTo(x, y + height, x, y + height - radius);\n ctx.lineTo(x, y + radius);\n ctx.quadraticCurveTo(x, y, x + radius, y);\n ctx.closePath();\n ctx.fill();\n }\n\n CRp$6.getTextAngle = function (ele, prefix) {\n var theta;\n var _p = ele._private;\n var rscratch = _p.rscratch;\n var pdash = prefix ? prefix + '-' : '';\n var rotation = ele.pstyle(pdash + 'text-rotation');\n var textAngle = getPrefixedProperty(rscratch, 'labelAngle', prefix);\n\n if (rotation.strValue === 'autorotate') {\n theta = ele.isEdge() ? textAngle : 0;\n } else if (rotation.strValue === 'none') {\n theta = 0;\n } else {\n theta = rotation.pfValue;\n }\n\n return theta;\n };\n\n CRp$6.drawText = function (context, ele, prefix) {\n var applyRotation = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;\n var useEleOpacity = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;\n var _p = ele._private;\n var rscratch = _p.rscratch;\n var parentOpacity = useEleOpacity ? ele.effectiveOpacity() : 1;\n\n if (useEleOpacity && (parentOpacity === 0 || ele.pstyle('text-opacity').value === 0)) {\n return;\n } // use 'main' as an alias for the main label (i.e. null prefix)\n\n\n if (prefix === 'main') {\n prefix = null;\n }\n\n var textX = getPrefixedProperty(rscratch, 'labelX', prefix);\n var textY = getPrefixedProperty(rscratch, 'labelY', prefix);\n var orgTextX, orgTextY; // used for rotation\n\n var text = this.getLabelText(ele, prefix);\n\n if (text != null && text !== '' && !isNaN(textX) && !isNaN(textY)) {\n this.setupTextStyle(context, ele, useEleOpacity);\n var pdash = prefix ? prefix + '-' : '';\n var textW = getPrefixedProperty(rscratch, 'labelWidth', prefix);\n var textH = getPrefixedProperty(rscratch, 'labelHeight', prefix);\n var marginX = ele.pstyle(pdash + 'text-margin-x').pfValue;\n var marginY = ele.pstyle(pdash + 'text-margin-y').pfValue;\n var isEdge = ele.isEdge();\n var halign = ele.pstyle('text-halign').value;\n var valign = ele.pstyle('text-valign').value;\n\n if (isEdge) {\n halign = 'center';\n valign = 'center';\n }\n\n textX += marginX;\n textY += marginY;\n var theta;\n\n if (!applyRotation) {\n theta = 0;\n } else {\n theta = this.getTextAngle(ele, prefix);\n }\n\n if (theta !== 0) {\n orgTextX = textX;\n orgTextY = textY;\n context.translate(orgTextX, orgTextY);\n context.rotate(theta);\n textX = 0;\n textY = 0;\n }\n\n switch (valign) {\n case 'top':\n break;\n\n case 'center':\n textY += textH / 2;\n break;\n\n case 'bottom':\n textY += textH;\n break;\n }\n\n var backgroundOpacity = ele.pstyle('text-background-opacity').value;\n var borderOpacity = ele.pstyle('text-border-opacity').value;\n var textBorderWidth = ele.pstyle('text-border-width').pfValue;\n var backgroundPadding = ele.pstyle('text-background-padding').pfValue;\n\n if (backgroundOpacity > 0 || textBorderWidth > 0 && borderOpacity > 0) {\n var bgX = textX - backgroundPadding;\n\n switch (halign) {\n case 'left':\n bgX -= textW;\n break;\n\n case 'center':\n bgX -= textW / 2;\n break;\n }\n\n var bgY = textY - textH - backgroundPadding;\n var bgW = textW + 2 * backgroundPadding;\n var bgH = textH + 2 * backgroundPadding;\n\n if (backgroundOpacity > 0) {\n var textFill = context.fillStyle;\n var textBackgroundColor = ele.pstyle('text-background-color').value;\n context.fillStyle = 'rgba(' + textBackgroundColor[0] + ',' + textBackgroundColor[1] + ',' + textBackgroundColor[2] + ',' + backgroundOpacity * parentOpacity + ')';\n var styleShape = ele.pstyle('text-background-shape').strValue;\n\n if (styleShape.indexOf('round') === 0) {\n roundRect(context, bgX, bgY, bgW, bgH, 2);\n } else {\n context.fillRect(bgX, bgY, bgW, bgH);\n }\n\n context.fillStyle = textFill;\n }\n\n if (textBorderWidth > 0 && borderOpacity > 0) {\n var textStroke = context.strokeStyle;\n var textLineWidth = context.lineWidth;\n var textBorderColor = ele.pstyle('text-border-color').value;\n var textBorderStyle = ele.pstyle('text-border-style').value;\n context.strokeStyle = 'rgba(' + textBorderColor[0] + ',' + textBorderColor[1] + ',' + textBorderColor[2] + ',' + borderOpacity * parentOpacity + ')';\n context.lineWidth = textBorderWidth;\n\n if (context.setLineDash) {\n // for very outofdate browsers\n switch (textBorderStyle) {\n case 'dotted':\n context.setLineDash([1, 1]);\n break;\n\n case 'dashed':\n context.setLineDash([4, 2]);\n break;\n\n case 'double':\n context.lineWidth = textBorderWidth / 4; // 50% reserved for white between the two borders\n\n context.setLineDash([]);\n break;\n\n case 'solid':\n context.setLineDash([]);\n break;\n }\n }\n\n context.strokeRect(bgX, bgY, bgW, bgH);\n\n if (textBorderStyle === 'double') {\n var whiteWidth = textBorderWidth / 2;\n context.strokeRect(bgX + whiteWidth, bgY + whiteWidth, bgW - whiteWidth * 2, bgH - whiteWidth * 2);\n }\n\n if (context.setLineDash) {\n // for very outofdate browsers\n context.setLineDash([]);\n }\n\n context.lineWidth = textLineWidth;\n context.strokeStyle = textStroke;\n }\n }\n\n var lineWidth = 2 * ele.pstyle('text-outline-width').pfValue; // *2 b/c the stroke is drawn centred on the middle\n\n if (lineWidth > 0) {\n context.lineWidth = lineWidth;\n }\n\n if (ele.pstyle('text-wrap').value === 'wrap') {\n var lines = getPrefixedProperty(rscratch, 'labelWrapCachedLines', prefix);\n var lineHeight = getPrefixedProperty(rscratch, 'labelLineHeight', prefix);\n var halfTextW = textW / 2;\n var justification = this.getLabelJustification(ele);\n\n if (justification === 'auto') ; else if (halign === 'left') {\n // auto justification : right\n if (justification === 'left') {\n textX += -textW;\n } else if (justification === 'center') {\n textX += -halfTextW;\n } // else same as auto\n\n } else if (halign === 'center') {\n // auto justfication : center\n if (justification === 'left') {\n textX += -halfTextW;\n } else if (justification === 'right') {\n textX += halfTextW;\n } // else same as auto\n\n } else if (halign === 'right') {\n // auto justification : left\n if (justification === 'center') {\n textX += halfTextW;\n } else if (justification === 'right') {\n textX += textW;\n } // else same as auto\n\n }\n\n switch (valign) {\n case 'top':\n textY -= (lines.length - 1) * lineHeight;\n break;\n\n case 'center':\n case 'bottom':\n textY -= (lines.length - 1) * lineHeight;\n break;\n }\n\n for (var l = 0; l < lines.length; l++) {\n if (lineWidth > 0) {\n context.strokeText(lines[l], textX, textY);\n }\n\n context.fillText(lines[l], textX, textY);\n textY += lineHeight;\n }\n } else {\n if (lineWidth > 0) {\n context.strokeText(text, textX, textY);\n }\n\n context.fillText(text, textX, textY);\n }\n\n if (theta !== 0) {\n context.rotate(-theta);\n context.translate(-orgTextX, -orgTextY);\n }\n }\n };\n\n /* global Path2D */\n var CRp$5 = {};\n\n CRp$5.drawNode = function (context, node, shiftToOriginWithBb) {\n var drawLabel = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;\n var shouldDrawOverlay = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;\n var shouldDrawOpacity = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true;\n var r = this;\n var nodeWidth, nodeHeight;\n var _p = node._private;\n var rs = _p.rscratch;\n var pos = node.position();\n\n if (!number$1(pos.x) || !number$1(pos.y)) {\n return; // can't draw node with undefined position\n }\n\n if (shouldDrawOpacity && !node.visible()) {\n return;\n }\n\n var eleOpacity = shouldDrawOpacity ? node.effectiveOpacity() : 1;\n var usePaths = r.usePaths();\n var path;\n var pathCacheHit = false;\n var padding = node.padding();\n nodeWidth = node.width() + 2 * padding;\n nodeHeight = node.height() + 2 * padding; //\n // setup shift\n\n var bb;\n\n if (shiftToOriginWithBb) {\n bb = shiftToOriginWithBb;\n context.translate(-bb.x1, -bb.y1);\n } //\n // load bg image\n\n\n var bgImgProp = node.pstyle('background-image');\n var urls = bgImgProp.value;\n var urlDefined = new Array(urls.length);\n var image = new Array(urls.length);\n var numImages = 0;\n\n for (var i = 0; i < urls.length; i++) {\n var url = urls[i];\n var defd = urlDefined[i] = url != null && url !== 'none';\n\n if (defd) {\n var bgImgCrossOrigin = node.cy().style().getIndexedStyle(node, 'background-image-crossorigin', 'value', i);\n numImages++; // get image, and if not loaded then ask to redraw when later loaded\n\n image[i] = r.getCachedImage(url, bgImgCrossOrigin, function () {\n _p.backgroundTimestamp = Date.now();\n node.emitAndNotify('background');\n });\n }\n } //\n // setup styles\n\n\n var darkness = node.pstyle('background-blacken').value;\n var borderWidth = node.pstyle('border-width').pfValue;\n var bgOpacity = node.pstyle('background-opacity').value * eleOpacity;\n var borderColor = node.pstyle('border-color').value;\n var borderStyle = node.pstyle('border-style').value;\n var borderOpacity = node.pstyle('border-opacity').value * eleOpacity;\n context.lineJoin = 'miter'; // so borders are square with the node shape\n\n var setupShapeColor = function setupShapeColor() {\n var bgOpy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : bgOpacity;\n r.eleFillStyle(context, node, bgOpy);\n };\n\n var setupBorderColor = function setupBorderColor() {\n var bdrOpy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : borderOpacity;\n r.colorStrokeStyle(context, borderColor[0], borderColor[1], borderColor[2], bdrOpy);\n }; //\n // setup shape\n\n\n var styleShape = node.pstyle('shape').strValue;\n var shapePts = node.pstyle('shape-polygon-points').pfValue;\n\n if (usePaths) {\n context.translate(pos.x, pos.y);\n var pathCache = r.nodePathCache = r.nodePathCache || [];\n var key = hashStrings(styleShape === 'polygon' ? styleShape + ',' + shapePts.join(',') : styleShape, '' + nodeHeight, '' + nodeWidth);\n var cachedPath = pathCache[key];\n\n if (cachedPath != null) {\n path = cachedPath;\n pathCacheHit = true;\n rs.pathCache = path;\n } else {\n path = new Path2D();\n pathCache[key] = rs.pathCache = path;\n }\n }\n\n var drawShape = function drawShape() {\n if (!pathCacheHit) {\n var npos = pos;\n\n if (usePaths) {\n npos = {\n x: 0,\n y: 0\n };\n }\n\n r.nodeShapes[r.getNodeShape(node)].draw(path || context, npos.x, npos.y, nodeWidth, nodeHeight);\n }\n\n if (usePaths) {\n context.fill(path);\n } else {\n context.fill();\n }\n };\n\n var drawImages = function drawImages() {\n var nodeOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : eleOpacity;\n var inside = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n var prevBging = _p.backgrounding;\n var totalCompleted = 0;\n\n for (var _i = 0; _i < image.length; _i++) {\n var bgContainment = node.cy().style().getIndexedStyle(node, 'background-image-containment', 'value', _i);\n\n if (inside && bgContainment === 'over' || !inside && bgContainment === 'inside') {\n totalCompleted++;\n continue;\n }\n\n if (urlDefined[_i] && image[_i].complete && !image[_i].error) {\n totalCompleted++;\n r.drawInscribedImage(context, image[_i], node, _i, nodeOpacity);\n }\n }\n\n _p.backgrounding = !(totalCompleted === numImages);\n\n if (prevBging !== _p.backgrounding) {\n // update style b/c :backgrounding state changed\n node.updateStyle(false);\n }\n };\n\n var drawPie = function drawPie() {\n var redrawShape = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n var pieOpacity = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : eleOpacity;\n\n if (r.hasPie(node)) {\n r.drawPie(context, node, pieOpacity); // redraw/restore path if steps after pie need it\n\n if (redrawShape) {\n if (!usePaths) {\n r.nodeShapes[r.getNodeShape(node)].draw(context, pos.x, pos.y, nodeWidth, nodeHeight);\n }\n }\n }\n };\n\n var darken = function darken() {\n var darkenOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : eleOpacity;\n var opacity = (darkness > 0 ? darkness : -darkness) * darkenOpacity;\n var c = darkness > 0 ? 0 : 255;\n\n if (darkness !== 0) {\n r.colorFillStyle(context, c, c, c, opacity);\n\n if (usePaths) {\n context.fill(path);\n } else {\n context.fill();\n }\n }\n };\n\n var drawBorder = function drawBorder() {\n if (borderWidth > 0) {\n context.lineWidth = borderWidth;\n context.lineCap = 'butt';\n\n if (context.setLineDash) {\n // for very outofdate browsers\n switch (borderStyle) {\n case 'dotted':\n context.setLineDash([1, 1]);\n break;\n\n case 'dashed':\n context.setLineDash([4, 2]);\n break;\n\n case 'solid':\n case 'double':\n context.setLineDash([]);\n break;\n }\n }\n\n if (usePaths) {\n context.stroke(path);\n } else {\n context.stroke();\n }\n\n if (borderStyle === 'double') {\n context.lineWidth = borderWidth / 3;\n var gco = context.globalCompositeOperation;\n context.globalCompositeOperation = 'destination-out';\n\n if (usePaths) {\n context.stroke(path);\n } else {\n context.stroke();\n }\n\n context.globalCompositeOperation = gco;\n } // reset in case we changed the border style\n\n\n if (context.setLineDash) {\n // for very outofdate browsers\n context.setLineDash([]);\n }\n }\n };\n\n var drawOverlay = function drawOverlay() {\n if (shouldDrawOverlay) {\n r.drawNodeOverlay(context, node, pos, nodeWidth, nodeHeight);\n }\n };\n\n var drawUnderlay = function drawUnderlay() {\n if (shouldDrawOverlay) {\n r.drawNodeUnderlay(context, node, pos, nodeWidth, nodeHeight);\n }\n };\n\n var drawText = function drawText() {\n r.drawElementText(context, node, null, drawLabel);\n };\n\n var ghost = node.pstyle('ghost').value === 'yes';\n\n if (ghost) {\n var gx = node.pstyle('ghost-offset-x').pfValue;\n var gy = node.pstyle('ghost-offset-y').pfValue;\n var ghostOpacity = node.pstyle('ghost-opacity').value;\n var effGhostOpacity = ghostOpacity * eleOpacity;\n context.translate(gx, gy);\n setupShapeColor(ghostOpacity * bgOpacity);\n drawShape();\n drawImages(effGhostOpacity, true);\n setupBorderColor(ghostOpacity * borderOpacity);\n drawBorder();\n drawPie(darkness !== 0 || borderWidth !== 0);\n drawImages(effGhostOpacity, false);\n darken(effGhostOpacity);\n context.translate(-gx, -gy);\n }\n\n if (usePaths) {\n context.translate(-pos.x, -pos.y);\n }\n\n drawUnderlay();\n\n if (usePaths) {\n context.translate(pos.x, pos.y);\n }\n\n setupShapeColor();\n drawShape();\n drawImages(eleOpacity, true);\n setupBorderColor();\n drawBorder();\n drawPie(darkness !== 0 || borderWidth !== 0);\n drawImages(eleOpacity, false);\n darken();\n\n if (usePaths) {\n context.translate(-pos.x, -pos.y);\n }\n\n drawText();\n drawOverlay(); //\n // clean up shift\n\n if (shiftToOriginWithBb) {\n context.translate(bb.x1, bb.y1);\n }\n };\n\n var drawNodeOverlayUnderlay = function drawNodeOverlayUnderlay(overlayOrUnderlay) {\n if (!['overlay', 'underlay'].includes(overlayOrUnderlay)) {\n throw new Error('Invalid state');\n }\n\n return function (context, node, pos, nodeWidth, nodeHeight) {\n var r = this;\n\n if (!node.visible()) {\n return;\n }\n\n var padding = node.pstyle(\"\".concat(overlayOrUnderlay, \"-padding\")).pfValue;\n var opacity = node.pstyle(\"\".concat(overlayOrUnderlay, \"-opacity\")).value;\n var color = node.pstyle(\"\".concat(overlayOrUnderlay, \"-color\")).value;\n var shape = node.pstyle(\"\".concat(overlayOrUnderlay, \"-shape\")).value;\n\n if (opacity > 0) {\n pos = pos || node.position();\n\n if (nodeWidth == null || nodeHeight == null) {\n var _padding = node.padding();\n\n nodeWidth = node.width() + 2 * _padding;\n nodeHeight = node.height() + 2 * _padding;\n }\n\n r.colorFillStyle(context, color[0], color[1], color[2], opacity);\n r.nodeShapes[shape].draw(context, pos.x, pos.y, nodeWidth + padding * 2, nodeHeight + padding * 2);\n context.fill();\n }\n };\n };\n\n CRp$5.drawNodeOverlay = drawNodeOverlayUnderlay('overlay');\n CRp$5.drawNodeUnderlay = drawNodeOverlayUnderlay('underlay'); // does the node have at least one pie piece?\n\n CRp$5.hasPie = function (node) {\n node = node[0]; // ensure ele ref\n\n return node._private.hasPie;\n };\n\n CRp$5.drawPie = function (context, node, nodeOpacity, pos) {\n node = node[0]; // ensure ele ref\n\n pos = pos || node.position();\n var cyStyle = node.cy().style();\n var pieSize = node.pstyle('pie-size');\n var x = pos.x;\n var y = pos.y;\n var nodeW = node.width();\n var nodeH = node.height();\n var radius = Math.min(nodeW, nodeH) / 2; // must fit in node\n\n var lastPercent = 0; // what % to continue drawing pie slices from on [0, 1]\n\n var usePaths = this.usePaths();\n\n if (usePaths) {\n x = 0;\n y = 0;\n }\n\n if (pieSize.units === '%') {\n radius = radius * pieSize.pfValue;\n } else if (pieSize.pfValue !== undefined) {\n radius = pieSize.pfValue / 2;\n }\n\n for (var i = 1; i <= cyStyle.pieBackgroundN; i++) {\n // 1..N\n var size = node.pstyle('pie-' + i + '-background-size').value;\n var color = node.pstyle('pie-' + i + '-background-color').value;\n var opacity = node.pstyle('pie-' + i + '-background-opacity').value * nodeOpacity;\n var percent = size / 100; // map integer range [0, 100] to [0, 1]\n // percent can't push beyond 1\n\n if (percent + lastPercent > 1) {\n percent = 1 - lastPercent;\n }\n\n var angleStart = 1.5 * Math.PI + 2 * Math.PI * lastPercent; // start at 12 o'clock and go clockwise\n\n var angleDelta = 2 * Math.PI * percent;\n var angleEnd = angleStart + angleDelta; // ignore if\n // - zero size\n // - we're already beyond the full circle\n // - adding the current slice would go beyond the full circle\n\n if (size === 0 || lastPercent >= 1 || lastPercent + percent > 1) {\n continue;\n }\n\n context.beginPath();\n context.moveTo(x, y);\n context.arc(x, y, radius, angleStart, angleEnd);\n context.closePath();\n this.colorFillStyle(context, color[0], color[1], color[2], opacity);\n context.fill();\n lastPercent += percent;\n }\n };\n\n var CRp$4 = {};\n var motionBlurDelay = 100; // var isFirefox = typeof InstallTrigger !== 'undefined';\n\n CRp$4.getPixelRatio = function () {\n var context = this.data.contexts[0];\n\n if (this.forcedPixelRatio != null) {\n return this.forcedPixelRatio;\n }\n\n var backingStore = context.backingStorePixelRatio || context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1;\n return (window.devicePixelRatio || 1) / backingStore; // eslint-disable-line no-undef\n };\n\n CRp$4.paintCache = function (context) {\n var caches = this.paintCaches = this.paintCaches || [];\n var needToCreateCache = true;\n var cache;\n\n for (var i = 0; i < caches.length; i++) {\n cache = caches[i];\n\n if (cache.context === context) {\n needToCreateCache = false;\n break;\n }\n }\n\n if (needToCreateCache) {\n cache = {\n context: context\n };\n caches.push(cache);\n }\n\n return cache;\n };\n\n CRp$4.createGradientStyleFor = function (context, shapeStyleName, ele, fill, opacity) {\n var gradientStyle;\n var usePaths = this.usePaths();\n var colors = ele.pstyle(shapeStyleName + '-gradient-stop-colors').value,\n positions = ele.pstyle(shapeStyleName + '-gradient-stop-positions').pfValue;\n\n if (fill === 'radial-gradient') {\n if (ele.isEdge()) {\n var start = ele.sourceEndpoint(),\n end = ele.targetEndpoint(),\n mid = ele.midpoint();\n var d1 = dist(start, mid);\n var d2 = dist(end, mid);\n gradientStyle = context.createRadialGradient(mid.x, mid.y, 0, mid.x, mid.y, Math.max(d1, d2));\n } else {\n var pos = usePaths ? {\n x: 0,\n y: 0\n } : ele.position(),\n width = ele.paddedWidth(),\n height = ele.paddedHeight();\n gradientStyle = context.createRadialGradient(pos.x, pos.y, 0, pos.x, pos.y, Math.max(width, height));\n }\n } else {\n if (ele.isEdge()) {\n var _start = ele.sourceEndpoint(),\n _end = ele.targetEndpoint();\n\n gradientStyle = context.createLinearGradient(_start.x, _start.y, _end.x, _end.y);\n } else {\n var _pos = usePaths ? {\n x: 0,\n y: 0\n } : ele.position(),\n _width = ele.paddedWidth(),\n _height = ele.paddedHeight(),\n halfWidth = _width / 2,\n halfHeight = _height / 2;\n\n var direction = ele.pstyle('background-gradient-direction').value;\n\n switch (direction) {\n case 'to-bottom':\n gradientStyle = context.createLinearGradient(_pos.x, _pos.y - halfHeight, _pos.x, _pos.y + halfHeight);\n break;\n\n case 'to-top':\n gradientStyle = context.createLinearGradient(_pos.x, _pos.y + halfHeight, _pos.x, _pos.y - halfHeight);\n break;\n\n case 'to-left':\n gradientStyle = context.createLinearGradient(_pos.x + halfWidth, _pos.y, _pos.x - halfWidth, _pos.y);\n break;\n\n case 'to-right':\n gradientStyle = context.createLinearGradient(_pos.x - halfWidth, _pos.y, _pos.x + halfWidth, _pos.y);\n break;\n\n case 'to-bottom-right':\n case 'to-right-bottom':\n gradientStyle = context.createLinearGradient(_pos.x - halfWidth, _pos.y - halfHeight, _pos.x + halfWidth, _pos.y + halfHeight);\n break;\n\n case 'to-top-right':\n case 'to-right-top':\n gradientStyle = context.createLinearGradient(_pos.x - halfWidth, _pos.y + halfHeight, _pos.x + halfWidth, _pos.y - halfHeight);\n break;\n\n case 'to-bottom-left':\n case 'to-left-bottom':\n gradientStyle = context.createLinearGradient(_pos.x + halfWidth, _pos.y - halfHeight, _pos.x - halfWidth, _pos.y + halfHeight);\n break;\n\n case 'to-top-left':\n case 'to-left-top':\n gradientStyle = context.createLinearGradient(_pos.x + halfWidth, _pos.y + halfHeight, _pos.x - halfWidth, _pos.y - halfHeight);\n break;\n }\n }\n }\n\n if (!gradientStyle) return null; // invalid gradient style\n\n var hasPositions = positions.length === colors.length;\n var length = colors.length;\n\n for (var i = 0; i < length; i++) {\n gradientStyle.addColorStop(hasPositions ? positions[i] : i / (length - 1), 'rgba(' + colors[i][0] + ',' + colors[i][1] + ',' + colors[i][2] + ',' + opacity + ')');\n }\n\n return gradientStyle;\n };\n\n CRp$4.gradientFillStyle = function (context, ele, fill, opacity) {\n var gradientStyle = this.createGradientStyleFor(context, 'background', ele, fill, opacity);\n if (!gradientStyle) return null; // error\n\n context.fillStyle = gradientStyle;\n };\n\n CRp$4.colorFillStyle = function (context, r, g, b, a) {\n context.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; // turn off for now, seems context does its own caching\n // var cache = this.paintCache(context);\n // var fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';\n // if( cache.fillStyle !== fillStyle ){\n // context.fillStyle = cache.fillStyle = fillStyle;\n // }\n };\n\n CRp$4.eleFillStyle = function (context, ele, opacity) {\n var backgroundFill = ele.pstyle('background-fill').value;\n\n if (backgroundFill === 'linear-gradient' || backgroundFill === 'radial-gradient') {\n this.gradientFillStyle(context, ele, backgroundFill, opacity);\n } else {\n var backgroundColor = ele.pstyle('background-color').value;\n this.colorFillStyle(context, backgroundColor[0], backgroundColor[1], backgroundColor[2], opacity);\n }\n };\n\n CRp$4.gradientStrokeStyle = function (context, ele, fill, opacity) {\n var gradientStyle = this.createGradientStyleFor(context, 'line', ele, fill, opacity);\n if (!gradientStyle) return null; // error\n\n context.strokeStyle = gradientStyle;\n };\n\n CRp$4.colorStrokeStyle = function (context, r, g, b, a) {\n context.strokeStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; // turn off for now, seems context does its own caching\n // var cache = this.paintCache(context);\n // var strokeStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';\n // if( cache.strokeStyle !== strokeStyle ){\n // context.strokeStyle = cache.strokeStyle = strokeStyle;\n // }\n };\n\n CRp$4.eleStrokeStyle = function (context, ele, opacity) {\n var lineFill = ele.pstyle('line-fill').value;\n\n if (lineFill === 'linear-gradient' || lineFill === 'radial-gradient') {\n this.gradientStrokeStyle(context, ele, lineFill, opacity);\n } else {\n var lineColor = ele.pstyle('line-color').value;\n this.colorStrokeStyle(context, lineColor[0], lineColor[1], lineColor[2], opacity);\n }\n }; // Resize canvas\n\n\n CRp$4.matchCanvasSize = function (container) {\n var r = this;\n var data = r.data;\n var bb = r.findContainerClientCoords();\n var width = bb[2];\n var height = bb[3];\n var pixelRatio = r.getPixelRatio();\n var mbPxRatio = r.motionBlurPxRatio;\n\n if (container === r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_NODE] || container === r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_DRAG]) {\n pixelRatio = mbPxRatio;\n }\n\n var canvasWidth = width * pixelRatio;\n var canvasHeight = height * pixelRatio;\n var canvas;\n\n if (canvasWidth === r.canvasWidth && canvasHeight === r.canvasHeight) {\n return; // save cycles if same\n }\n\n r.fontCaches = null; // resizing resets the style\n\n var canvasContainer = data.canvasContainer;\n canvasContainer.style.width = width + 'px';\n canvasContainer.style.height = height + 'px';\n\n for (var i = 0; i < r.CANVAS_LAYERS; i++) {\n canvas = data.canvases[i];\n canvas.width = canvasWidth;\n canvas.height = canvasHeight;\n canvas.style.width = width + 'px';\n canvas.style.height = height + 'px';\n }\n\n for (var i = 0; i < r.BUFFER_COUNT; i++) {\n canvas = data.bufferCanvases[i];\n canvas.width = canvasWidth;\n canvas.height = canvasHeight;\n canvas.style.width = width + 'px';\n canvas.style.height = height + 'px';\n }\n\n r.textureMult = 1;\n\n if (pixelRatio <= 1) {\n canvas = data.bufferCanvases[r.TEXTURE_BUFFER];\n r.textureMult = 2;\n canvas.width = canvasWidth * r.textureMult;\n canvas.height = canvasHeight * r.textureMult;\n }\n\n r.canvasWidth = canvasWidth;\n r.canvasHeight = canvasHeight;\n };\n\n CRp$4.renderTo = function (cxt, zoom, pan, pxRatio) {\n this.render({\n forcedContext: cxt,\n forcedZoom: zoom,\n forcedPan: pan,\n drawAllLayers: true,\n forcedPxRatio: pxRatio\n });\n };\n\n CRp$4.render = function (options) {\n options = options || staticEmptyObject();\n var forcedContext = options.forcedContext;\n var drawAllLayers = options.drawAllLayers;\n var drawOnlyNodeLayer = options.drawOnlyNodeLayer;\n var forcedZoom = options.forcedZoom;\n var forcedPan = options.forcedPan;\n var r = this;\n var pixelRatio = options.forcedPxRatio === undefined ? this.getPixelRatio() : options.forcedPxRatio;\n var cy = r.cy;\n var data = r.data;\n var needDraw = data.canvasNeedsRedraw;\n var textureDraw = r.textureOnViewport && !forcedContext && (r.pinching || r.hoverData.dragging || r.swipePanning || r.data.wheelZooming);\n var motionBlur = options.motionBlur !== undefined ? options.motionBlur : r.motionBlur;\n var mbPxRatio = r.motionBlurPxRatio;\n var hasCompoundNodes = cy.hasCompoundNodes();\n var inNodeDragGesture = r.hoverData.draggingEles;\n var inBoxSelection = r.hoverData.selecting || r.touchData.selecting ? true : false;\n motionBlur = motionBlur && !forcedContext && r.motionBlurEnabled && !inBoxSelection;\n var motionBlurFadeEffect = motionBlur;\n\n if (!forcedContext) {\n if (r.prevPxRatio !== pixelRatio) {\n r.invalidateContainerClientCoordsCache();\n r.matchCanvasSize(r.container);\n r.redrawHint('eles', true);\n r.redrawHint('drag', true);\n }\n\n r.prevPxRatio = pixelRatio;\n }\n\n if (!forcedContext && r.motionBlurTimeout) {\n clearTimeout(r.motionBlurTimeout);\n }\n\n if (motionBlur) {\n if (r.mbFrames == null) {\n r.mbFrames = 0;\n }\n\n r.mbFrames++;\n\n if (r.mbFrames < 3) {\n // need several frames before even high quality motionblur\n motionBlurFadeEffect = false;\n } // go to lower quality blurry frames when several m/b frames have been rendered (avoids flashing)\n\n\n if (r.mbFrames > r.minMbLowQualFrames) {\n //r.fullQualityMb = false;\n r.motionBlurPxRatio = r.mbPxRBlurry;\n }\n }\n\n if (r.clearingMotionBlur) {\n r.motionBlurPxRatio = 1;\n } // b/c drawToContext() may be async w.r.t. redraw(), keep track of last texture frame\n // because a rogue async texture frame would clear needDraw\n\n\n if (r.textureDrawLastFrame && !textureDraw) {\n needDraw[r.NODE] = true;\n needDraw[r.SELECT_BOX] = true;\n }\n\n var style = cy.style();\n var zoom = cy.zoom();\n var effectiveZoom = forcedZoom !== undefined ? forcedZoom : zoom;\n var pan = cy.pan();\n var effectivePan = {\n x: pan.x,\n y: pan.y\n };\n var vp = {\n zoom: zoom,\n pan: {\n x: pan.x,\n y: pan.y\n }\n };\n var prevVp = r.prevViewport;\n var viewportIsDiff = prevVp === undefined || vp.zoom !== prevVp.zoom || vp.pan.x !== prevVp.pan.x || vp.pan.y !== prevVp.pan.y; // we want the low quality motionblur only when the viewport is being manipulated etc (where it's not noticed)\n\n if (!viewportIsDiff && !(inNodeDragGesture && !hasCompoundNodes)) {\n r.motionBlurPxRatio = 1;\n }\n\n if (forcedPan) {\n effectivePan = forcedPan;\n } // apply pixel ratio\n\n\n effectiveZoom *= pixelRatio;\n effectivePan.x *= pixelRatio;\n effectivePan.y *= pixelRatio;\n var eles = r.getCachedZSortedEles();\n\n function mbclear(context, x, y, w, h) {\n var gco = context.globalCompositeOperation;\n context.globalCompositeOperation = 'destination-out';\n r.colorFillStyle(context, 255, 255, 255, r.motionBlurTransparency);\n context.fillRect(x, y, w, h);\n context.globalCompositeOperation = gco;\n }\n\n function setContextTransform(context, clear) {\n var ePan, eZoom, w, h;\n\n if (!r.clearingMotionBlur && (context === data.bufferContexts[r.MOTIONBLUR_BUFFER_NODE] || context === data.bufferContexts[r.MOTIONBLUR_BUFFER_DRAG])) {\n ePan = {\n x: pan.x * mbPxRatio,\n y: pan.y * mbPxRatio\n };\n eZoom = zoom * mbPxRatio;\n w = r.canvasWidth * mbPxRatio;\n h = r.canvasHeight * mbPxRatio;\n } else {\n ePan = effectivePan;\n eZoom = effectiveZoom;\n w = r.canvasWidth;\n h = r.canvasHeight;\n }\n\n context.setTransform(1, 0, 0, 1, 0, 0);\n\n if (clear === 'motionBlur') {\n mbclear(context, 0, 0, w, h);\n } else if (!forcedContext && (clear === undefined || clear)) {\n context.clearRect(0, 0, w, h);\n }\n\n if (!drawAllLayers) {\n context.translate(ePan.x, ePan.y);\n context.scale(eZoom, eZoom);\n }\n\n if (forcedPan) {\n context.translate(forcedPan.x, forcedPan.y);\n }\n\n if (forcedZoom) {\n context.scale(forcedZoom, forcedZoom);\n }\n }\n\n if (!textureDraw) {\n r.textureDrawLastFrame = false;\n }\n\n if (textureDraw) {\n r.textureDrawLastFrame = true;\n\n if (!r.textureCache) {\n r.textureCache = {};\n r.textureCache.bb = cy.mutableElements().boundingBox();\n r.textureCache.texture = r.data.bufferCanvases[r.TEXTURE_BUFFER];\n var cxt = r.data.bufferContexts[r.TEXTURE_BUFFER];\n cxt.setTransform(1, 0, 0, 1, 0, 0);\n cxt.clearRect(0, 0, r.canvasWidth * r.textureMult, r.canvasHeight * r.textureMult);\n r.render({\n forcedContext: cxt,\n drawOnlyNodeLayer: true,\n forcedPxRatio: pixelRatio * r.textureMult\n });\n var vp = r.textureCache.viewport = {\n zoom: cy.zoom(),\n pan: cy.pan(),\n width: r.canvasWidth,\n height: r.canvasHeight\n };\n vp.mpan = {\n x: (0 - vp.pan.x) / vp.zoom,\n y: (0 - vp.pan.y) / vp.zoom\n };\n }\n\n needDraw[r.DRAG] = false;\n needDraw[r.NODE] = false;\n var context = data.contexts[r.NODE];\n var texture = r.textureCache.texture;\n var vp = r.textureCache.viewport;\n context.setTransform(1, 0, 0, 1, 0, 0);\n\n if (motionBlur) {\n mbclear(context, 0, 0, vp.width, vp.height);\n } else {\n context.clearRect(0, 0, vp.width, vp.height);\n }\n\n var outsideBgColor = style.core('outside-texture-bg-color').value;\n var outsideBgOpacity = style.core('outside-texture-bg-opacity').value;\n r.colorFillStyle(context, outsideBgColor[0], outsideBgColor[1], outsideBgColor[2], outsideBgOpacity);\n context.fillRect(0, 0, vp.width, vp.height);\n var zoom = cy.zoom();\n setContextTransform(context, false);\n context.clearRect(vp.mpan.x, vp.mpan.y, vp.width / vp.zoom / pixelRatio, vp.height / vp.zoom / pixelRatio);\n context.drawImage(texture, vp.mpan.x, vp.mpan.y, vp.width / vp.zoom / pixelRatio, vp.height / vp.zoom / pixelRatio);\n } else if (r.textureOnViewport && !forcedContext) {\n // clear the cache since we don't need it\n r.textureCache = null;\n }\n\n var extent = cy.extent();\n var vpManip = r.pinching || r.hoverData.dragging || r.swipePanning || r.data.wheelZooming || r.hoverData.draggingEles || r.cy.animated();\n var hideEdges = r.hideEdgesOnViewport && vpManip;\n var needMbClear = [];\n needMbClear[r.NODE] = !needDraw[r.NODE] && motionBlur && !r.clearedForMotionBlur[r.NODE] || r.clearingMotionBlur;\n\n if (needMbClear[r.NODE]) {\n r.clearedForMotionBlur[r.NODE] = true;\n }\n\n needMbClear[r.DRAG] = !needDraw[r.DRAG] && motionBlur && !r.clearedForMotionBlur[r.DRAG] || r.clearingMotionBlur;\n\n if (needMbClear[r.DRAG]) {\n r.clearedForMotionBlur[r.DRAG] = true;\n }\n\n if (needDraw[r.NODE] || drawAllLayers || drawOnlyNodeLayer || needMbClear[r.NODE]) {\n var useBuffer = motionBlur && !needMbClear[r.NODE] && mbPxRatio !== 1;\n var context = forcedContext || (useBuffer ? r.data.bufferContexts[r.MOTIONBLUR_BUFFER_NODE] : data.contexts[r.NODE]);\n var clear = motionBlur && !useBuffer ? 'motionBlur' : undefined;\n setContextTransform(context, clear);\n\n if (hideEdges) {\n r.drawCachedNodes(context, eles.nondrag, pixelRatio, extent);\n } else {\n r.drawLayeredElements(context, eles.nondrag, pixelRatio, extent);\n }\n\n if (r.debug) {\n r.drawDebugPoints(context, eles.nondrag);\n }\n\n if (!drawAllLayers && !motionBlur) {\n needDraw[r.NODE] = false;\n }\n }\n\n if (!drawOnlyNodeLayer && (needDraw[r.DRAG] || drawAllLayers || needMbClear[r.DRAG])) {\n var useBuffer = motionBlur && !needMbClear[r.DRAG] && mbPxRatio !== 1;\n var context = forcedContext || (useBuffer ? r.data.bufferContexts[r.MOTIONBLUR_BUFFER_DRAG] : data.contexts[r.DRAG]);\n setContextTransform(context, motionBlur && !useBuffer ? 'motionBlur' : undefined);\n\n if (hideEdges) {\n r.drawCachedNodes(context, eles.drag, pixelRatio, extent);\n } else {\n r.drawCachedElements(context, eles.drag, pixelRatio, extent);\n }\n\n if (r.debug) {\n r.drawDebugPoints(context, eles.drag);\n }\n\n if (!drawAllLayers && !motionBlur) {\n needDraw[r.DRAG] = false;\n }\n }\n\n if (r.showFps || !drawOnlyNodeLayer && needDraw[r.SELECT_BOX] && !drawAllLayers) {\n var context = forcedContext || data.contexts[r.SELECT_BOX];\n setContextTransform(context);\n\n if (r.selection[4] == 1 && (r.hoverData.selecting || r.touchData.selecting)) {\n var zoom = r.cy.zoom();\n var borderWidth = style.core('selection-box-border-width').value / zoom;\n context.lineWidth = borderWidth;\n context.fillStyle = 'rgba(' + style.core('selection-box-color').value[0] + ',' + style.core('selection-box-color').value[1] + ',' + style.core('selection-box-color').value[2] + ',' + style.core('selection-box-opacity').value + ')';\n context.fillRect(r.selection[0], r.selection[1], r.selection[2] - r.selection[0], r.selection[3] - r.selection[1]);\n\n if (borderWidth > 0) {\n context.strokeStyle = 'rgba(' + style.core('selection-box-border-color').value[0] + ',' + style.core('selection-box-border-color').value[1] + ',' + style.core('selection-box-border-color').value[2] + ',' + style.core('selection-box-opacity').value + ')';\n context.strokeRect(r.selection[0], r.selection[1], r.selection[2] - r.selection[0], r.selection[3] - r.selection[1]);\n }\n }\n\n if (data.bgActivePosistion && !r.hoverData.selecting) {\n var zoom = r.cy.zoom();\n var pos = data.bgActivePosistion;\n context.fillStyle = 'rgba(' + style.core('active-bg-color').value[0] + ',' + style.core('active-bg-color').value[1] + ',' + style.core('active-bg-color').value[2] + ',' + style.core('active-bg-opacity').value + ')';\n context.beginPath();\n context.arc(pos.x, pos.y, style.core('active-bg-size').pfValue / zoom, 0, 2 * Math.PI);\n context.fill();\n }\n\n var timeToRender = r.lastRedrawTime;\n\n if (r.showFps && timeToRender) {\n timeToRender = Math.round(timeToRender);\n var fps = Math.round(1000 / timeToRender);\n context.setTransform(1, 0, 0, 1, 0, 0);\n context.fillStyle = 'rgba(255, 0, 0, 0.75)';\n context.strokeStyle = 'rgba(255, 0, 0, 0.75)';\n context.lineWidth = 1;\n context.fillText('1 frame = ' + timeToRender + ' ms = ' + fps + ' fps', 0, 20);\n var maxFps = 60;\n context.strokeRect(0, 30, 250, 20);\n context.fillRect(0, 30, 250 * Math.min(fps / maxFps, 1), 20);\n }\n\n if (!drawAllLayers) {\n needDraw[r.SELECT_BOX] = false;\n }\n } // motionblur: blit rendered blurry frames\n\n\n if (motionBlur && mbPxRatio !== 1) {\n var cxtNode = data.contexts[r.NODE];\n var txtNode = r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_NODE];\n var cxtDrag = data.contexts[r.DRAG];\n var txtDrag = r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_DRAG];\n\n var drawMotionBlur = function drawMotionBlur(cxt, txt, needClear) {\n cxt.setTransform(1, 0, 0, 1, 0, 0);\n\n if (needClear || !motionBlurFadeEffect) {\n cxt.clearRect(0, 0, r.canvasWidth, r.canvasHeight);\n } else {\n mbclear(cxt, 0, 0, r.canvasWidth, r.canvasHeight);\n }\n\n var pxr = mbPxRatio;\n cxt.drawImage(txt, // img\n 0, 0, // sx, sy\n r.canvasWidth * pxr, r.canvasHeight * pxr, // sw, sh\n 0, 0, // x, y\n r.canvasWidth, r.canvasHeight // w, h\n );\n };\n\n if (needDraw[r.NODE] || needMbClear[r.NODE]) {\n drawMotionBlur(cxtNode, txtNode, needMbClear[r.NODE]);\n needDraw[r.NODE] = false;\n }\n\n if (needDraw[r.DRAG] || needMbClear[r.DRAG]) {\n drawMotionBlur(cxtDrag, txtDrag, needMbClear[r.DRAG]);\n needDraw[r.DRAG] = false;\n }\n }\n\n r.prevViewport = vp;\n\n if (r.clearingMotionBlur) {\n r.clearingMotionBlur = false;\n r.motionBlurCleared = true;\n r.motionBlur = true;\n }\n\n if (motionBlur) {\n r.motionBlurTimeout = setTimeout(function () {\n r.motionBlurTimeout = null;\n r.clearedForMotionBlur[r.NODE] = false;\n r.clearedForMotionBlur[r.DRAG] = false;\n r.motionBlur = false;\n r.clearingMotionBlur = !textureDraw;\n r.mbFrames = 0;\n needDraw[r.NODE] = true;\n needDraw[r.DRAG] = true;\n r.redraw();\n }, motionBlurDelay);\n }\n\n if (!forcedContext) {\n cy.emit('render');\n }\n };\n\n var CRp$3 = {}; // @O Polygon drawing\n\n CRp$3.drawPolygonPath = function (context, x, y, width, height, points) {\n var halfW = width / 2;\n var halfH = height / 2;\n\n if (context.beginPath) {\n context.beginPath();\n }\n\n context.moveTo(x + halfW * points[0], y + halfH * points[1]);\n\n for (var i = 1; i < points.length / 2; i++) {\n context.lineTo(x + halfW * points[i * 2], y + halfH * points[i * 2 + 1]);\n }\n\n context.closePath();\n };\n\n CRp$3.drawRoundPolygonPath = function (context, x, y, width, height, points) {\n var halfW = width / 2;\n var halfH = height / 2;\n var cornerRadius = getRoundPolygonRadius(width, height);\n\n if (context.beginPath) {\n context.beginPath();\n }\n\n for (var _i = 0; _i < points.length / 4; _i++) {\n var sourceUv = void 0,\n destUv = void 0;\n\n if (_i === 0) {\n sourceUv = points.length - 2;\n } else {\n sourceUv = _i * 4 - 2;\n }\n\n destUv = _i * 4 + 2;\n var px = x + halfW * points[_i * 4];\n var py = y + halfH * points[_i * 4 + 1];\n var cosTheta = -points[sourceUv] * points[destUv] - points[sourceUv + 1] * points[destUv + 1];\n var offset = cornerRadius / Math.tan(Math.acos(cosTheta) / 2);\n var cp0x = px - offset * points[sourceUv];\n var cp0y = py - offset * points[sourceUv + 1];\n var cp1x = px + offset * points[destUv];\n var cp1y = py + offset * points[destUv + 1];\n\n if (_i === 0) {\n context.moveTo(cp0x, cp0y);\n } else {\n context.lineTo(cp0x, cp0y);\n }\n\n context.arcTo(px, py, cp1x, cp1y, cornerRadius);\n }\n\n context.closePath();\n }; // Round rectangle drawing\n\n\n CRp$3.drawRoundRectanglePath = function (context, x, y, width, height) {\n var halfWidth = width / 2;\n var halfHeight = height / 2;\n var cornerRadius = getRoundRectangleRadius(width, height);\n\n if (context.beginPath) {\n context.beginPath();\n } // Start at top middle\n\n\n context.moveTo(x, y - halfHeight); // Arc from middle top to right side\n\n context.arcTo(x + halfWidth, y - halfHeight, x + halfWidth, y, cornerRadius); // Arc from right side to bottom\n\n context.arcTo(x + halfWidth, y + halfHeight, x, y + halfHeight, cornerRadius); // Arc from bottom to left side\n\n context.arcTo(x - halfWidth, y + halfHeight, x - halfWidth, y, cornerRadius); // Arc from left side to topBorder\n\n context.arcTo(x - halfWidth, y - halfHeight, x, y - halfHeight, cornerRadius); // Join line\n\n context.lineTo(x, y - halfHeight);\n context.closePath();\n };\n\n CRp$3.drawBottomRoundRectanglePath = function (context, x, y, width, height) {\n var halfWidth = width / 2;\n var halfHeight = height / 2;\n var cornerRadius = getRoundRectangleRadius(width, height);\n\n if (context.beginPath) {\n context.beginPath();\n } // Start at top middle\n\n\n context.moveTo(x, y - halfHeight);\n context.lineTo(x + halfWidth, y - halfHeight);\n context.lineTo(x + halfWidth, y);\n context.arcTo(x + halfWidth, y + halfHeight, x, y + halfHeight, cornerRadius);\n context.arcTo(x - halfWidth, y + halfHeight, x - halfWidth, y, cornerRadius);\n context.lineTo(x - halfWidth, y - halfHeight);\n context.lineTo(x, y - halfHeight);\n context.closePath();\n };\n\n CRp$3.drawCutRectanglePath = function (context, x, y, width, height) {\n var halfWidth = width / 2;\n var halfHeight = height / 2;\n var cornerLength = getCutRectangleCornerLength();\n\n if (context.beginPath) {\n context.beginPath();\n }\n\n context.moveTo(x - halfWidth + cornerLength, y - halfHeight);\n context.lineTo(x + halfWidth - cornerLength, y - halfHeight);\n context.lineTo(x + halfWidth, y - halfHeight + cornerLength);\n context.lineTo(x + halfWidth, y + halfHeight - cornerLength);\n context.lineTo(x + halfWidth - cornerLength, y + halfHeight);\n context.lineTo(x - halfWidth + cornerLength, y + halfHeight);\n context.lineTo(x - halfWidth, y + halfHeight - cornerLength);\n context.lineTo(x - halfWidth, y - halfHeight + cornerLength);\n context.closePath();\n };\n\n CRp$3.drawBarrelPath = function (context, x, y, width, height) {\n var halfWidth = width / 2;\n var halfHeight = height / 2;\n var xBegin = x - halfWidth;\n var xEnd = x + halfWidth;\n var yBegin = y - halfHeight;\n var yEnd = y + halfHeight;\n var barrelCurveConstants = getBarrelCurveConstants(width, height);\n var wOffset = barrelCurveConstants.widthOffset;\n var hOffset = barrelCurveConstants.heightOffset;\n var ctrlPtXOffset = barrelCurveConstants.ctrlPtOffsetPct * wOffset;\n\n if (context.beginPath) {\n context.beginPath();\n }\n\n context.moveTo(xBegin, yBegin + hOffset);\n context.lineTo(xBegin, yEnd - hOffset);\n context.quadraticCurveTo(xBegin + ctrlPtXOffset, yEnd, xBegin + wOffset, yEnd);\n context.lineTo(xEnd - wOffset, yEnd);\n context.quadraticCurveTo(xEnd - ctrlPtXOffset, yEnd, xEnd, yEnd - hOffset);\n context.lineTo(xEnd, yBegin + hOffset);\n context.quadraticCurveTo(xEnd - ctrlPtXOffset, yBegin, xEnd - wOffset, yBegin);\n context.lineTo(xBegin + wOffset, yBegin);\n context.quadraticCurveTo(xBegin + ctrlPtXOffset, yBegin, xBegin, yBegin + hOffset);\n context.closePath();\n };\n\n var sin0 = Math.sin(0);\n var cos0 = Math.cos(0);\n var sin = {};\n var cos = {};\n var ellipseStepSize = Math.PI / 40;\n\n for (var i = 0 * Math.PI; i < 2 * Math.PI; i += ellipseStepSize) {\n sin[i] = Math.sin(i);\n cos[i] = Math.cos(i);\n }\n\n CRp$3.drawEllipsePath = function (context, centerX, centerY, width, height) {\n if (context.beginPath) {\n context.beginPath();\n }\n\n if (context.ellipse) {\n context.ellipse(centerX, centerY, width / 2, height / 2, 0, 0, 2 * Math.PI);\n } else {\n var xPos, yPos;\n var rw = width / 2;\n var rh = height / 2;\n\n for (var i = 0 * Math.PI; i < 2 * Math.PI; i += ellipseStepSize) {\n xPos = centerX - rw * sin[i] * sin0 + rw * cos[i] * cos0;\n yPos = centerY + rh * cos[i] * sin0 + rh * sin[i] * cos0;\n\n if (i === 0) {\n context.moveTo(xPos, yPos);\n } else {\n context.lineTo(xPos, yPos);\n }\n }\n }\n\n context.closePath();\n };\n\n /* global atob, ArrayBuffer, Uint8Array, Blob */\n var CRp$2 = {};\n\n CRp$2.createBuffer = function (w, h) {\n var buffer = document.createElement('canvas'); // eslint-disable-line no-undef\n\n buffer.width = w;\n buffer.height = h;\n return [buffer, buffer.getContext('2d')];\n };\n\n CRp$2.bufferCanvasImage = function (options) {\n var cy = this.cy;\n var eles = cy.mutableElements();\n var bb = eles.boundingBox();\n var ctrRect = this.findContainerClientCoords();\n var width = options.full ? Math.ceil(bb.w) : ctrRect[2];\n var height = options.full ? Math.ceil(bb.h) : ctrRect[3];\n var specdMaxDims = number$1(options.maxWidth) || number$1(options.maxHeight);\n var pxRatio = this.getPixelRatio();\n var scale = 1;\n\n if (options.scale !== undefined) {\n width *= options.scale;\n height *= options.scale;\n scale = options.scale;\n } else if (specdMaxDims) {\n var maxScaleW = Infinity;\n var maxScaleH = Infinity;\n\n if (number$1(options.maxWidth)) {\n maxScaleW = scale * options.maxWidth / width;\n }\n\n if (number$1(options.maxHeight)) {\n maxScaleH = scale * options.maxHeight / height;\n }\n\n scale = Math.min(maxScaleW, maxScaleH);\n width *= scale;\n height *= scale;\n }\n\n if (!specdMaxDims) {\n width *= pxRatio;\n height *= pxRatio;\n scale *= pxRatio;\n }\n\n var buffCanvas = document.createElement('canvas'); // eslint-disable-line no-undef\n\n buffCanvas.width = width;\n buffCanvas.height = height;\n buffCanvas.style.width = width + 'px';\n buffCanvas.style.height = height + 'px';\n var buffCxt = buffCanvas.getContext('2d'); // Rasterize the layers, but only if container has nonzero size\n\n if (width > 0 && height > 0) {\n buffCxt.clearRect(0, 0, width, height);\n buffCxt.globalCompositeOperation = 'source-over';\n var zsortedEles = this.getCachedZSortedEles();\n\n if (options.full) {\n // draw the full bounds of the graph\n buffCxt.translate(-bb.x1 * scale, -bb.y1 * scale);\n buffCxt.scale(scale, scale);\n this.drawElements(buffCxt, zsortedEles);\n buffCxt.scale(1 / scale, 1 / scale);\n buffCxt.translate(bb.x1 * scale, bb.y1 * scale);\n } else {\n // draw the current view\n var pan = cy.pan();\n var translation = {\n x: pan.x * scale,\n y: pan.y * scale\n };\n scale *= cy.zoom();\n buffCxt.translate(translation.x, translation.y);\n buffCxt.scale(scale, scale);\n this.drawElements(buffCxt, zsortedEles);\n buffCxt.scale(1 / scale, 1 / scale);\n buffCxt.translate(-translation.x, -translation.y);\n } // need to fill bg at end like this in order to fill cleared transparent pixels in jpgs\n\n\n if (options.bg) {\n buffCxt.globalCompositeOperation = 'destination-over';\n buffCxt.fillStyle = options.bg;\n buffCxt.rect(0, 0, width, height);\n buffCxt.fill();\n }\n }\n\n return buffCanvas;\n };\n\n function b64ToBlob(b64, mimeType) {\n var bytes = atob(b64);\n var buff = new ArrayBuffer(bytes.length);\n var buffUint8 = new Uint8Array(buff);\n\n for (var i = 0; i < bytes.length; i++) {\n buffUint8[i] = bytes.charCodeAt(i);\n }\n\n return new Blob([buff], {\n type: mimeType\n });\n }\n\n function b64UriToB64(b64uri) {\n var i = b64uri.indexOf(',');\n return b64uri.substr(i + 1);\n }\n\n function output(options, canvas, mimeType) {\n var getB64Uri = function getB64Uri() {\n return canvas.toDataURL(mimeType, options.quality);\n };\n\n switch (options.output) {\n case 'blob-promise':\n return new Promise$1(function (resolve, reject) {\n try {\n canvas.toBlob(function (blob) {\n if (blob != null) {\n resolve(blob);\n } else {\n reject(new Error('`canvas.toBlob()` sent a null value in its callback'));\n }\n }, mimeType, options.quality);\n } catch (err) {\n reject(err);\n }\n });\n\n case 'blob':\n return b64ToBlob(b64UriToB64(getB64Uri()), mimeType);\n\n case 'base64':\n return b64UriToB64(getB64Uri());\n\n case 'base64uri':\n default:\n return getB64Uri();\n }\n }\n\n CRp$2.png = function (options) {\n return output(options, this.bufferCanvasImage(options), 'image/png');\n };\n\n CRp$2.jpg = function (options) {\n return output(options, this.bufferCanvasImage(options), 'image/jpeg');\n };\n\n var CRp$1 = {};\n\n CRp$1.nodeShapeImpl = function (name, context, centerX, centerY, width, height, points) {\n switch (name) {\n case 'ellipse':\n return this.drawEllipsePath(context, centerX, centerY, width, height);\n\n case 'polygon':\n return this.drawPolygonPath(context, centerX, centerY, width, height, points);\n\n case 'round-polygon':\n return this.drawRoundPolygonPath(context, centerX, centerY, width, height, points);\n\n case 'roundrectangle':\n case 'round-rectangle':\n return this.drawRoundRectanglePath(context, centerX, centerY, width, height);\n\n case 'cutrectangle':\n case 'cut-rectangle':\n return this.drawCutRectanglePath(context, centerX, centerY, width, height);\n\n case 'bottomroundrectangle':\n case 'bottom-round-rectangle':\n return this.drawBottomRoundRectanglePath(context, centerX, centerY, width, height);\n\n case 'barrel':\n return this.drawBarrelPath(context, centerX, centerY, width, height);\n }\n };\n\n var CR = CanvasRenderer;\n var CRp = CanvasRenderer.prototype;\n CRp.CANVAS_LAYERS = 3; //\n\n CRp.SELECT_BOX = 0;\n CRp.DRAG = 1;\n CRp.NODE = 2;\n CRp.BUFFER_COUNT = 3; //\n\n CRp.TEXTURE_BUFFER = 0;\n CRp.MOTIONBLUR_BUFFER_NODE = 1;\n CRp.MOTIONBLUR_BUFFER_DRAG = 2;\n\n function CanvasRenderer(options) {\n var r = this;\n r.data = {\n canvases: new Array(CRp.CANVAS_LAYERS),\n contexts: new Array(CRp.CANVAS_LAYERS),\n canvasNeedsRedraw: new Array(CRp.CANVAS_LAYERS),\n bufferCanvases: new Array(CRp.BUFFER_COUNT),\n bufferContexts: new Array(CRp.CANVAS_LAYERS)\n };\n var tapHlOffAttr = '-webkit-tap-highlight-color';\n var tapHlOffStyle = 'rgba(0,0,0,0)';\n r.data.canvasContainer = document.createElement('div'); // eslint-disable-line no-undef\n\n var containerStyle = r.data.canvasContainer.style;\n r.data.canvasContainer.style[tapHlOffAttr] = tapHlOffStyle;\n containerStyle.position = 'relative';\n containerStyle.zIndex = '0';\n containerStyle.overflow = 'hidden';\n var container = options.cy.container();\n container.appendChild(r.data.canvasContainer);\n container.style[tapHlOffAttr] = tapHlOffStyle;\n var styleMap = {\n '-webkit-user-select': 'none',\n '-moz-user-select': '-moz-none',\n 'user-select': 'none',\n '-webkit-tap-highlight-color': 'rgba(0,0,0,0)',\n 'outline-style': 'none'\n };\n\n if (ms()) {\n styleMap['-ms-touch-action'] = 'none';\n styleMap['touch-action'] = 'none';\n }\n\n for (var i = 0; i < CRp.CANVAS_LAYERS; i++) {\n var canvas = r.data.canvases[i] = document.createElement('canvas'); // eslint-disable-line no-undef\n\n r.data.contexts[i] = canvas.getContext('2d');\n Object.keys(styleMap).forEach(function (k) {\n canvas.style[k] = styleMap[k];\n });\n canvas.style.position = 'absolute';\n canvas.setAttribute('data-id', 'layer' + i);\n canvas.style.zIndex = String(CRp.CANVAS_LAYERS - i);\n r.data.canvasContainer.appendChild(canvas);\n r.data.canvasNeedsRedraw[i] = false;\n }\n\n r.data.topCanvas = r.data.canvases[0];\n r.data.canvases[CRp.NODE].setAttribute('data-id', 'layer' + CRp.NODE + '-node');\n r.data.canvases[CRp.SELECT_BOX].setAttribute('data-id', 'layer' + CRp.SELECT_BOX + '-selectbox');\n r.data.canvases[CRp.DRAG].setAttribute('data-id', 'layer' + CRp.DRAG + '-drag');\n\n for (var i = 0; i < CRp.BUFFER_COUNT; i++) {\n r.data.bufferCanvases[i] = document.createElement('canvas'); // eslint-disable-line no-undef\n\n r.data.bufferContexts[i] = r.data.bufferCanvases[i].getContext('2d');\n r.data.bufferCanvases[i].style.position = 'absolute';\n r.data.bufferCanvases[i].setAttribute('data-id', 'buffer' + i);\n r.data.bufferCanvases[i].style.zIndex = String(-i - 1);\n r.data.bufferCanvases[i].style.visibility = 'hidden'; //r.data.canvasContainer.appendChild(r.data.bufferCanvases[i]);\n }\n\n r.pathsEnabled = true;\n var emptyBb = makeBoundingBox();\n\n var getBoxCenter = function getBoxCenter(bb) {\n return {\n x: (bb.x1 + bb.x2) / 2,\n y: (bb.y1 + bb.y2) / 2\n };\n };\n\n var getCenterOffset = function getCenterOffset(bb) {\n return {\n x: -bb.w / 2,\n y: -bb.h / 2\n };\n };\n\n var backgroundTimestampHasChanged = function backgroundTimestampHasChanged(ele) {\n var _p = ele[0]._private;\n var same = _p.oldBackgroundTimestamp === _p.backgroundTimestamp;\n return !same;\n };\n\n var getStyleKey = function getStyleKey(ele) {\n return ele[0]._private.nodeKey;\n };\n\n var getLabelKey = function getLabelKey(ele) {\n return ele[0]._private.labelStyleKey;\n };\n\n var getSourceLabelKey = function getSourceLabelKey(ele) {\n return ele[0]._private.sourceLabelStyleKey;\n };\n\n var getTargetLabelKey = function getTargetLabelKey(ele) {\n return ele[0]._private.targetLabelStyleKey;\n };\n\n var drawElement = function drawElement(context, ele, bb, scaledLabelShown, useEleOpacity) {\n return r.drawElement(context, ele, bb, false, false, useEleOpacity);\n };\n\n var drawLabel = function drawLabel(context, ele, bb, scaledLabelShown, useEleOpacity) {\n return r.drawElementText(context, ele, bb, scaledLabelShown, 'main', useEleOpacity);\n };\n\n var drawSourceLabel = function drawSourceLabel(context, ele, bb, scaledLabelShown, useEleOpacity) {\n return r.drawElementText(context, ele, bb, scaledLabelShown, 'source', useEleOpacity);\n };\n\n var drawTargetLabel = function drawTargetLabel(context, ele, bb, scaledLabelShown, useEleOpacity) {\n return r.drawElementText(context, ele, bb, scaledLabelShown, 'target', useEleOpacity);\n };\n\n var getElementBox = function getElementBox(ele) {\n ele.boundingBox();\n return ele[0]._private.bodyBounds;\n };\n\n var getLabelBox = function getLabelBox(ele) {\n ele.boundingBox();\n return ele[0]._private.labelBounds.main || emptyBb;\n };\n\n var getSourceLabelBox = function getSourceLabelBox(ele) {\n ele.boundingBox();\n return ele[0]._private.labelBounds.source || emptyBb;\n };\n\n var getTargetLabelBox = function getTargetLabelBox(ele) {\n ele.boundingBox();\n return ele[0]._private.labelBounds.target || emptyBb;\n };\n\n var isLabelVisibleAtScale = function isLabelVisibleAtScale(ele, scaledLabelShown) {\n return scaledLabelShown;\n };\n\n var getElementRotationPoint = function getElementRotationPoint(ele) {\n return getBoxCenter(getElementBox(ele));\n };\n\n var addTextMargin = function addTextMargin(prefix, pt, ele) {\n var pre = prefix ? prefix + '-' : '';\n return {\n x: pt.x + ele.pstyle(pre + 'text-margin-x').pfValue,\n y: pt.y + ele.pstyle(pre + 'text-margin-y').pfValue\n };\n };\n\n var getRsPt = function getRsPt(ele, x, y) {\n var rs = ele[0]._private.rscratch;\n return {\n x: rs[x],\n y: rs[y]\n };\n };\n\n var getLabelRotationPoint = function getLabelRotationPoint(ele) {\n return addTextMargin('', getRsPt(ele, 'labelX', 'labelY'), ele);\n };\n\n var getSourceLabelRotationPoint = function getSourceLabelRotationPoint(ele) {\n return addTextMargin('source', getRsPt(ele, 'sourceLabelX', 'sourceLabelY'), ele);\n };\n\n var getTargetLabelRotationPoint = function getTargetLabelRotationPoint(ele) {\n return addTextMargin('target', getRsPt(ele, 'targetLabelX', 'targetLabelY'), ele);\n };\n\n var getElementRotationOffset = function getElementRotationOffset(ele) {\n return getCenterOffset(getElementBox(ele));\n };\n\n var getSourceLabelRotationOffset = function getSourceLabelRotationOffset(ele) {\n return getCenterOffset(getSourceLabelBox(ele));\n };\n\n var getTargetLabelRotationOffset = function getTargetLabelRotationOffset(ele) {\n return getCenterOffset(getTargetLabelBox(ele));\n };\n\n var getLabelRotationOffset = function getLabelRotationOffset(ele) {\n var bb = getLabelBox(ele);\n var p = getCenterOffset(getLabelBox(ele));\n\n if (ele.isNode()) {\n switch (ele.pstyle('text-halign').value) {\n case 'left':\n p.x = -bb.w;\n break;\n\n case 'right':\n p.x = 0;\n break;\n }\n\n switch (ele.pstyle('text-valign').value) {\n case 'top':\n p.y = -bb.h;\n break;\n\n case 'bottom':\n p.y = 0;\n break;\n }\n }\n\n return p;\n };\n\n var eleTxrCache = r.data.eleTxrCache = new ElementTextureCache(r, {\n getKey: getStyleKey,\n doesEleInvalidateKey: backgroundTimestampHasChanged,\n drawElement: drawElement,\n getBoundingBox: getElementBox,\n getRotationPoint: getElementRotationPoint,\n getRotationOffset: getElementRotationOffset,\n allowEdgeTxrCaching: false,\n allowParentTxrCaching: false\n });\n var lblTxrCache = r.data.lblTxrCache = new ElementTextureCache(r, {\n getKey: getLabelKey,\n drawElement: drawLabel,\n getBoundingBox: getLabelBox,\n getRotationPoint: getLabelRotationPoint,\n getRotationOffset: getLabelRotationOffset,\n isVisible: isLabelVisibleAtScale\n });\n var slbTxrCache = r.data.slbTxrCache = new ElementTextureCache(r, {\n getKey: getSourceLabelKey,\n drawElement: drawSourceLabel,\n getBoundingBox: getSourceLabelBox,\n getRotationPoint: getSourceLabelRotationPoint,\n getRotationOffset: getSourceLabelRotationOffset,\n isVisible: isLabelVisibleAtScale\n });\n var tlbTxrCache = r.data.tlbTxrCache = new ElementTextureCache(r, {\n getKey: getTargetLabelKey,\n drawElement: drawTargetLabel,\n getBoundingBox: getTargetLabelBox,\n getRotationPoint: getTargetLabelRotationPoint,\n getRotationOffset: getTargetLabelRotationOffset,\n isVisible: isLabelVisibleAtScale\n });\n var lyrTxrCache = r.data.lyrTxrCache = new LayeredTextureCache(r);\n r.onUpdateEleCalcs(function invalidateTextureCaches(willDraw, eles) {\n // each cache should check for sub-key diff to see that the update affects that cache particularly\n eleTxrCache.invalidateElements(eles);\n lblTxrCache.invalidateElements(eles);\n slbTxrCache.invalidateElements(eles);\n tlbTxrCache.invalidateElements(eles); // any change invalidates the layers\n\n lyrTxrCache.invalidateElements(eles); // update the old bg timestamp so diffs can be done in the ele txr caches\n\n for (var _i = 0; _i < eles.length; _i++) {\n var _p = eles[_i]._private;\n _p.oldBackgroundTimestamp = _p.backgroundTimestamp;\n }\n });\n\n var refineInLayers = function refineInLayers(reqs) {\n for (var i = 0; i < reqs.length; i++) {\n lyrTxrCache.enqueueElementRefinement(reqs[i].ele);\n }\n };\n\n eleTxrCache.onDequeue(refineInLayers);\n lblTxrCache.onDequeue(refineInLayers);\n slbTxrCache.onDequeue(refineInLayers);\n tlbTxrCache.onDequeue(refineInLayers);\n }\n\n CRp.redrawHint = function (group, bool) {\n var r = this;\n\n switch (group) {\n case 'eles':\n r.data.canvasNeedsRedraw[CRp.NODE] = bool;\n break;\n\n case 'drag':\n r.data.canvasNeedsRedraw[CRp.DRAG] = bool;\n break;\n\n case 'select':\n r.data.canvasNeedsRedraw[CRp.SELECT_BOX] = bool;\n break;\n }\n }; // whether to use Path2D caching for drawing\n\n\n var pathsImpld = typeof Path2D !== 'undefined';\n\n CRp.path2dEnabled = function (on) {\n if (on === undefined) {\n return this.pathsEnabled;\n }\n\n this.pathsEnabled = on ? true : false;\n };\n\n CRp.usePaths = function () {\n return pathsImpld && this.pathsEnabled;\n };\n\n CRp.setImgSmoothing = function (context, bool) {\n if (context.imageSmoothingEnabled != null) {\n context.imageSmoothingEnabled = bool;\n } else {\n context.webkitImageSmoothingEnabled = bool;\n context.mozImageSmoothingEnabled = bool;\n context.msImageSmoothingEnabled = bool;\n }\n };\n\n CRp.getImgSmoothing = function (context) {\n if (context.imageSmoothingEnabled != null) {\n return context.imageSmoothingEnabled;\n } else {\n return context.webkitImageSmoothingEnabled || context.mozImageSmoothingEnabled || context.msImageSmoothingEnabled;\n }\n };\n\n CRp.makeOffscreenCanvas = function (width, height) {\n var canvas;\n\n if ((typeof OffscreenCanvas === \"undefined\" ? \"undefined\" : _typeof(OffscreenCanvas)) !== (\"undefined\" )) {\n canvas = new OffscreenCanvas(width, height);\n } else {\n canvas = document.createElement('canvas'); // eslint-disable-line no-undef\n\n canvas.width = width;\n canvas.height = height;\n }\n\n return canvas;\n };\n\n [CRp$a, CRp$9, CRp$8, CRp$7, CRp$6, CRp$5, CRp$4, CRp$3, CRp$2, CRp$1].forEach(function (props) {\n extend(CRp, props);\n });\n\n var renderer = [{\n name: 'null',\n impl: NullRenderer\n }, {\n name: 'base',\n impl: BR\n }, {\n name: 'canvas',\n impl: CR\n }];\n\n var incExts = [{\n type: 'layout',\n extensions: layout\n }, {\n type: 'renderer',\n extensions: renderer\n }];\n\n var extensions = {}; // registered modules for extensions, indexed by name\n\n var modules = {};\n\n function setExtension(type, name, registrant) {\n var ext = registrant;\n\n var overrideErr = function overrideErr(field) {\n warn('Can not register `' + name + '` for `' + type + '` since `' + field + '` already exists in the prototype and can not be overridden');\n };\n\n if (type === 'core') {\n if (Core.prototype[name]) {\n return overrideErr(name);\n } else {\n Core.prototype[name] = registrant;\n }\n } else if (type === 'collection') {\n if (Collection.prototype[name]) {\n return overrideErr(name);\n } else {\n Collection.prototype[name] = registrant;\n }\n } else if (type === 'layout') {\n // fill in missing layout functions in the prototype\n var Layout = function Layout(options) {\n this.options = options;\n registrant.call(this, options); // make sure layout has _private for use w/ std apis like .on()\n\n if (!plainObject(this._private)) {\n this._private = {};\n }\n\n this._private.cy = options.cy;\n this._private.listeners = [];\n this.createEmitter();\n };\n\n var layoutProto = Layout.prototype = Object.create(registrant.prototype);\n var optLayoutFns = [];\n\n for (var i = 0; i < optLayoutFns.length; i++) {\n var fnName = optLayoutFns[i];\n\n layoutProto[fnName] = layoutProto[fnName] || function () {\n return this;\n };\n } // either .start() or .run() is defined, so autogen the other\n\n\n if (layoutProto.start && !layoutProto.run) {\n layoutProto.run = function () {\n this.start();\n return this;\n };\n } else if (!layoutProto.start && layoutProto.run) {\n layoutProto.start = function () {\n this.run();\n return this;\n };\n }\n\n var regStop = registrant.prototype.stop;\n\n layoutProto.stop = function () {\n var opts = this.options;\n\n if (opts && opts.animate) {\n var anis = this.animations;\n\n if (anis) {\n for (var _i = 0; _i < anis.length; _i++) {\n anis[_i].stop();\n }\n }\n }\n\n if (regStop) {\n regStop.call(this);\n } else {\n this.emit('layoutstop');\n }\n\n return this;\n };\n\n if (!layoutProto.destroy) {\n layoutProto.destroy = function () {\n return this;\n };\n }\n\n layoutProto.cy = function () {\n return this._private.cy;\n };\n\n var getCy = function getCy(layout) {\n return layout._private.cy;\n };\n\n var emitterOpts = {\n addEventFields: function addEventFields(layout, evt) {\n evt.layout = layout;\n evt.cy = getCy(layout);\n evt.target = layout;\n },\n bubble: function bubble() {\n return true;\n },\n parent: function parent(layout) {\n return getCy(layout);\n }\n };\n extend(layoutProto, {\n createEmitter: function createEmitter() {\n this._private.emitter = new Emitter(emitterOpts, this);\n return this;\n },\n emitter: function emitter() {\n return this._private.emitter;\n },\n on: function on(evt, cb) {\n this.emitter().on(evt, cb);\n return this;\n },\n one: function one(evt, cb) {\n this.emitter().one(evt, cb);\n return this;\n },\n once: function once(evt, cb) {\n this.emitter().one(evt, cb);\n return this;\n },\n removeListener: function removeListener(evt, cb) {\n this.emitter().removeListener(evt, cb);\n return this;\n },\n removeAllListeners: function removeAllListeners() {\n this.emitter().removeAllListeners();\n return this;\n },\n emit: function emit(evt, params) {\n this.emitter().emit(evt, params);\n return this;\n }\n });\n define.eventAliasesOn(layoutProto);\n ext = Layout; // replace with our wrapped layout\n } else if (type === 'renderer' && name !== 'null' && name !== 'base') {\n // user registered renderers inherit from base\n var BaseRenderer = getExtension('renderer', 'base');\n var bProto = BaseRenderer.prototype;\n var RegistrantRenderer = registrant;\n var rProto = registrant.prototype;\n\n var Renderer = function Renderer() {\n BaseRenderer.apply(this, arguments);\n RegistrantRenderer.apply(this, arguments);\n };\n\n var proto = Renderer.prototype;\n\n for (var pName in bProto) {\n var pVal = bProto[pName];\n var existsInR = rProto[pName] != null;\n\n if (existsInR) {\n return overrideErr(pName);\n }\n\n proto[pName] = pVal; // take impl from base\n }\n\n for (var _pName in rProto) {\n proto[_pName] = rProto[_pName]; // take impl from registrant\n }\n\n bProto.clientFunctions.forEach(function (name) {\n proto[name] = proto[name] || function () {\n error('Renderer does not implement `renderer.' + name + '()` on its prototype');\n };\n });\n ext = Renderer;\n } else if (type === '__proto__' || type === 'constructor' || type === 'prototype') {\n // to avoid potential prototype pollution\n return error(type + ' is an illegal type to be registered, possibly lead to prototype pollutions');\n }\n\n return setMap({\n map: extensions,\n keys: [type, name],\n value: ext\n });\n }\n\n function getExtension(type, name) {\n return getMap({\n map: extensions,\n keys: [type, name]\n });\n }\n\n function setModule(type, name, moduleType, moduleName, registrant) {\n return setMap({\n map: modules,\n keys: [type, name, moduleType, moduleName],\n value: registrant\n });\n }\n\n function getModule(type, name, moduleType, moduleName) {\n return getMap({\n map: modules,\n keys: [type, name, moduleType, moduleName]\n });\n }\n\n var extension = function extension() {\n // e.g. extension('renderer', 'svg')\n if (arguments.length === 2) {\n return getExtension.apply(null, arguments);\n } // e.g. extension('renderer', 'svg', { ... })\n else if (arguments.length === 3) {\n return setExtension.apply(null, arguments);\n } // e.g. extension('renderer', 'svg', 'nodeShape', 'ellipse')\n else if (arguments.length === 4) {\n return getModule.apply(null, arguments);\n } // e.g. extension('renderer', 'svg', 'nodeShape', 'ellipse', { ... })\n else if (arguments.length === 5) {\n return setModule.apply(null, arguments);\n } else {\n error('Invalid extension access syntax');\n }\n }; // allows a core instance to access extensions internally\n\n\n Core.prototype.extension = extension; // included extensions\n\n incExts.forEach(function (group) {\n group.extensions.forEach(function (ext) {\n setExtension(group.type, ext.name, ext.impl);\n });\n });\n\n // (useful for init)\n\n var Stylesheet = function Stylesheet() {\n if (!(this instanceof Stylesheet)) {\n return new Stylesheet();\n }\n\n this.length = 0;\n };\n\n var sheetfn = Stylesheet.prototype;\n\n sheetfn.instanceString = function () {\n return 'stylesheet';\n }; // just store the selector to be parsed later\n\n\n sheetfn.selector = function (selector) {\n var i = this.length++;\n this[i] = {\n selector: selector,\n properties: []\n };\n return this; // chaining\n }; // just store the property to be parsed later\n\n\n sheetfn.css = function (name, value) {\n var i = this.length - 1;\n\n if (string(name)) {\n this[i].properties.push({\n name: name,\n value: value\n });\n } else if (plainObject(name)) {\n var map = name;\n var propNames = Object.keys(map);\n\n for (var j = 0; j < propNames.length; j++) {\n var key = propNames[j];\n var mapVal = map[key];\n\n if (mapVal == null) {\n continue;\n }\n\n var prop = Style.properties[key] || Style.properties[dash2camel(key)];\n\n if (prop == null) {\n continue;\n }\n\n var _name = prop.name;\n var _value = mapVal;\n this[i].properties.push({\n name: _name,\n value: _value\n });\n }\n }\n\n return this; // chaining\n };\n\n sheetfn.style = sheetfn.css; // generate a real style object from the dummy stylesheet\n\n sheetfn.generateStyle = function (cy) {\n var style = new Style(cy);\n return this.appendToStyle(style);\n }; // append a dummy stylesheet object on a real style object\n\n\n sheetfn.appendToStyle = function (style) {\n for (var i = 0; i < this.length; i++) {\n var context = this[i];\n var selector = context.selector;\n var props = context.properties;\n style.selector(selector); // apply selector\n\n for (var j = 0; j < props.length; j++) {\n var prop = props[j];\n style.css(prop.name, prop.value); // apply property\n }\n }\n\n return style;\n };\n\n var version = \"3.26.0\";\n\n var cytoscape = function cytoscape(options) {\n // if no options specified, use default\n if (options === undefined) {\n options = {};\n } // create instance\n\n\n if (plainObject(options)) {\n return new Core(options);\n } // allow for registration of extensions\n else if (string(options)) {\n return extension.apply(extension, arguments);\n }\n }; // e.g. cytoscape.use( require('cytoscape-foo'), bar )\n\n\n cytoscape.use = function (ext) {\n var args = Array.prototype.slice.call(arguments, 1); // args to pass to ext\n\n args.unshift(cytoscape); // cytoscape is first arg to ext\n\n ext.apply(null, args);\n return this;\n };\n\n cytoscape.warnings = function (bool) {\n return warnings(bool);\n }; // replaced by build system\n\n\n cytoscape.version = version; // expose public apis (mostly for extensions)\n\n cytoscape.stylesheet = cytoscape.Stylesheet = Stylesheet;\n\n return cytoscape;\n\n}));\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2N5dG9zY2FwZS9kaXN0L2N5dG9zY2FwZS51bWQuanMuanMiLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRSxLQUE0RDtBQUM5RCxFQUFFLENBQ3dHO0FBQzFHLENBQUMsdUJBQXVCOztBQUV4QjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG9CQUFvQixrQkFBa0I7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLE1BQU07QUFDTjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsOEJBQThCLCtCQUErQjtBQUM3RDs7QUFFQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsMkNBQTJDLFNBQVM7O0FBRXBEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLCtEQUErRDs7QUFFL0Q7QUFDQTs7QUFFQTs7QUFFQSw0QkFBNEI7O0FBRTVCLHVDQUF1Qzs7QUFFdkM7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtB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QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxvQkFBb0IsT0FBTztBQUMzQjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsb0JBQW9CLE9BQU87QUFDM0I7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FB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QTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNOzs7QUFHTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBOztBQUVBLHdDQUF3QyxPQUFPO0FBQy9DOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHVDQUF1Qzs7O0FBR3ZDLHNCQUFzQixjQUFjO0FBQ3BDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFNBQVM7O0FBRVQsMEJBQTBCLHNCQUFzQjtBQUNoRDtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsdUJBQXVCLDRCQUE0QjtBQUNuRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOzs7QUFHTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTCxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlEQUF5RCxtQ0FBbUMsMEJBQTBCO0FBQ3RIO0FBQ0EsT0FBTztBQUNQO0FBQ0Esd0NBQXdDLFdBQVc7QUFDbkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QyxXQUFXO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5Q0FBeUMsV0FBVztBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaURBQWlELHNDQUFzQztBQUN2RjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxLQUFLOztBQUVMLEdBQUc7QUFDSCxHQUFHOztBQUVI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QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCOztBQUUzQjs7QUFFQSxvQkFBb0IsWUFBWTtBQUNoQztBQUNBLE1BQU07OztBQUdOLHFCQUFxQixhQUFhO0FBQ2xDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7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QUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0EsU0FBUztBQUNULE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZTtBQUNmOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUEsZUFBZTtBQUNmO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQSxpR0FBaUc7QUFDakc7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0Esc0JBQXNCLHFCQUFxQjtBQUMzQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7O0FBR0EsK0RBQStEO0FBQy9EO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFF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QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUEsb0JBQW9CLDJCQUEyQjtBQUMvQztBQUNBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQzs7QUFFbEM7QUFDQSx3QkFBd0I7QUFDeEI7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FB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O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsNkJBQTZCOztBQUU3QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxvQkFBb0IsaUJBQWlCO0FBQ3JDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07OztBQUdOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztB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QUVBOztBQUVBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7O0FBRVIsTUFBTTs7O0FBR047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsdURBQXVEOztBQUV2RDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLE1BQU07OztBQUdOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx3QkFBd0IsaUJBQWlCO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsdUJBQXVCLGtCQUFrQjtBQUN6QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esb0JBQW9CLGlCQUFpQjtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQztBQUMxQzs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQztBQUMxQzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDJEQUEyRDs7QUFFM0Q7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsR0FBRyxJQUFJOztBQUVQLDRCQUE0Qjs7QUFFNUI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7OztBQUdKO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSw4QkFBOEI7QUFDOUIsNkNBQTZDOztBQUU3QztBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxRQUFROzs7QUFHUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSw4Q0FBOEM7O0FBRTlDLGlDQUFpQzs7QUFFakM7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSx1QkFBdUI7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0Esa0JBQWtCO0FBQ2xCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG9CQUFvQix5QkFBeUI7QUFDN0M7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSLHdCQUF3QjtBQUN4QjtBQUNBOztBQUVBOztBQUVBLG9CQUFvQixzQkFBc0I7QUFDMUM7O0FBRUE7QUFDQTtBQUNBOztBQUVBLHlDQUF5Qzs7QUFFekM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFVBQVU7O0FBRVY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxvQkFBb0Isc0JBQXNCO0FBQzFDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSx5Q0FBeUM7O0FBRXpDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxTQUFTO0FBQ1Q7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBLHVDQUF1QyxRQUFRO0FBQy9DO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTs7QUFFVjs7QUFFQSxzQkFBc0IsNEJBQTRCO0FBQ2xEO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHNCQUFzQixpQkFBaUI7QUFDdkM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7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QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUEsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtCQUErQjtBQUMvQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUEsc0JBQXNCLGdCQUFnQjtBQUN0QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsdUNBQXVDO0FBQ3ZDOztBQUVBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSx3QkFBd0Isa0JBQWtCO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTs7O0FBR1Y7QUFDQSxRQUFROztBQUVSOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQjs7QUFFM0I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDRDQUE0QyxRQUFRO0FBQ3BEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFNBQVM7OztBQUdULHVDQUF1QyxRQUFRO0FBQy9DO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsVUFBVTs7O0FBR1Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsTUFBTTtBQUNOOzs7QUFHQTs7QUFFQSxvQkFBb0IsaUJBQWlCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBLE1BQU07OztBQUdOLHdDQUF3Qzs7QUFFeEM7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxNQUFNOzs7QUFHTjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxRQUFROzs7QUFHUjtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFR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Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QjtBQUN2Qjs7QUFFQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSxpQ0FBaUM7QUFDakMsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUssR0FBRzs7QUFFUjtBQUNBLGlDQUFpQzs7QUFFakM7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTCxvQkFBb0IsNkJBQTZCO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLE1BQU07OztBQUdOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FB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QixLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBLG1CQUFtQjtBQUNuQixLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQSxtQkFBbUI7QUFDbkIsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBLG1CQUFtQjtBQUNuQixLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLHNCQUFzQixjQUFjO0FBQ3BDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxtQkFBbUI7QUFDbkIsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsY0FBYztBQUN0QztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQjtBQUNuQixLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxtQkFBbUI7QUFDbkIsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw2RUFBNkU7O0FBRTdFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlOztBQUVmO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQSxvREFBb0Q7O0FBRXBEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUI7O0FBRXZCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxPQUFPO0FBQ1AsbUJBQW1CO0FBQ25CLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLEtBQUs7QUFDTDtBQUNB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QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxzQkFBc0IsZ0JBQWdCO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxzQkFBc0IsZ0JBQWdCO0FBQ3RDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7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Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLG9CQUFvQixrQkFBa0I7QUFDdEM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUM7O0FBRW5DO0FBQ0E7QUFDQSxtREFBbUQ7O0FBRW5EO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG9CQUFvQixlQUFlO0FBQ25DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsMkNBQTJDOztBQUUzQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEM7O0FBRTFDO0FBQ0E7QUFDQTs7QUFFQSxvQkFBb0IsYUFBYTtBQUNqQztBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzRUFBc0U7O0FBRXRFO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhCQUE4Qjs7QUFFOUI7QUFDQTtBQUNBO0FBQ0EsNENBQTRDOztBQUU1QztBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQzs7QUFFckM7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHFDQUFxQzs7QUFFckM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQSw0QkFBNEI7QUFDNUI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDREQUE0RDs7QUFFNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDRCQUE0QjtBQUM1Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGlFQUFpRTs7O0FBR2pFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsc0JBQXNCLDJCQUEyQjtBQUNqRDtBQUNBLDBEQUEwRDs7QUFFMUQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsNERBQTREOztBQUU1RDtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCOztBQUU1QixvQkFBb0Isa0JBQWtCO0FBQ3RDO0FBQ0E7QUFDQSx5REFBeUQ7QUFDekQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTiw4QkFBOEI7OztBQUc5QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsU0FBUyxHQUFHOztBQUVaO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBLG9DQUFvQzs7QUFFcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsd0JBQXdCLDRCQUE0QjtBQUNwRDtBQUNBOztBQUVBOztBQUVBLDJIQUEySDs7O0FBRzNIOztBQUVBO0FBQ0Esa0RBQWtEOztBQUVsRDtBQUNBLHVEQUF1RDs7QUFFdkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhOztBQUViO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQSxVQUFVO0FBQ1Y7QUFDQSxVQUFVO0FBQ1Y7QUFDQSxVQUFVO0FBQ1Y7QUFDQSxVQUFVO0FBQ1Y7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLFFBQVE7O0FBRVI7O0FBRUEsb0JBQW9CLG9CQUFvQjtBQUN4QztBQUNBLE1BQU07QUFDTjs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxvQkFBb0IsZ0JBQWdCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLG9DQUFvQzs7QUFFcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7O0FBRVosWUFBWTs7QUFFWixjQUFjOztBQUVkLGNBQWM7O0FBRWQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxNQUFNO0FBQ04sOEJBQThCO0FBQzlCLE1BQU07QUFDTjtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7O0FBRWI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxNQUFNO0FBQ04sOEJBQThCO0FBQzlCLE1BQU07QUFDTjtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7O0FBRWI7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QUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsOEJBQThCLGFBQWE7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsT0FBTzs7O0FBR1A7QUFDQTtBQUNBOztBQUVBLG1DQUFtQztBQUNuQztBQUNBLE1BQU07QUFDTjtBQUNBOztBQUVBOztBQUVBO0FBQ0EsMkNBQTJDOztBQUUzQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxzQkFBc0Isa0JBQWtCO0FBQ3hDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwwQkFBMEIsa0JBQWtCO0FBQzVDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTs7O0FBR1o7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTs7QUFF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QUdOLDREQUE0RDs7QUFFNUQ7QUFDQSx1REFBdUQ7O0FBRXZEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUssR0FBRzs7QUFFUjtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHNCQUFzQixzQkFBc0I7QUFDNUM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxRQUFROzs7QUFHUjtBQUNBLE9BQU87OztBQUdQO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZTtBQUNmLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWU7QUFDZjtBQUNBO0FBQ0EsU0FBUztBQUNULFNBQVM7OztBQUdUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7O0FBRUE7QUFDQSx3Q0FBd0M7QUFDeEMsUUFBUTtBQUNSO0FBQ0E7QUFDQSxVQUFVOzs7QUFHVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtB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QUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7OztBQUdWO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLFVBQVU7OztBQUdWO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxVQUFVOzs7QUFHVjtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsVUFBVTs7O0FBR1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxvQkFBb0IsdUJBQXVCO0FBQzNDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxxQ0FBcUM7O0FBRXJDO0FBQ0E7QUFDQSxVQUFVOzs7QUFHVjtBQUNBO0FBQ0EsVUFBVTs7O0FBR1Y7QUFDQTtBQUNBLFVBQVU7OztBQUdWO0FBQ0E7QUFDQSxVQUFVOzs7QUFHVjtBQUNBO0FBQ0EsVUFBVTs7O0FBR1Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FB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QTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSw2Q0FBNkM7O0FBRTdDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSwrQ0FBK0M7O0FBRS9DO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUTs7QUFFUixLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EseUNBQXlDOztBQUV6QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FB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QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixvQkFBb0I7QUFDOUM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkIscUJBQXFCO0FBQ2hEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxNQUFNOzs7QUFHTjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG9CQUFvQixvQkFBb0I7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNOzs7QUFHTjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEM7O0FBRTFDO0FBQ0Esc0NBQXNDOztBQUV0QztBQUNBO0FBQ0Esc0NBQXNDO0FBQ3RDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0EsY0FBYztBQUNkOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdDQUFnQzs7QUFFaEM7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7O0FBRUEsZ0NBQWdDOztBQUVoQztBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBaUQ7O0FBRWpEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxvQkFBb0IsNEJBQTRCO0FBQ2hEOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQzs7QUFFaEM7QUFDQTtBQUNBLEtBQUs7OztBQUdMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE1BQU07OztBQUdOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNEJBQTRCOztBQUU1Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx5REFBeUQ7O0FBRXpEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxvRUFBb0U7O0FBRXBFO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHdDQUF3QztBQUN4QztBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQSxZQUFZOztBQUVaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQSxZQUFZOztBQUVaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQSxZQUFZOztBQUVaOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsd0JBQXdCLGtCQUFrQjtBQUMxQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFD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QSxNQUFNOzs7QUFHTjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNB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QUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNENBQTRDOztBQUU1Qyw0Q0FBNEM7O0FBRTVDLHVCQUF1QixrQkFBa0I7QUFDekM7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLHNCQUFzQixpQkFBaUI7QUFDdkM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOzs7QUFHTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE1BQU07QUFDTixpREFBaUQ7O0FBRWpEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsR0FBRzs7QUFFSCx1QkFBdUI7O0FBRXZCOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQSx3Q0FBd0M7O0FBRXhDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLHNCQUFzQix5QkFBeUI7QUFDL0M7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDZCQUE2QixrQkFBa0I7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLG9CQUFvQjtBQUNwQixNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDZCQUE2QjtBQUM3Qjs7QUFFQTtBQUNBLHdDQUF3QztBQUN4Qzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU0sdUNBQXVDLEtBQUs7QUFDbEQ7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsTUFBTSwrREFBK0QsS0FBSztBQUMxRTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxLQUFLOzs7QUFHTCx3Q0FBd0M7O0FBRXhDO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEtBQUs7OztBQUdMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixLQUFLOzs7QUFHTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLE1BQU07QUFDTjtBQUNBOztBQUVBLHNCQUFzQixzQkFBc0I7QUFDNUM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQSxpQkFBaUI7QUFDakI7O0FBRUEsK0JBQStCOztBQUUvQjtBQUNBO0FBQ0E7QUFDQSxLQUFLOzs7QUFHTDtBQUNBLG9CQUFvQixpQkFBaUI7QUFDckM7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDOztBQUVoQyxzQkFBc0Isa0JBQWtCO0FBQ3hDO0FBQ0EsMENBQTBDO0FBQzFDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07OztBQUdOO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsS0FBSzs7O0FBR0w7QUFDQSx5REFBeUQ7O0FBRXpELDZCQUE2Qjs7QUFFN0I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOzs7QUFHTCwrQkFBK0I7O0FBRS9COztBQUVBOztBQUVBLENBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2N5dG9zY2FwZS9kaXN0L2N5dG9zY2FwZS51bWQuanM/YmY4NSJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBUaGUgQ3l0b3NjYXBlIENvbnNvcnRpdW0uXG4gKlxuICogUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weSBvZlxuICogdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUg4oCcU29mdHdhcmXigJ0pLCB0byBkZWFsIGluXG4gKiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvXG4gKiB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllc1xuICogb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvXG4gKiBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4gKlxuICogVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsXG4gKiBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuICpcbiAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCDigJxBUyBJU+KAnSwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuICogSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4gKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbiAqIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbiAqIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4gKiBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRVxuICogU09GVFdBUkUuXG4gKi9cblxuKGZ1bmN0aW9uIChnbG9iYWwsIGZhY3RvcnkpIHtcbiAgdHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnICYmIHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnID8gbW9kdWxlLmV4cG9ydHMgPSBmYWN0b3J5KCkgOlxuICB0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQgPyBkZWZpbmUoZmFjdG9yeSkgOlxuICAoZ2xvYmFsID0gdHlwZW9mIGdsb2JhbFRoaXMgIT09ICd1bmRlZmluZWQnID8gZ2xvYmFsVGhpcyA6IGdsb2JhbCB8fCBzZWxmLCBnbG9iYWwuY3l0b3NjYXBlID0gZmFjdG9yeSgpKTtcbn0pKHRoaXMsIChmdW5jdGlvbiAoKSB7ICd1c2Ugc3RyaWN0JztcblxuICBmdW5jdGlvbiBfdHlwZW9mKG9iaikge1xuICAgIFwiQGJhYmVsL2hlbHBlcnMgLSB0eXBlb2ZcIjtcblxuICAgIHJldHVybiBfdHlwZW9mID0gXCJmdW5jdGlvblwiID09IHR5cGVvZiBTeW1ib2wgJiYgXCJzeW1ib2xcIiA9PSB0eXBlb2YgU3ltYm9sLml0ZXJhdG9yID8gZnVuY3Rpb24gKG9iaikge1xuICAgICAgcmV0dXJuIHR5cGVvZiBvYmo7XG4gICAgfSA6IGZ1bmN0aW9uIChvYmopIHtcbiAgICAgIHJldHVybiBvYmogJiYgXCJmdW5jdGlvblwiID09IHR5cGVvZiBTeW1ib2wgJiYgb2JqLmNvbnN0cnVjdG9yID09PSBTeW1ib2wgJiYgb2JqICE9PSBTeW1ib2wucHJvdG90eXBlID8gXCJzeW1ib2xcIiA6IHR5cGVvZiBvYmo7XG4gICAgfSwgX3R5cGVvZihvYmopO1xuICB9XG5cbiAgZnVuY3Rpb24gX2NsYXNzQ2FsbENoZWNrKGluc3RhbmNlLCBDb25zdHJ1Y3Rvcikge1xuICAgIGlmICghKGluc3RhbmNlIGluc3RhbmNlb2YgQ29uc3RydWN0b3IpKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uXCIpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIF9kZWZpbmVQcm9wZXJ0aWVzKHRhcmdldCwgcHJvcHMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHByb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZGVzY3JpcHRvciA9IHByb3BzW2ldO1xuICAgICAgZGVzY3JpcHRvci5lbnVtZXJhYmxlID0gZGVzY3JpcHRvci5lbnVtZXJhYmxlIHx8IGZhbHNlO1xuICAgICAgZGVzY3JpcHRvci5jb25maWd1cmFibGUgPSB0cnVlO1xuICAgICAgaWYgKFwidmFsdWVcIiBpbiBkZXNjcmlwdG9yKSBkZXNjcmlwdG9yLndyaXRhYmxlID0gdHJ1ZTtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGRlc2NyaXB0b3Iua2V5LCBkZXNjcmlwdG9yKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBfY3JlYXRlQ2xhc3MoQ29uc3RydWN0b3IsIHByb3RvUHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgaWYgKHByb3RvUHJvcHMpIF9kZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLnByb3RvdHlwZSwgcHJvdG9Qcm9wcyk7XG4gICAgaWYgKHN0YXRpY1Byb3BzKSBfZGVmaW5lUHJvcGVydGllcyhDb25zdHJ1Y3Rvciwgc3RhdGljUHJvcHMpO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShDb25zdHJ1Y3RvciwgXCJwcm90b3R5cGVcIiwge1xuICAgICAgd3JpdGFibGU6IGZhbHNlXG4gICAgfSk7XG4gICAgcmV0dXJuIENvbnN0cnVjdG9yO1xuICB9XG5cbiAgZnVuY3Rpb24gX2RlZmluZVByb3BlcnR5JDEob2JqLCBrZXksIHZhbHVlKSB7XG4gICAgaWYgKGtleSBpbiBvYmopIHtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmosIGtleSwge1xuICAgICAgICB2YWx1ZTogdmFsdWUsXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgd3JpdGFibGU6IHRydWVcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBvYmpba2V5XSA9IHZhbHVlO1xuICAgIH1cblxuICAgIHJldHVybiBvYmo7XG4gIH1cblxuICBmdW5jdGlvbiBfc2xpY2VkVG9BcnJheShhcnIsIGkpIHtcbiAgICByZXR1cm4gX2FycmF5V2l0aEhvbGVzKGFycikgfHwgX2l0ZXJhYmxlVG9BcnJheUxpbWl0KGFyciwgaSkgfHwgX3Vuc3VwcG9ydGVkSXRlcmFibGVUb0FycmF5KGFyciwgaSkgfHwgX25vbkl0ZXJhYmxlUmVzdCgpO1xuICB9XG5cbiAgZnVuY3Rpb24gX2FycmF5V2l0aEhvbGVzKGFycikge1xuICAgIGlmIChBcnJheS5pc0FycmF5KGFycikpIHJldHVybiBhcnI7XG4gIH1cblxuICBmdW5jdGlvbiBfaXRlcmFibGVUb0FycmF5TGltaXQoYXJyLCBpKSB7XG4gICAgdmFyIF9pID0gYXJyID09IG51bGwgPyBudWxsIDogdHlwZW9mIFN5bWJvbCAhPT0gXCJ1bmRlZmluZWRcIiAmJiBhcnJbU3ltYm9sLml0ZXJhdG9yXSB8fCBhcnJbXCJAQGl0ZXJhdG9yXCJdO1xuXG4gICAgaWYgKF9pID09IG51bGwpIHJldHVybjtcbiAgICB2YXIgX2FyciA9IFtdO1xuICAgIHZhciBfbiA9IHRydWU7XG4gICAgdmFyIF9kID0gZmFsc2U7XG5cbiAgICB2YXIgX3MsIF9lO1xuXG4gICAgdHJ5IHtcbiAgICAgIGZvciAoX2kgPSBfaS5jYWxsKGFycik7ICEoX24gPSAoX3MgPSBfaS5uZXh0KCkpLmRvbmUpOyBfbiA9IHRydWUpIHtcbiAgICAgICAgX2Fyci5wdXNoKF9zLnZhbHVlKTtcblxuICAgICAgICBpZiAoaSAmJiBfYXJyLmxlbmd0aCA9PT0gaSkgYnJlYWs7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBfZCA9IHRydWU7XG4gICAgICBfZSA9IGVycjtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKCFfbiAmJiBfaVtcInJldHVyblwiXSAhPSBudWxsKSBfaVtcInJldHVyblwiXSgpO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKF9kKSB0aHJvdyBfZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gX2FycjtcbiAgfVxuXG4gIGZ1bmN0aW9uIF91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheShvLCBtaW5MZW4pIHtcbiAgICBpZiAoIW8pIHJldHVybjtcbiAgICBpZiAodHlwZW9mIG8gPT09IFwic3RyaW5nXCIpIHJldHVybiBfYXJyYXlMaWtlVG9BcnJheShvLCBtaW5MZW4pO1xuICAgIHZhciBuID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG8pLnNsaWNlKDgsIC0xKTtcbiAgICBpZiAobiA9PT0gXCJPYmplY3RcIiAmJiBvLmNvbnN0cnVjdG9yKSBuID0gby5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgIGlmIChuID09PSBcIk1hcFwiIHx8IG4gPT09IFwiU2V0XCIpIHJldHVybiBBcnJheS5mcm9tKG8pO1xuICAgIGlmIChuID09PSBcIkFyZ3VtZW50c1wiIHx8IC9eKD86VWl8SSludCg/Ojh8MTZ8MzIpKD86Q2xhbXBlZCk/QXJyYXkkLy50ZXN0KG4pKSByZXR1cm4gX2FycmF5TGlrZVRvQXJyYXkobywgbWluTGVuKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIF9hcnJheUxpa2VUb0FycmF5KGFyciwgbGVuKSB7XG4gICAgaWYgKGxlbiA9PSBudWxsIHx8IGxlbiA+IGFyci5sZW5ndGgpIGxlbiA9IGFyci5sZW5ndGg7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgYXJyMiA9IG5ldyBBcnJheShsZW4pOyBpIDwgbGVuOyBpKyspIGFycjJbaV0gPSBhcnJbaV07XG5cbiAgICByZXR1cm4gYXJyMjtcbiAgfVxuXG4gIGZ1bmN0aW9uIF9ub25JdGVyYWJsZVJlc3QoKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkludmFsaWQgYXR0ZW1wdCB0byBkZXN0cnVjdHVyZSBub24taXRlcmFibGUgaW5zdGFuY2UuXFxuSW4gb3JkZXIgdG8gYmUgaXRlcmFibGUsIG5vbi1hcnJheSBvYmplY3RzIG11c3QgaGF2ZSBhIFtTeW1ib2wuaXRlcmF0b3JdKCkgbWV0aG9kLlwiKTtcbiAgfVxuXG4gIHZhciBfd2luZG93ID0gdHlwZW9mIHdpbmRvdyA9PT0gJ3VuZGVmaW5lZCcgPyBudWxsIDogd2luZG93OyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cbiAgdmFyIG5hdmlnYXRvciA9IF93aW5kb3cgPyBfd2luZG93Lm5hdmlnYXRvciA6IG51bGw7XG4gIF93aW5kb3cgPyBfd2luZG93LmRvY3VtZW50IDogbnVsbDtcblxuICB2YXIgdHlwZW9mc3RyID0gX3R5cGVvZignJyk7XG5cbiAgdmFyIHR5cGVvZm9iaiA9IF90eXBlb2Yoe30pO1xuXG4gIHZhciB0eXBlb2ZmbiA9IF90eXBlb2YoZnVuY3Rpb24gKCkge30pO1xuXG4gIHZhciB0eXBlb2ZodG1sZWxlID0gdHlwZW9mIEhUTUxFbGVtZW50ID09PSBcInVuZGVmaW5lZFwiID8gXCJ1bmRlZmluZWRcIiA6IF90eXBlb2YoSFRNTEVsZW1lbnQpO1xuXG4gIHZhciBpbnN0YW5jZVN0ciA9IGZ1bmN0aW9uIGluc3RhbmNlU3RyKG9iaikge1xuICAgIHJldHVybiBvYmogJiYgb2JqLmluc3RhbmNlU3RyaW5nICYmIGZuJDYob2JqLmluc3RhbmNlU3RyaW5nKSA/IG9iai5pbnN0YW5jZVN0cmluZygpIDogbnVsbDtcbiAgfTtcblxuICB2YXIgc3RyaW5nID0gZnVuY3Rpb24gc3RyaW5nKG9iaikge1xuICAgIHJldHVybiBvYmogIT0gbnVsbCAmJiBfdHlwZW9mKG9iaikgPT0gdHlwZW9mc3RyO1xuICB9O1xuICB2YXIgZm4kNiA9IGZ1bmN0aW9uIGZuKG9iaikge1xuICAgIHJldHVybiBvYmogIT0gbnVsbCAmJiBfdHlwZW9mKG9iaikgPT09IHR5cGVvZmZuO1xuICB9O1xuICB2YXIgYXJyYXkgPSBmdW5jdGlvbiBhcnJheShvYmopIHtcbiAgICByZXR1cm4gIWVsZW1lbnRPckNvbGxlY3Rpb24ob2JqKSAmJiAoQXJyYXkuaXNBcnJheSA/IEFycmF5LmlzQXJyYXkob2JqKSA6IG9iaiAhPSBudWxsICYmIG9iaiBpbnN0YW5jZW9mIEFycmF5KTtcbiAgfTtcbiAgdmFyIHBsYWluT2JqZWN0ID0gZnVuY3Rpb24gcGxhaW5PYmplY3Qob2JqKSB7XG4gICAgcmV0dXJuIG9iaiAhPSBudWxsICYmIF90eXBlb2Yob2JqKSA9PT0gdHlwZW9mb2JqICYmICFhcnJheShvYmopICYmIG9iai5jb25zdHJ1Y3RvciA9PT0gT2JqZWN0O1xuICB9O1xuICB2YXIgb2JqZWN0ID0gZnVuY3Rpb24gb2JqZWN0KG9iaikge1xuICAgIHJldHVybiBvYmogIT0gbnVsbCAmJiBfdHlwZW9mKG9iaikgPT09IHR5cGVvZm9iajtcbiAgfTtcbiAgdmFyIG51bWJlciQxID0gZnVuY3Rpb24gbnVtYmVyKG9iaikge1xuICAgIHJldHVybiBvYmogIT0gbnVsbCAmJiBfdHlwZW9mKG9iaikgPT09IF90eXBlb2YoMSkgJiYgIWlzTmFOKG9iaik7XG4gIH07XG4gIHZhciBpbnRlZ2VyID0gZnVuY3Rpb24gaW50ZWdlcihvYmopIHtcbiAgICByZXR1cm4gbnVtYmVyJDEob2JqKSAmJiBNYXRoLmZsb29yKG9iaikgPT09IG9iajtcbiAgfTtcbiAgdmFyIGh0bWxFbGVtZW50ID0gZnVuY3Rpb24gaHRtbEVsZW1lbnQob2JqKSB7XG4gICAgaWYgKCd1bmRlZmluZWQnID09PSB0eXBlb2ZodG1sZWxlKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gbnVsbCAhPSBvYmogJiYgb2JqIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQ7XG4gICAgfVxuICB9O1xuICB2YXIgZWxlbWVudE9yQ29sbGVjdGlvbiA9IGZ1bmN0aW9uIGVsZW1lbnRPckNvbGxlY3Rpb24ob2JqKSB7XG4gICAgcmV0dXJuIGVsZW1lbnQob2JqKSB8fCBjb2xsZWN0aW9uKG9iaik7XG4gIH07XG4gIHZhciBlbGVtZW50ID0gZnVuY3Rpb24gZWxlbWVudChvYmopIHtcbiAgICByZXR1cm4gaW5zdGFuY2VTdHIob2JqKSA9PT0gJ2NvbGxlY3Rpb24nICYmIG9iai5fcHJpdmF0ZS5zaW5nbGU7XG4gIH07XG4gIHZhciBjb2xsZWN0aW9uID0gZnVuY3Rpb24gY29sbGVjdGlvbihvYmopIHtcbiAgICByZXR1cm4gaW5zdGFuY2VTdHIob2JqKSA9PT0gJ2NvbGxlY3Rpb24nICYmICFvYmouX3ByaXZhdGUuc2luZ2xlO1xuICB9O1xuICB2YXIgY29yZSA9IGZ1bmN0aW9uIGNvcmUob2JqKSB7XG4gICAgcmV0dXJuIGluc3RhbmNlU3RyKG9iaikgPT09ICdjb3JlJztcbiAgfTtcbiAgdmFyIHN0eWxlc2hlZXQgPSBmdW5jdGlvbiBzdHlsZXNoZWV0KG9iaikge1xuICAgIHJldHVybiBpbnN0YW5jZVN0cihvYmopID09PSAnc3R5bGVzaGVldCc7XG4gIH07XG4gIHZhciBldmVudCA9IGZ1bmN0aW9uIGV2ZW50KG9iaikge1xuICAgIHJldHVybiBpbnN0YW5jZVN0cihvYmopID09PSAnZXZlbnQnO1xuICB9O1xuICB2YXIgZW1wdHlTdHJpbmcgPSBmdW5jdGlvbiBlbXB0eVN0cmluZyhvYmopIHtcbiAgICBpZiAob2JqID09PSB1bmRlZmluZWQgfHwgb2JqID09PSBudWxsKSB7XG4gICAgICAvLyBudWxsIGlzIGVtcHR5XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKG9iaiA9PT0gJycgfHwgb2JqLm1hdGNoKC9eXFxzKyQvKSkge1xuICAgICAgcmV0dXJuIHRydWU7IC8vIGVtcHR5IHN0cmluZyBpcyBlbXB0eVxuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTsgLy8gb3RoZXJ3aXNlLCB3ZSBkb24ndCBrbm93IHdoYXQgd2UndmUgZ290XG4gIH07XG4gIHZhciBkb21FbGVtZW50ID0gZnVuY3Rpb24gZG9tRWxlbWVudChvYmopIHtcbiAgICBpZiAodHlwZW9mIEhUTUxFbGVtZW50ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuIGZhbHNlOyAvLyB3ZSdyZSBub3QgaW4gYSBicm93c2VyIHNvIGl0IGRvZXNuJ3QgbWF0dGVyXG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBvYmogaW5zdGFuY2VvZiBIVE1MRWxlbWVudDtcbiAgICB9XG4gIH07XG4gIHZhciBib3VuZGluZ0JveCA9IGZ1bmN0aW9uIGJvdW5kaW5nQm94KG9iaikge1xuICAgIHJldHVybiBwbGFpbk9iamVjdChvYmopICYmIG51bWJlciQxKG9iai54MSkgJiYgbnVtYmVyJDEob2JqLngyKSAmJiBudW1iZXIkMShvYmoueTEpICYmIG51bWJlciQxKG9iai55Mik7XG4gIH07XG4gIHZhciBwcm9taXNlID0gZnVuY3Rpb24gcHJvbWlzZShvYmopIHtcbiAgICByZXR1cm4gb2JqZWN0KG9iaikgJiYgZm4kNihvYmoudGhlbik7XG4gIH07XG4gIHZhciBtcyA9IGZ1bmN0aW9uIG1zKCkge1xuICAgIHJldHVybiBuYXZpZ2F0b3IgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvbXNpZXx0cmlkZW50fGVkZ2UvaSk7XG4gIH07IC8vIHByb2JhYmx5IGEgYmV0dGVyIHdheSB0byBkZXRlY3QgdGhpcy4uLlxuXG4gIHZhciBtZW1vaXplJDEgPSBmdW5jdGlvbiBtZW1vaXplKGZuLCBrZXlGbikge1xuICAgIGlmICgha2V5Rm4pIHtcbiAgICAgIGtleUZuID0gZnVuY3Rpb24ga2V5Rm4oKSB7XG4gICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgcmV0dXJuIGFyZ3VtZW50c1swXTtcbiAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgcmV0dXJuICd1bmRlZmluZWQnO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGFyZ3MgPSBbXTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGFyZ3MucHVzaChhcmd1bWVudHNbaV0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGFyZ3Muam9pbignJCcpO1xuICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgbWVtb2l6ZWRGbiA9IGZ1bmN0aW9uIG1lbW9pemVkRm4oKSB7XG4gICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICB2YXIgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgIHZhciByZXQ7XG4gICAgICB2YXIgayA9IGtleUZuLmFwcGx5KHNlbGYsIGFyZ3MpO1xuICAgICAgdmFyIGNhY2hlID0gbWVtb2l6ZWRGbi5jYWNoZTtcblxuICAgICAgaWYgKCEocmV0ID0gY2FjaGVba10pKSB7XG4gICAgICAgIHJldCA9IGNhY2hlW2tdID0gZm4uYXBwbHkoc2VsZiwgYXJncyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZXQ7XG4gICAgfTtcblxuICAgIG1lbW9pemVkRm4uY2FjaGUgPSB7fTtcbiAgICByZXR1cm4gbWVtb2l6ZWRGbjtcbiAgfTtcblxuICB2YXIgY2FtZWwyZGFzaCA9IG1lbW9pemUkMShmdW5jdGlvbiAoc3RyKSB7XG4gICAgcmV0dXJuIHN0ci5yZXBsYWNlKC8oW0EtWl0pL2csIGZ1bmN0aW9uICh2KSB7XG4gICAgICByZXR1cm4gJy0nICsgdi50b0xvd2VyQ2FzZSgpO1xuICAgIH0pO1xuICB9KTtcbiAgdmFyIGRhc2gyY2FtZWwgPSBtZW1vaXplJDEoZnVuY3Rpb24gKHN0cikge1xuICAgIHJldHVybiBzdHIucmVwbGFjZSgvKC1cXHcpL2csIGZ1bmN0aW9uICh2KSB7XG4gICAgICByZXR1cm4gdlsxXS50b1VwcGVyQ2FzZSgpO1xuICAgIH0pO1xuICB9KTtcbiAgdmFyIHByZXBlbmRDYW1lbCA9IG1lbW9pemUkMShmdW5jdGlvbiAocHJlZml4LCBzdHIpIHtcbiAgICByZXR1cm4gcHJlZml4ICsgc3RyWzBdLnRvVXBwZXJDYXNlKCkgKyBzdHIuc3Vic3RyaW5nKDEpO1xuICB9LCBmdW5jdGlvbiAocHJlZml4LCBzdHIpIHtcbiAgICByZXR1cm4gcHJlZml4ICsgJyQnICsgc3RyO1xuICB9KTtcbiAgdmFyIGNhcGl0YWxpemUgPSBmdW5jdGlvbiBjYXBpdGFsaXplKHN0cikge1xuICAgIGlmIChlbXB0eVN0cmluZyhzdHIpKSB7XG4gICAgICByZXR1cm4gc3RyO1xuICAgIH1cblxuICAgIHJldHVybiBzdHIuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBzdHIuc3Vic3RyaW5nKDEpO1xuICB9O1xuXG4gIHZhciBudW1iZXIgPSAnKD86Wy0rXT8oPzooPzpcXFxcZCt8XFxcXGQqXFxcXC5cXFxcZCspKD86W0VlXVsrLV0/XFxcXGQrKT8pKSc7XG4gIHZhciByZ2JhID0gJ3JnYlthXT9cXFxcKCgnICsgbnVtYmVyICsgJ1slXT8pXFxcXHMqLFxcXFxzKignICsgbnVtYmVyICsgJ1slXT8pXFxcXHMqLFxcXFxzKignICsgbnVtYmVyICsgJ1slXT8pKD86XFxcXHMqLFxcXFxzKignICsgbnVtYmVyICsgJykpP1xcXFwpJztcbiAgdmFyIHJnYmFOb0JhY2tSZWZzID0gJ3JnYlthXT9cXFxcKCg/OicgKyBudW1iZXIgKyAnWyVdPylcXFxccyosXFxcXHMqKD86JyArIG51bWJlciArICdbJV0/KVxcXFxzKixcXFxccyooPzonICsgbnVtYmVyICsgJ1slXT8pKD86XFxcXHMqLFxcXFxzKig/OicgKyBudW1iZXIgKyAnKSk/XFxcXCknO1xuICB2YXIgaHNsYSA9ICdoc2xbYV0/XFxcXCgoJyArIG51bWJlciArICcpXFxcXHMqLFxcXFxzKignICsgbnVtYmVyICsgJ1slXSlcXFxccyosXFxcXHMqKCcgKyBudW1iZXIgKyAnWyVdKSg/OlxcXFxzKixcXFxccyooJyArIG51bWJlciArICcpKT9cXFxcKSc7XG4gIHZhciBoc2xhTm9CYWNrUmVmcyA9ICdoc2xbYV0/XFxcXCgoPzonICsgbnVtYmVyICsgJylcXFxccyosXFxcXHMqKD86JyArIG51bWJlciArICdbJV0pXFxcXHMqLFxcXFxzKig/OicgKyBudW1iZXIgKyAnWyVdKSg/OlxcXFxzKixcXFxccyooPzonICsgbnVtYmVyICsgJykpP1xcXFwpJztcbiAgdmFyIGhleDMgPSAnXFxcXCNbMC05YS1mQS1GXXszfSc7XG4gIHZhciBoZXg2ID0gJ1xcXFwjWzAtOWEtZkEtRl17Nn0nO1xuXG4gIHZhciBhc2NlbmRpbmcgPSBmdW5jdGlvbiBhc2NlbmRpbmcoYSwgYikge1xuICAgIGlmIChhIDwgYikge1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH0gZWxzZSBpZiAoYSA+IGIpIHtcbiAgICAgIHJldHVybiAxO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gIH07XG4gIHZhciBkZXNjZW5kaW5nID0gZnVuY3Rpb24gZGVzY2VuZGluZyhhLCBiKSB7XG4gICAgcmV0dXJuIC0xICogYXNjZW5kaW5nKGEsIGIpO1xuICB9O1xuXG4gIHZhciBleHRlbmQgPSBPYmplY3QuYXNzaWduICE9IG51bGwgPyBPYmplY3QuYXNzaWduLmJpbmQoT2JqZWN0KSA6IGZ1bmN0aW9uICh0Z3QpIHtcbiAgICB2YXIgYXJncyA9IGFyZ3VtZW50cztcblxuICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJncy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIG9iaiA9IGFyZ3NbaV07XG5cbiAgICAgIGlmIChvYmogPT0gbnVsbCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyhvYmopO1xuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGtleXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdmFyIGsgPSBrZXlzW2pdO1xuICAgICAgICB0Z3Rba10gPSBvYmpba107XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRndDtcbiAgfTtcblxuICB2YXIgaGV4MnR1cGxlID0gZnVuY3Rpb24gaGV4MnR1cGxlKGhleCkge1xuICAgIGlmICghKGhleC5sZW5ndGggPT09IDQgfHwgaGV4Lmxlbmd0aCA9PT0gNykgfHwgaGV4WzBdICE9PSAnIycpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgc2hvcnRIZXggPSBoZXgubGVuZ3RoID09PSA0O1xuICAgIHZhciByLCBnLCBiO1xuICAgIHZhciBiYXNlID0gMTY7XG5cbiAgICBpZiAoc2hvcnRIZXgpIHtcbiAgICAgIHIgPSBwYXJzZUludChoZXhbMV0gKyBoZXhbMV0sIGJhc2UpO1xuICAgICAgZyA9IHBhcnNlSW50KGhleFsyXSArIGhleFsyXSwgYmFzZSk7XG4gICAgICBiID0gcGFyc2VJbnQoaGV4WzNdICsgaGV4WzNdLCBiYXNlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgciA9IHBhcnNlSW50KGhleFsxXSArIGhleFsyXSwgYmFzZSk7XG4gICAgICBnID0gcGFyc2VJbnQoaGV4WzNdICsgaGV4WzRdLCBiYXNlKTtcbiAgICAgIGIgPSBwYXJzZUludChoZXhbNV0gKyBoZXhbNl0sIGJhc2UpO1xuICAgIH1cblxuICAgIHJldHVybiBbciwgZywgYl07XG4gIH07IC8vIGdldCBbciwgZywgYiwgYV0gZnJvbSBoc2woMCwgMCwgMCkgb3IgaHNsYSgwLCAwLCAwLCAwKVxuXG4gIHZhciBoc2wydHVwbGUgPSBmdW5jdGlvbiBoc2wydHVwbGUoaHNsKSB7XG4gICAgdmFyIHJldDtcbiAgICB2YXIgaCwgcywgbCwgYSwgciwgZywgYjtcblxuICAgIGZ1bmN0aW9uIGh1ZTJyZ2IocCwgcSwgdCkge1xuICAgICAgaWYgKHQgPCAwKSB0ICs9IDE7XG4gICAgICBpZiAodCA+IDEpIHQgLT0gMTtcbiAgICAgIGlmICh0IDwgMSAvIDYpIHJldHVybiBwICsgKHEgLSBwKSAqIDYgKiB0O1xuICAgICAgaWYgKHQgPCAxIC8gMikgcmV0dXJuIHE7XG4gICAgICBpZiAodCA8IDIgLyAzKSByZXR1cm4gcCArIChxIC0gcCkgKiAoMiAvIDMgLSB0KSAqIDY7XG4gICAgICByZXR1cm4gcDtcbiAgICB9XG5cbiAgICB2YXIgbSA9IG5ldyBSZWdFeHAoJ14nICsgaHNsYSArICckJykuZXhlYyhoc2wpO1xuXG4gICAgaWYgKG0pIHtcbiAgICAgIC8vIGdldCBodWVcbiAgICAgIGggPSBwYXJzZUludChtWzFdKTtcblxuICAgICAgaWYgKGggPCAwKSB7XG4gICAgICAgIGggPSAoMzYwIC0gLTEgKiBoICUgMzYwKSAlIDM2MDtcbiAgICAgIH0gZWxzZSBpZiAoaCA+IDM2MCkge1xuICAgICAgICBoID0gaCAlIDM2MDtcbiAgICAgIH1cblxuICAgICAgaCAvPSAzNjA7IC8vIG5vcm1hbGlzZSBvbiBbMCwgMV1cblxuICAgICAgcyA9IHBhcnNlRmxvYXQobVsyXSk7XG5cbiAgICAgIGlmIChzIDwgMCB8fCBzID4gMTAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gc2F0dXJhdGlvbiBpcyBbMCwgMTAwXVxuXG5cbiAgICAgIHMgPSBzIC8gMTAwOyAvLyBub3JtYWxpc2Ugb24gWzAsIDFdXG5cbiAgICAgIGwgPSBwYXJzZUZsb2F0KG1bM10pO1xuXG4gICAgICBpZiAobCA8IDAgfHwgbCA+IDEwMCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIGxpZ2h0bmVzcyBpcyBbMCwgMTAwXVxuXG5cbiAgICAgIGwgPSBsIC8gMTAwOyAvLyBub3JtYWxpc2Ugb24gWzAsIDFdXG5cbiAgICAgIGEgPSBtWzRdO1xuXG4gICAgICBpZiAoYSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGEgPSBwYXJzZUZsb2F0KGEpO1xuXG4gICAgICAgIGlmIChhIDwgMCB8fCBhID4gMSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSAvLyBhbHBoYSBpcyBbMCwgMV1cblxuICAgICAgfSAvLyBub3csIGNvbnZlcnQgdG8gcmdiXG4gICAgICAvLyBjb2RlIGZyb20gaHR0cDovL21qaWphY2tzb24uY29tLzIwMDgvMDIvcmdiLXRvLWhzbC1hbmQtcmdiLXRvLWhzdi1jb2xvci1tb2RlbC1jb252ZXJzaW9uLWFsZ29yaXRobXMtaW4tamF2YXNjcmlwdFxuXG5cbiAgICAgIGlmIChzID09PSAwKSB7XG4gICAgICAgIHIgPSBnID0gYiA9IE1hdGgucm91bmQobCAqIDI1NSk7IC8vIGFjaHJvbWF0aWNcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBxID0gbCA8IDAuNSA/IGwgKiAoMSArIHMpIDogbCArIHMgLSBsICogcztcbiAgICAgICAgdmFyIHAgPSAyICogbCAtIHE7XG4gICAgICAgIHIgPSBNYXRoLnJvdW5kKDI1NSAqIGh1ZTJyZ2IocCwgcSwgaCArIDEgLyAzKSk7XG4gICAgICAgIGcgPSBNYXRoLnJvdW5kKDI1NSAqIGh1ZTJyZ2IocCwgcSwgaCkpO1xuICAgICAgICBiID0gTWF0aC5yb3VuZCgyNTUgKiBodWUycmdiKHAsIHEsIGggLSAxIC8gMykpO1xuICAgICAgfVxuXG4gICAgICByZXQgPSBbciwgZywgYiwgYV07XG4gICAgfVxuXG4gICAgcmV0dXJuIHJldDtcbiAgfTsgLy8gZ2V0IFtyLCBnLCBiLCBhXSBmcm9tIHJnYigwLCAwLCAwKSBvciByZ2JhKDAsIDAsIDAsIDApXG5cbiAgdmFyIHJnYjJ0dXBsZSA9IGZ1bmN0aW9uIHJnYjJ0dXBsZShyZ2IpIHtcbiAgICB2YXIgcmV0O1xuICAgIHZhciBtID0gbmV3IFJlZ0V4cCgnXicgKyByZ2JhICsgJyQnKS5leGVjKHJnYik7XG5cbiAgICBpZiAobSkge1xuICAgICAgcmV0ID0gW107XG4gICAgICB2YXIgaXNQY3QgPSBbXTtcblxuICAgICAgZm9yICh2YXIgaSA9IDE7IGkgPD0gMzsgaSsrKSB7XG4gICAgICAgIHZhciBjaGFubmVsID0gbVtpXTtcblxuICAgICAgICBpZiAoY2hhbm5lbFtjaGFubmVsLmxlbmd0aCAtIDFdID09PSAnJScpIHtcbiAgICAgICAgICBpc1BjdFtpXSA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBjaGFubmVsID0gcGFyc2VGbG9hdChjaGFubmVsKTtcblxuICAgICAgICBpZiAoaXNQY3RbaV0pIHtcbiAgICAgICAgICBjaGFubmVsID0gY2hhbm5lbCAvIDEwMCAqIDI1NTsgLy8gbm9ybWFsaXNlIHRvIFswLCAyNTVdXG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2hhbm5lbCA8IDAgfHwgY2hhbm5lbCA+IDI1NSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSAvLyBpbnZhbGlkIGNoYW5uZWwgdmFsdWVcblxuXG4gICAgICAgIHJldC5wdXNoKE1hdGguZmxvb3IoY2hhbm5lbCkpO1xuICAgICAgfVxuXG4gICAgICB2YXIgYXRMZWFzdE9uZUlzUGN0ID0gaXNQY3RbMV0gfHwgaXNQY3RbMl0gfHwgaXNQY3RbM107XG4gICAgICB2YXIgYWxsQXJlUGN0ID0gaXNQY3RbMV0gJiYgaXNQY3RbMl0gJiYgaXNQY3RbM107XG5cbiAgICAgIGlmIChhdExlYXN0T25lSXNQY3QgJiYgIWFsbEFyZVBjdCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIG11c3QgYWxsIGJlIHBlcmNlbnQgdmFsdWVzIGlmIG9uZSBpc1xuXG5cbiAgICAgIHZhciBhbHBoYSA9IG1bNF07XG5cbiAgICAgIGlmIChhbHBoYSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGFscGhhID0gcGFyc2VGbG9hdChhbHBoYSk7XG5cbiAgICAgICAgaWYgKGFscGhhIDwgMCB8fCBhbHBoYSA+IDEpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gLy8gaW52YWxpZCBhbHBoYSB2YWx1ZVxuXG5cbiAgICAgICAgcmV0LnB1c2goYWxwaGEpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXQ7XG4gIH07XG4gIHZhciBjb2xvcm5hbWUydHVwbGUgPSBmdW5jdGlvbiBjb2xvcm5hbWUydHVwbGUoY29sb3IpIHtcbiAgICByZXR1cm4gY29sb3JzW2NvbG9yLnRvTG93ZXJDYXNlKCldO1xuICB9O1xuICB2YXIgY29sb3IydHVwbGUgPSBmdW5jdGlvbiBjb2xvcjJ0dXBsZShjb2xvcikge1xuICAgIHJldHVybiAoYXJyYXkoY29sb3IpID8gY29sb3IgOiBudWxsKSB8fCBjb2xvcm5hbWUydHVwbGUoY29sb3IpIHx8IGhleDJ0dXBsZShjb2xvcikgfHwgcmdiMnR1cGxlKGNvbG9yKSB8fCBoc2wydHVwbGUoY29sb3IpO1xuICB9O1xuICB2YXIgY29sb3JzID0ge1xuICAgIC8vIHNwZWNpYWwgY29sb3VyIG5hbWVzXG4gICAgdHJhbnNwYXJlbnQ6IFswLCAwLCAwLCAwXSxcbiAgICAvLyBOQiBhbHBoYSA9PT0gMFxuICAgIC8vIHJlZ3VsYXIgY29sb3Vyc1xuICAgIGFsaWNlYmx1ZTogWzI0MCwgMjQ4LCAyNTVdLFxuICAgIGFudGlxdWV3aGl0ZTogWzI1MCwgMjM1LCAyMTVdLFxuICAgIGFxdWE6IFswLCAyNTUsIDI1NV0sXG4gICAgYXF1YW1hcmluZTogWzEyNywgMjU1LCAyMTJdLFxuICAgIGF6dXJlOiBbMjQwLCAyNTUsIDI1NV0sXG4gICAgYmVpZ2U6IFsyNDUsIDI0NSwgMjIwXSxcbiAgICBiaXNxdWU6IFsyNTUsIDIyOCwgMTk2XSxcbiAgICBibGFjazogWzAsIDAsIDBdLFxuICAgIGJsYW5jaGVkYWxtb25kOiBbMjU1LCAyMzUsIDIwNV0sXG4gICAgYmx1ZTogWzAsIDAsIDI1NV0sXG4gICAgYmx1ZXZpb2xldDogWzEzOCwgNDMsIDIyNl0sXG4gICAgYnJvd246IFsxNjUsIDQyLCA0Ml0sXG4gICAgYnVybHl3b29kOiBbMjIyLCAxODQsIDEzNV0sXG4gICAgY2FkZXRibHVlOiBbOTUsIDE1OCwgMTYwXSxcbiAgICBjaGFydHJldXNlOiBbMTI3LCAyNTUsIDBdLFxuICAgIGNob2NvbGF0ZTogWzIxMCwgMTA1LCAzMF0sXG4gICAgY29yYWw6IFsyNTUsIDEyNywgODBdLFxuICAgIGNvcm5mbG93ZXJibHVlOiBbMTAwLCAxNDksIDIzN10sXG4gICAgY29ybnNpbGs6IFsyNTUsIDI0OCwgMjIwXSxcbiAgICBjcmltc29uOiBbMjIwLCAyMCwgNjBdLFxuICAgIGN5YW46IFswLCAyNTUsIDI1NV0sXG4gICAgZGFya2JsdWU6IFswLCAwLCAxMzldLFxuICAgIGRhcmtjeWFuOiBbMCwgMTM5LCAxMzldLFxuICAgIGRhcmtnb2xkZW5yb2Q6IFsxODQsIDEzNCwgMTFdLFxuICAgIGRhcmtncmF5OiBbMTY5LCAxNjksIDE2OV0sXG4gICAgZGFya2dyZWVuOiBbMCwgMTAwLCAwXSxcbiAgICBkYXJrZ3JleTogWzE2OSwgMTY5LCAxNjldLFxuICAgIGRhcmtraGFraTogWzE4OSwgMTgzLCAxMDddLFxuICAgIGRhcmttYWdlbnRhOiBbMTM5LCAwLCAxMzldLFxuICAgIGRhcmtvbGl2ZWdyZWVuOiBbODUsIDEwNywgNDddLFxuICAgIGRhcmtvcmFuZ2U6IFsyNTUsIDE0MCwgMF0sXG4gICAgZGFya29yY2hpZDogWzE1MywgNTAsIDIwNF0sXG4gICAgZGFya3JlZDogWzEzOSwgMCwgMF0sXG4gICAgZGFya3NhbG1vbjogWzIzMywgMTUwLCAxMjJdLFxuICAgIGRhcmtzZWFncmVlbjogWzE0MywgMTg4LCAxNDNdLFxuICAgIGRhcmtzbGF0ZWJsdWU6IFs3MiwgNjEsIDEzOV0sXG4gICAgZGFya3NsYXRlZ3JheTogWzQ3LCA3OSwgNzldLFxuICAgIGRhcmtzbGF0ZWdyZXk6IFs0NywgNzksIDc5XSxcbiAgICBkYXJrdHVycXVvaXNlOiBbMCwgMjA2LCAyMDldLFxuICAgIGRhcmt2aW9sZXQ6IFsxNDgsIDAsIDIxMV0sXG4gICAgZGVlcHBpbms6IFsyNTUsIDIwLCAxNDddLFxuICAgIGRlZXBza3libHVlOiBbMCwgMTkxLCAyNTVdLFxuICAgIGRpbWdyYXk6IFsxMDUsIDEwNSwgMTA1XSxcbiAgICBkaW1ncmV5OiBbMTA1LCAxMDUsIDEwNV0sXG4gICAgZG9kZ2VyYmx1ZTogWzMwLCAxNDQsIDI1NV0sXG4gICAgZmlyZWJyaWNrOiBbMTc4LCAzNCwgMzRdLFxuICAgIGZsb3JhbHdoaXRlOiBbMjU1LCAyNTAsIDI0MF0sXG4gICAgZm9yZXN0Z3JlZW46IFszNCwgMTM5LCAzNF0sXG4gICAgZnVjaHNpYTogWzI1NSwgMCwgMjU1XSxcbiAgICBnYWluc2Jvcm86IFsyMjAsIDIyMCwgMjIwXSxcbiAgICBnaG9zdHdoaXRlOiBbMjQ4LCAyNDgsIDI1NV0sXG4gICAgZ29sZDogWzI1NSwgMjE1LCAwXSxcbiAgICBnb2xkZW5yb2Q6IFsyMTgsIDE2NSwgMzJdLFxuICAgIGdyYXk6IFsxMjgsIDEyOCwgMTI4XSxcbiAgICBncmV5OiBbMTI4LCAxMjgsIDEyOF0sXG4gICAgZ3JlZW46IFswLCAxMjgsIDBdLFxuICAgIGdyZWVueWVsbG93OiBbMTczLCAyNTUsIDQ3XSxcbiAgICBob25leWRldzogWzI0MCwgMjU1LCAyNDBdLFxuICAgIGhvdHBpbms6IFsyNTUsIDEwNSwgMTgwXSxcbiAgICBpbmRpYW5yZWQ6IFsyMDUsIDkyLCA5Ml0sXG4gICAgaW5kaWdvOiBbNzUsIDAsIDEzMF0sXG4gICAgaXZvcnk6IFsyNTUsIDI1NSwgMjQwXSxcbiAgICBraGFraTogWzI0MCwgMjMwLCAxNDBdLFxuICAgIGxhdmVuZGVyOiBbMjMwLCAyMzAsIDI1MF0sXG4gICAgbGF2ZW5kZXJibHVzaDogWzI1NSwgMjQwLCAyNDVdLFxuICAgIGxhd25ncmVlbjogWzEyNCwgMjUyLCAwXSxcbiAgICBsZW1vbmNoaWZmb246IFsyNTUsIDI1MCwgMjA1XSxcbiAgICBsaWdodGJsdWU6IFsxNzMsIDIxNiwgMjMwXSxcbiAgICBsaWdodGNvcmFsOiBbMjQwLCAxMjgsIDEyOF0sXG4gICAgbGlnaHRjeWFuOiBbMjI0LCAyNTUsIDI1NV0sXG4gICAgbGlnaHRnb2xkZW5yb2R5ZWxsb3c6IFsyNTAsIDI1MCwgMjEwXSxcbiAgICBsaWdodGdyYXk6IFsyMTEsIDIxMSwgMjExXSxcbiAgICBsaWdodGdyZWVuOiBbMTQ0LCAyMzgsIDE0NF0sXG4gICAgbGlnaHRncmV5OiBbMjExLCAyMTEsIDIxMV0sXG4gICAgbGlnaHRwaW5rOiBbMjU1LCAxODIsIDE5M10sXG4gICAgbGlnaHRzYWxtb246IFsyNTUsIDE2MCwgMTIyXSxcbiAgICBsaWdodHNlYWdyZWVuOiBbMzIsIDE3OCwgMTcwXSxcbiAgICBsaWdodHNreWJsdWU6IFsxMzUsIDIwNiwgMjUwXSxcbiAgICBsaWdodHNsYXRlZ3JheTogWzExOSwgMTM2LCAxNTNdLFxuICAgIGxpZ2h0c2xhdGVncmV5OiBbMTE5LCAxMzYsIDE1M10sXG4gICAgbGlnaHRzdGVlbGJsdWU6IFsxNzYsIDE5NiwgMjIyXSxcbiAgICBsaWdodHllbGxvdzogWzI1NSwgMjU1LCAyMjRdLFxuICAgIGxpbWU6IFswLCAyNTUsIDBdLFxuICAgIGxpbWVncmVlbjogWzUwLCAyMDUsIDUwXSxcbiAgICBsaW5lbjogWzI1MCwgMjQwLCAyMzBdLFxuICAgIG1hZ2VudGE6IFsyNTUsIDAsIDI1NV0sXG4gICAgbWFyb29uOiBbMTI4LCAwLCAwXSxcbiAgICBtZWRpdW1hcXVhbWFyaW5lOiBbMTAyLCAyMDUsIDE3MF0sXG4gICAgbWVkaXVtYmx1ZTogWzAsIDAsIDIwNV0sXG4gICAgbWVkaXVtb3JjaGlkOiBbMTg2LCA4NSwgMjExXSxcbiAgICBtZWRpdW1wdXJwbGU6IFsxNDcsIDExMiwgMjE5XSxcbiAgICBtZWRpdW1zZWFncmVlbjogWzYwLCAxNzksIDExM10sXG4gICAgbWVkaXVtc2xhdGVibHVlOiBbMTIzLCAxMDQsIDIzOF0sXG4gICAgbWVkaXVtc3ByaW5nZ3JlZW46IFswLCAyNTAsIDE1NF0sXG4gICAgbWVkaXVtdHVycXVvaXNlOiBbNzIsIDIwOSwgMjA0XSxcbiAgICBtZWRpdW12aW9sZXRyZWQ6IFsxOTksIDIxLCAxMzNdLFxuICAgIG1pZG5pZ2h0Ymx1ZTogWzI1LCAyNSwgMTEyXSxcbiAgICBtaW50Y3JlYW06IFsyNDUsIDI1NSwgMjUwXSxcbiAgICBtaXN0eXJvc2U6IFsyNTUsIDIyOCwgMjI1XSxcbiAgICBtb2NjYXNpbjogWzI1NSwgMjI4LCAxODFdLFxuICAgIG5hdmFqb3doaXRlOiBbMjU1LCAyMjIsIDE3M10sXG4gICAgbmF2eTogWzAsIDAsIDEyOF0sXG4gICAgb2xkbGFjZTogWzI1MywgMjQ1LCAyMzBdLFxuICAgIG9saXZlOiBbMTI4LCAxMjgsIDBdLFxuICAgIG9saXZlZHJhYjogWzEwNywgMTQyLCAzNV0sXG4gICAgb3JhbmdlOiBbMjU1LCAxNjUsIDBdLFxuICAgIG9yYW5nZXJlZDogWzI1NSwgNjksIDBdLFxuICAgIG9yY2hpZDogWzIxOCwgMTEyLCAyMTRdLFxuICAgIHBhbGVnb2xkZW5yb2Q6IFsyMzgsIDIzMiwgMTcwXSxcbiAgICBwYWxlZ3JlZW46IFsxNTIsIDI1MSwgMTUyXSxcbiAgICBwYWxldHVycXVvaXNlOiBbMTc1LCAyMzgsIDIzOF0sXG4gICAgcGFsZXZpb2xldHJlZDogWzIxOSwgMTEyLCAxNDddLFxuICAgIHBhcGF5YXdoaXA6IFsyNTUsIDIzOSwgMjEzXSxcbiAgICBwZWFjaHB1ZmY6IFsyNTUsIDIxOCwgMTg1XSxcbiAgICBwZXJ1OiBbMjA1LCAxMzMsIDYzXSxcbiAgICBwaW5rOiBbMjU1LCAxOTIsIDIwM10sXG4gICAgcGx1bTogWzIyMSwgMTYwLCAyMjFdLFxuICAgIHBvd2RlcmJsdWU6IFsxNzYsIDIyNCwgMjMwXSxcbiAgICBwdXJwbGU6IFsxMjgsIDAsIDEyOF0sXG4gICAgcmVkOiBbMjU1LCAwLCAwXSxcbiAgICByb3N5YnJvd246IFsxODgsIDE0MywgMTQzXSxcbiAgICByb3lhbGJsdWU6IFs2NSwgMTA1LCAyMjVdLFxuICAgIHNhZGRsZWJyb3duOiBbMTM5LCA2OSwgMTldLFxuICAgIHNhbG1vbjogWzI1MCwgMTI4LCAxMTRdLFxuICAgIHNhbmR5YnJvd246IFsyNDQsIDE2NCwgOTZdLFxuICAgIHNlYWdyZWVuOiBbNDYsIDEzOSwgODddLFxuICAgIHNlYXNoZWxsOiBbMjU1LCAyNDUsIDIzOF0sXG4gICAgc2llbm5hOiBbMTYwLCA4MiwgNDVdLFxuICAgIHNpbHZlcjogWzE5MiwgMTkyLCAxOTJdLFxuICAgIHNreWJsdWU6IFsxMzUsIDIwNiwgMjM1XSxcbiAgICBzbGF0ZWJsdWU6IFsxMDYsIDkwLCAyMDVdLFxuICAgIHNsYXRlZ3JheTogWzExMiwgMTI4LCAxNDRdLFxuICAgIHNsYXRlZ3JleTogWzExMiwgMTI4LCAxNDRdLFxuICAgIHNub3c6IFsyNTUsIDI1MCwgMjUwXSxcbiAgICBzcHJpbmdncmVlbjogWzAsIDI1NSwgMTI3XSxcbiAgICBzdGVlbGJsdWU6IFs3MCwgMTMwLCAxODBdLFxuICAgIHRhbjogWzIxMCwgMTgwLCAxNDBdLFxuICAgIHRlYWw6IFswLCAxMjgsIDEyOF0sXG4gICAgdGhpc3RsZTogWzIxNiwgMTkxLCAyMTZdLFxuICAgIHRvbWF0bzogWzI1NSwgOTksIDcxXSxcbiAgICB0dXJxdW9pc2U6IFs2NCwgMjI0LCAyMDhdLFxuICAgIHZpb2xldDogWzIzOCwgMTMwLCAyMzhdLFxuICAgIHdoZWF0OiBbMjQ1LCAyMjIsIDE3OV0sXG4gICAgd2hpdGU6IFsyNTUsIDI1NSwgMjU1XSxcbiAgICB3aGl0ZXNtb2tlOiBbMjQ1LCAyNDUsIDI0NV0sXG4gICAgeWVsbG93OiBbMjU1LCAyNTUsIDBdLFxuICAgIHllbGxvd2dyZWVuOiBbMTU0LCAyMDUsIDUwXVxuICB9O1xuXG4gIHZhciBzZXRNYXAgPSBmdW5jdGlvbiBzZXRNYXAob3B0aW9ucykge1xuICAgIHZhciBvYmogPSBvcHRpb25zLm1hcDtcbiAgICB2YXIga2V5cyA9IG9wdGlvbnMua2V5cztcbiAgICB2YXIgbCA9IGtleXMubGVuZ3RoO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsOyBpKyspIHtcbiAgICAgIHZhciBrZXkgPSBrZXlzW2ldO1xuXG4gICAgICBpZiAocGxhaW5PYmplY3Qoa2V5KSkge1xuICAgICAgICB0aHJvdyBFcnJvcignVHJpZWQgdG8gc2V0IG1hcCB3aXRoIG9iamVjdCBrZXknKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGkgPCBrZXlzLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgLy8gZXh0ZW5kIHRoZSBtYXAgaWYgbmVjZXNzYXJ5XG4gICAgICAgIGlmIChvYmpba2V5XSA9PSBudWxsKSB7XG4gICAgICAgICAgb2JqW2tleV0gPSB7fTtcbiAgICAgICAgfVxuXG4gICAgICAgIG9iaiA9IG9ialtrZXldO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gc2V0IHRoZSB2YWx1ZVxuICAgICAgICBvYmpba2V5XSA9IG9wdGlvbnMudmFsdWU7XG4gICAgICB9XG4gICAgfVxuICB9OyAvLyBnZXRzIHRoZSB2YWx1ZSBpbiBhIG1hcCBldmVuIGlmIGl0J3Mgbm90IGJ1aWx0IGluIHBsYWNlc1xuXG4gIHZhciBnZXRNYXAgPSBmdW5jdGlvbiBnZXRNYXAob3B0aW9ucykge1xuICAgIHZhciBvYmogPSBvcHRpb25zLm1hcDtcbiAgICB2YXIga2V5cyA9IG9wdGlvbnMua2V5cztcbiAgICB2YXIgbCA9IGtleXMubGVuZ3RoO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsOyBpKyspIHtcbiAgICAgIHZhciBrZXkgPSBrZXlzW2ldO1xuXG4gICAgICBpZiAocGxhaW5PYmplY3Qoa2V5KSkge1xuICAgICAgICB0aHJvdyBFcnJvcignVHJpZWQgdG8gZ2V0IG1hcCB3aXRoIG9iamVjdCBrZXknKTtcbiAgICAgIH1cblxuICAgICAgb2JqID0gb2JqW2tleV07XG5cbiAgICAgIGlmIChvYmogPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gb2JqO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBvYmo7XG4gIH07IC8vIGRlbGV0ZXMgdGhlIGVudHJ5IGluIHRoZSBtYXBcblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgdGhlXG4gICAqIFtsYW5ndWFnZSB0eXBlXShodHRwOi8vd3d3LmVjbWEtaW50ZXJuYXRpb25hbC5vcmcvZWNtYS0yNjIvNy4wLyNzZWMtZWNtYXNjcmlwdC1sYW5ndWFnZS10eXBlcylcbiAgICogb2YgYE9iamVjdGAuIChlLmcuIGFycmF5cywgZnVuY3Rpb25zLCBvYmplY3RzLCByZWdleGVzLCBgbmV3IE51bWJlcigwKWAsIGFuZCBgbmV3IFN0cmluZygnJylgKVxuICAgKlxuICAgKiBAc3RhdGljXG4gICAqIEBtZW1iZXJPZiBfXG4gICAqIEBzaW5jZSAwLjEuMFxuICAgKiBAY2F0ZWdvcnkgTGFuZ1xuICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYW4gb2JqZWN0LCBlbHNlIGBmYWxzZWAuXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIF8uaXNPYmplY3Qoe30pO1xuICAgKiAvLyA9PiB0cnVlXG4gICAqXG4gICAqIF8uaXNPYmplY3QoWzEsIDIsIDNdKTtcbiAgICogLy8gPT4gdHJ1ZVxuICAgKlxuICAgKiBfLmlzT2JqZWN0KF8ubm9vcCk7XG4gICAqIC8vID0+IHRydWVcbiAgICpcbiAgICogXy5pc09iamVjdChudWxsKTtcbiAgICogLy8gPT4gZmFsc2VcbiAgICovXG4gIGZ1bmN0aW9uIGlzT2JqZWN0KHZhbHVlKSB7XG4gICAgdmFyIHR5cGUgPSB0eXBlb2YgdmFsdWU7XG4gICAgcmV0dXJuIHZhbHVlICE9IG51bGwgJiYgKHR5cGUgPT0gJ29iamVjdCcgfHwgdHlwZSA9PSAnZnVuY3Rpb24nKTtcbiAgfVxuXG4gIHZhciBpc09iamVjdF8xID0gaXNPYmplY3Q7XG5cbiAgdmFyIGNvbW1vbmpzR2xvYmFsID0gdHlwZW9mIGdsb2JhbFRoaXMgIT09ICd1bmRlZmluZWQnID8gZ2xvYmFsVGhpcyA6IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnID8gd2luZG93IDogdHlwZW9mIGdsb2JhbCAhPT0gJ3VuZGVmaW5lZCcgPyBnbG9iYWwgOiB0eXBlb2Ygc2VsZiAhPT0gJ3VuZGVmaW5lZCcgPyBzZWxmIDoge307XG5cbiAgZnVuY3Rpb24gY3JlYXRlQ29tbW9uanNNb2R1bGUoZm4sIG1vZHVsZSkge1xuICBcdHJldHVybiBtb2R1bGUgPSB7IGV4cG9ydHM6IHt9IH0sIGZuKG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMpLCBtb2R1bGUuZXhwb3J0cztcbiAgfVxuXG4gIC8qKiBEZXRlY3QgZnJlZSB2YXJpYWJsZSBgZ2xvYmFsYCBmcm9tIE5vZGUuanMuICovXG4gIHZhciBmcmVlR2xvYmFsID0gdHlwZW9mIGNvbW1vbmpzR2xvYmFsID09ICdvYmplY3QnICYmIGNvbW1vbmpzR2xvYmFsICYmIGNvbW1vbmpzR2xvYmFsLk9iamVjdCA9PT0gT2JqZWN0ICYmIGNvbW1vbmpzR2xvYmFsO1xuXG4gIHZhciBfZnJlZUdsb2JhbCA9IGZyZWVHbG9iYWw7XG5cbiAgLyoqIERldGVjdCBmcmVlIHZhcmlhYmxlIGBzZWxmYC4gKi9cbiAgdmFyIGZyZWVTZWxmID0gdHlwZW9mIHNlbGYgPT0gJ29iamVjdCcgJiYgc2VsZiAmJiBzZWxmLk9iamVjdCA9PT0gT2JqZWN0ICYmIHNlbGY7XG5cbiAgLyoqIFVzZWQgYXMgYSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvYmplY3QuICovXG4gIHZhciByb290ID0gX2ZyZWVHbG9iYWwgfHwgZnJlZVNlbGYgfHwgRnVuY3Rpb24oJ3JldHVybiB0aGlzJykoKTtcblxuICB2YXIgX3Jvb3QgPSByb290O1xuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSB0aW1lc3RhbXAgb2YgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdGhhdCBoYXZlIGVsYXBzZWQgc2luY2VcbiAgICogdGhlIFVuaXggZXBvY2ggKDEgSmFudWFyeSAxOTcwIDAwOjAwOjAwIFVUQykuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQG1lbWJlck9mIF9cbiAgICogQHNpbmNlIDIuNC4wXG4gICAqIEBjYXRlZ29yeSBEYXRlXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIHRpbWVzdGFtcC5cbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogXy5kZWZlcihmdW5jdGlvbihzdGFtcCkge1xuICAgKiAgIGNvbnNvbGUubG9nKF8ubm93KCkgLSBzdGFtcCk7XG4gICAqIH0sIF8ubm93KCkpO1xuICAgKiAvLyA9PiBMb2dzIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGl0IHRvb2sgZm9yIHRoZSBkZWZlcnJlZCBpbnZvY2F0aW9uLlxuICAgKi9cbiAgdmFyIG5vdyA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBfcm9vdC5EYXRlLm5vdygpO1xuICB9O1xuXG4gIHZhciBub3dfMSA9IG5vdztcblxuICAvKiogVXNlZCB0byBtYXRjaCBhIHNpbmdsZSB3aGl0ZXNwYWNlIGNoYXJhY3Rlci4gKi9cbiAgdmFyIHJlV2hpdGVzcGFjZSA9IC9cXHMvO1xuXG4gIC8qKlxuICAgKiBVc2VkIGJ5IGBfLnRyaW1gIGFuZCBgXy50cmltRW5kYCB0byBnZXQgdGhlIGluZGV4IG9mIHRoZSBsYXN0IG5vbi13aGl0ZXNwYWNlXG4gICAqIGNoYXJhY3RlciBvZiBgc3RyaW5nYC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZyBUaGUgc3RyaW5nIHRvIGluc3BlY3QuXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBsYXN0IG5vbi13aGl0ZXNwYWNlIGNoYXJhY3Rlci5cbiAgICovXG4gIGZ1bmN0aW9uIHRyaW1tZWRFbmRJbmRleChzdHJpbmcpIHtcbiAgICB2YXIgaW5kZXggPSBzdHJpbmcubGVuZ3RoO1xuXG4gICAgd2hpbGUgKGluZGV4LS0gJiYgcmVXaGl0ZXNwYWNlLnRlc3Qoc3RyaW5nLmNoYXJBdChpbmRleCkpKSB7fVxuICAgIHJldHVybiBpbmRleDtcbiAgfVxuXG4gIHZhciBfdHJpbW1lZEVuZEluZGV4ID0gdHJpbW1lZEVuZEluZGV4O1xuXG4gIC8qKiBVc2VkIHRvIG1hdGNoIGxlYWRpbmcgd2hpdGVzcGFjZS4gKi9cbiAgdmFyIHJlVHJpbVN0YXJ0ID0gL15cXHMrLztcblxuICAvKipcbiAgICogVGhlIGJhc2UgaW1wbGVtZW50YXRpb24gb2YgYF8udHJpbWAuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmcgVGhlIHN0cmluZyB0byB0cmltLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBSZXR1cm5zIHRoZSB0cmltbWVkIHN0cmluZy5cbiAgICovXG4gIGZ1bmN0aW9uIGJhc2VUcmltKHN0cmluZykge1xuICAgIHJldHVybiBzdHJpbmdcbiAgICAgID8gc3RyaW5nLnNsaWNlKDAsIF90cmltbWVkRW5kSW5kZXgoc3RyaW5nKSArIDEpLnJlcGxhY2UocmVUcmltU3RhcnQsICcnKVxuICAgICAgOiBzdHJpbmc7XG4gIH1cblxuICB2YXIgX2Jhc2VUcmltID0gYmFzZVRyaW07XG5cbiAgLyoqIEJ1aWx0LWluIHZhbHVlIHJlZmVyZW5jZXMuICovXG4gIHZhciBTeW1ib2wkMSA9IF9yb290LlN5bWJvbDtcblxuICB2YXIgX1N5bWJvbCA9IFN5bWJvbCQxO1xuXG4gIC8qKiBVc2VkIGZvciBidWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcy4gKi9cbiAgdmFyIG9iamVjdFByb3RvJDUgPSBPYmplY3QucHJvdG90eXBlO1xuXG4gIC8qKiBVc2VkIHRvIGNoZWNrIG9iamVjdHMgZm9yIG93biBwcm9wZXJ0aWVzLiAqL1xuICB2YXIgaGFzT3duUHJvcGVydHkkNCA9IG9iamVjdFByb3RvJDUuaGFzT3duUHJvcGVydHk7XG5cbiAgLyoqXG4gICAqIFVzZWQgdG8gcmVzb2x2ZSB0aGVcbiAgICogW2B0b1N0cmluZ1RhZ2BdKGh0dHA6Ly9lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLW9iamVjdC5wcm90b3R5cGUudG9zdHJpbmcpXG4gICAqIG9mIHZhbHVlcy5cbiAgICovXG4gIHZhciBuYXRpdmVPYmplY3RUb1N0cmluZyQxID0gb2JqZWN0UHJvdG8kNS50b1N0cmluZztcblxuICAvKiogQnVpbHQtaW4gdmFsdWUgcmVmZXJlbmNlcy4gKi9cbiAgdmFyIHN5bVRvU3RyaW5nVGFnJDEgPSBfU3ltYm9sID8gX1N5bWJvbC50b1N0cmluZ1RhZyA6IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQSBzcGVjaWFsaXplZCB2ZXJzaW9uIG9mIGBiYXNlR2V0VGFnYCB3aGljaCBpZ25vcmVzIGBTeW1ib2wudG9TdHJpbmdUYWdgIHZhbHVlcy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gcXVlcnkuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IFJldHVybnMgdGhlIHJhdyBgdG9TdHJpbmdUYWdgLlxuICAgKi9cbiAgZnVuY3Rpb24gZ2V0UmF3VGFnKHZhbHVlKSB7XG4gICAgdmFyIGlzT3duID0gaGFzT3duUHJvcGVydHkkNC5jYWxsKHZhbHVlLCBzeW1Ub1N0cmluZ1RhZyQxKSxcbiAgICAgICAgdGFnID0gdmFsdWVbc3ltVG9TdHJpbmdUYWckMV07XG5cbiAgICB0cnkge1xuICAgICAgdmFsdWVbc3ltVG9TdHJpbmdUYWckMV0gPSB1bmRlZmluZWQ7XG4gICAgICB2YXIgdW5tYXNrZWQgPSB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHt9XG5cbiAgICB2YXIgcmVzdWx0ID0gbmF0aXZlT2JqZWN0VG9TdHJpbmckMS5jYWxsKHZhbHVlKTtcbiAgICBpZiAodW5tYXNrZWQpIHtcbiAgICAgIGlmIChpc093bikge1xuICAgICAgICB2YWx1ZVtzeW1Ub1N0cmluZ1RhZyQxXSA9IHRhZztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRlbGV0ZSB2YWx1ZVtzeW1Ub1N0cmluZ1RhZyQxXTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHZhciBfZ2V0UmF3VGFnID0gZ2V0UmF3VGFnO1xuXG4gIC8qKiBVc2VkIGZvciBidWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcy4gKi9cbiAgdmFyIG9iamVjdFByb3RvJDQgPSBPYmplY3QucHJvdG90eXBlO1xuXG4gIC8qKlxuICAgKiBVc2VkIHRvIHJlc29sdmUgdGhlXG4gICAqIFtgdG9TdHJpbmdUYWdgXShodHRwOi8vZWNtYS1pbnRlcm5hdGlvbmFsLm9yZy9lY21hLTI2Mi83LjAvI3NlYy1vYmplY3QucHJvdG90eXBlLnRvc3RyaW5nKVxuICAgKiBvZiB2YWx1ZXMuXG4gICAqL1xuICB2YXIgbmF0aXZlT2JqZWN0VG9TdHJpbmcgPSBvYmplY3RQcm90byQ0LnRvU3RyaW5nO1xuXG4gIC8qKlxuICAgKiBDb252ZXJ0cyBgdmFsdWVgIHRvIGEgc3RyaW5nIHVzaW5nIGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nYC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY29udmVydC5cbiAgICogQHJldHVybnMge3N0cmluZ30gUmV0dXJucyB0aGUgY29udmVydGVkIHN0cmluZy5cbiAgICovXG4gIGZ1bmN0aW9uIG9iamVjdFRvU3RyaW5nKHZhbHVlKSB7XG4gICAgcmV0dXJuIG5hdGl2ZU9iamVjdFRvU3RyaW5nLmNhbGwodmFsdWUpO1xuICB9XG5cbiAgdmFyIF9vYmplY3RUb1N0cmluZyA9IG9iamVjdFRvU3RyaW5nO1xuXG4gIC8qKiBgT2JqZWN0I3RvU3RyaW5nYCByZXN1bHQgcmVmZXJlbmNlcy4gKi9cbiAgdmFyIG51bGxUYWcgPSAnW29iamVjdCBOdWxsXScsXG4gICAgICB1bmRlZmluZWRUYWcgPSAnW29iamVjdCBVbmRlZmluZWRdJztcblxuICAvKiogQnVpbHQtaW4gdmFsdWUgcmVmZXJlbmNlcy4gKi9cbiAgdmFyIHN5bVRvU3RyaW5nVGFnID0gX1N5bWJvbCA/IF9TeW1ib2wudG9TdHJpbmdUYWcgOiB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIFRoZSBiYXNlIGltcGxlbWVudGF0aW9uIG9mIGBnZXRUYWdgIHdpdGhvdXQgZmFsbGJhY2tzIGZvciBidWdneSBlbnZpcm9ubWVudHMuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIHF1ZXJ5LlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBSZXR1cm5zIHRoZSBgdG9TdHJpbmdUYWdgLlxuICAgKi9cbiAgZnVuY3Rpb24gYmFzZUdldFRhZyh2YWx1ZSkge1xuICAgIGlmICh2YWx1ZSA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gdmFsdWUgPT09IHVuZGVmaW5lZCA/IHVuZGVmaW5lZFRhZyA6IG51bGxUYWc7XG4gICAgfVxuICAgIHJldHVybiAoc3ltVG9TdHJpbmdUYWcgJiYgc3ltVG9TdHJpbmdUYWcgaW4gT2JqZWN0KHZhbHVlKSlcbiAgICAgID8gX2dldFJhd1RhZyh2YWx1ZSlcbiAgICAgIDogX29iamVjdFRvU3RyaW5nKHZhbHVlKTtcbiAgfVxuXG4gIHZhciBfYmFzZUdldFRhZyA9IGJhc2VHZXRUYWc7XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIG9iamVjdC1saWtlLiBBIHZhbHVlIGlzIG9iamVjdC1saWtlIGlmIGl0J3Mgbm90IGBudWxsYFxuICAgKiBhbmQgaGFzIGEgYHR5cGVvZmAgcmVzdWx0IG9mIFwib2JqZWN0XCIuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQG1lbWJlck9mIF9cbiAgICogQHNpbmNlIDQuMC4wXG4gICAqIEBjYXRlZ29yeSBMYW5nXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZSwgZWxzZSBgZmFsc2VgLlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiBfLmlzT2JqZWN0TGlrZSh7fSk7XG4gICAqIC8vID0+IHRydWVcbiAgICpcbiAgICogXy5pc09iamVjdExpa2UoWzEsIDIsIDNdKTtcbiAgICogLy8gPT4gdHJ1ZVxuICAgKlxuICAgKiBfLmlzT2JqZWN0TGlrZShfLm5vb3ApO1xuICAgKiAvLyA9PiBmYWxzZVxuICAgKlxuICAgKiBfLmlzT2JqZWN0TGlrZShudWxsKTtcbiAgICogLy8gPT4gZmFsc2VcbiAgICovXG4gIGZ1bmN0aW9uIGlzT2JqZWN0TGlrZSh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZSAhPSBudWxsICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0JztcbiAgfVxuXG4gIHZhciBpc09iamVjdExpa2VfMSA9IGlzT2JqZWN0TGlrZTtcblxuICAvKiogYE9iamVjdCN0b1N0cmluZ2AgcmVzdWx0IHJlZmVyZW5jZXMuICovXG4gIHZhciBzeW1ib2xUYWcgPSAnW29iamVjdCBTeW1ib2xdJztcblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgY2xhc3NpZmllZCBhcyBhIGBTeW1ib2xgIHByaW1pdGl2ZSBvciBvYmplY3QuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQG1lbWJlck9mIF9cbiAgICogQHNpbmNlIDQuMC4wXG4gICAqIEBjYXRlZ29yeSBMYW5nXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBhIHN5bWJvbCwgZWxzZSBgZmFsc2VgLlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiBfLmlzU3ltYm9sKFN5bWJvbC5pdGVyYXRvcik7XG4gICAqIC8vID0+IHRydWVcbiAgICpcbiAgICogXy5pc1N5bWJvbCgnYWJjJyk7XG4gICAqIC8vID0+IGZhbHNlXG4gICAqL1xuICBmdW5jdGlvbiBpc1N5bWJvbCh2YWx1ZSkge1xuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT0gJ3N5bWJvbCcgfHxcbiAgICAgIChpc09iamVjdExpa2VfMSh2YWx1ZSkgJiYgX2Jhc2VHZXRUYWcodmFsdWUpID09IHN5bWJvbFRhZyk7XG4gIH1cblxuICB2YXIgaXNTeW1ib2xfMSA9IGlzU3ltYm9sO1xuXG4gIC8qKiBVc2VkIGFzIHJlZmVyZW5jZXMgZm9yIHZhcmlvdXMgYE51bWJlcmAgY29uc3RhbnRzLiAqL1xuICB2YXIgTkFOID0gMCAvIDA7XG5cbiAgLyoqIFVzZWQgdG8gZGV0ZWN0IGJhZCBzaWduZWQgaGV4YWRlY2ltYWwgc3RyaW5nIHZhbHVlcy4gKi9cbiAgdmFyIHJlSXNCYWRIZXggPSAvXlstK10weFswLTlhLWZdKyQvaTtcblxuICAvKiogVXNlZCB0byBkZXRlY3QgYmluYXJ5IHN0cmluZyB2YWx1ZXMuICovXG4gIHZhciByZUlzQmluYXJ5ID0gL14wYlswMV0rJC9pO1xuXG4gIC8qKiBVc2VkIHRvIGRldGVjdCBvY3RhbCBzdHJpbmcgdmFsdWVzLiAqL1xuICB2YXIgcmVJc09jdGFsID0gL14wb1swLTddKyQvaTtcblxuICAvKiogQnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMgd2l0aG91dCBhIGRlcGVuZGVuY3kgb24gYHJvb3RgLiAqL1xuICB2YXIgZnJlZVBhcnNlSW50ID0gcGFyc2VJbnQ7XG5cbiAgLyoqXG4gICAqIENvbnZlcnRzIGB2YWx1ZWAgdG8gYSBudW1iZXIuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQG1lbWJlck9mIF9cbiAgICogQHNpbmNlIDQuMC4wXG4gICAqIEBjYXRlZ29yeSBMYW5nXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIHByb2Nlc3MuXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIG51bWJlci5cbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogXy50b051bWJlcigzLjIpO1xuICAgKiAvLyA9PiAzLjJcbiAgICpcbiAgICogXy50b051bWJlcihOdW1iZXIuTUlOX1ZBTFVFKTtcbiAgICogLy8gPT4gNWUtMzI0XG4gICAqXG4gICAqIF8udG9OdW1iZXIoSW5maW5pdHkpO1xuICAgKiAvLyA9PiBJbmZpbml0eVxuICAgKlxuICAgKiBfLnRvTnVtYmVyKCczLjInKTtcbiAgICogLy8gPT4gMy4yXG4gICAqL1xuICBmdW5jdGlvbiB0b051bWJlcih2YWx1ZSkge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT0gJ251bWJlcicpIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gICAgaWYgKGlzU3ltYm9sXzEodmFsdWUpKSB7XG4gICAgICByZXR1cm4gTkFOO1xuICAgIH1cbiAgICBpZiAoaXNPYmplY3RfMSh2YWx1ZSkpIHtcbiAgICAgIHZhciBvdGhlciA9IHR5cGVvZiB2YWx1ZS52YWx1ZU9mID09ICdmdW5jdGlvbicgPyB2YWx1ZS52YWx1ZU9mKCkgOiB2YWx1ZTtcbiAgICAgIHZhbHVlID0gaXNPYmplY3RfMShvdGhlcikgPyAob3RoZXIgKyAnJykgOiBvdGhlcjtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSAhPSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHZhbHVlID09PSAwID8gdmFsdWUgOiArdmFsdWU7XG4gICAgfVxuICAgIHZhbHVlID0gX2Jhc2VUcmltKHZhbHVlKTtcbiAgICB2YXIgaXNCaW5hcnkgPSByZUlzQmluYXJ5LnRlc3QodmFsdWUpO1xuICAgIHJldHVybiAoaXNCaW5hcnkgfHwgcmVJc09jdGFsLnRlc3QodmFsdWUpKVxuICAgICAgPyBmcmVlUGFyc2VJbnQodmFsdWUuc2xpY2UoMiksIGlzQmluYXJ5ID8gMiA6IDgpXG4gICAgICA6IChyZUlzQmFkSGV4LnRlc3QodmFsdWUpID8gTkFOIDogK3ZhbHVlKTtcbiAgfVxuXG4gIHZhciB0b051bWJlcl8xID0gdG9OdW1iZXI7XG5cbiAgLyoqIEVycm9yIG1lc3NhZ2UgY29uc3RhbnRzLiAqL1xuICB2YXIgRlVOQ19FUlJPUl9URVhUJDEgPSAnRXhwZWN0ZWQgYSBmdW5jdGlvbic7XG5cbiAgLyogQnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMgZm9yIHRob3NlIHdpdGggdGhlIHNhbWUgbmFtZSBhcyBvdGhlciBgbG9kYXNoYCBtZXRob2RzLiAqL1xuICB2YXIgbmF0aXZlTWF4ID0gTWF0aC5tYXgsXG4gICAgICBuYXRpdmVNaW4gPSBNYXRoLm1pbjtcblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGRlYm91bmNlZCBmdW5jdGlvbiB0aGF0IGRlbGF5cyBpbnZva2luZyBgZnVuY2AgdW50aWwgYWZ0ZXIgYHdhaXRgXG4gICAqIG1pbGxpc2Vjb25kcyBoYXZlIGVsYXBzZWQgc2luY2UgdGhlIGxhc3QgdGltZSB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIHdhc1xuICAgKiBpbnZva2VkLiBUaGUgZGVib3VuY2VkIGZ1bmN0aW9uIGNvbWVzIHdpdGggYSBgY2FuY2VsYCBtZXRob2QgdG8gY2FuY2VsXG4gICAqIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvIGltbWVkaWF0ZWx5IGludm9rZSB0aGVtLlxuICAgKiBQcm92aWRlIGBvcHRpb25zYCB0byBpbmRpY2F0ZSB3aGV0aGVyIGBmdW5jYCBzaG91bGQgYmUgaW52b2tlZCBvbiB0aGVcbiAgICogbGVhZGluZyBhbmQvb3IgdHJhaWxpbmcgZWRnZSBvZiB0aGUgYHdhaXRgIHRpbWVvdXQuIFRoZSBgZnVuY2AgaXMgaW52b2tlZFxuICAgKiB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uLiBTdWJzZXF1ZW50XG4gICAqIGNhbGxzIHRvIHRoZSBkZWJvdW5jZWQgZnVuY3Rpb24gcmV0dXJuIHRoZSByZXN1bHQgb2YgdGhlIGxhc3QgYGZ1bmNgXG4gICAqIGludm9jYXRpb24uXG4gICAqXG4gICAqICoqTm90ZToqKiBJZiBgbGVhZGluZ2AgYW5kIGB0cmFpbGluZ2Agb3B0aW9ucyBhcmUgYHRydWVgLCBgZnVuY2AgaXNcbiAgICogaW52b2tlZCBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dCBvbmx5IGlmIHRoZSBkZWJvdW5jZWQgZnVuY3Rpb25cbiAgICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICAgKlxuICAgKiBJZiBgd2FpdGAgaXMgYDBgIGFuZCBgbGVhZGluZ2AgaXMgYGZhbHNlYCwgYGZ1bmNgIGludm9jYXRpb24gaXMgZGVmZXJyZWRcbiAgICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICAgKlxuICAgKiBTZWUgW0RhdmlkIENvcmJhY2hvJ3MgYXJ0aWNsZV0oaHR0cHM6Ly9jc3MtdHJpY2tzLmNvbS9kZWJvdW5jaW5nLXRocm90dGxpbmctZXhwbGFpbmVkLWV4YW1wbGVzLylcbiAgICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy5kZWJvdW5jZWAgYW5kIGBfLnRocm90dGxlYC5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKiBAbWVtYmVyT2YgX1xuICAgKiBAc2luY2UgMC4xLjBcbiAgICogQGNhdGVnb3J5IEZ1bmN0aW9uXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGRlYm91bmNlLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW3dhaXQ9MF0gVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gZGVsYXkuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9ucz17fV0gVGhlIG9wdGlvbnMgb2JqZWN0LlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9ZmFsc2VdXG4gICAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSBsZWFkaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5tYXhXYWl0XVxuICAgKiAgVGhlIG1heGltdW0gdGltZSBgZnVuY2AgaXMgYWxsb3dlZCB0byBiZSBkZWxheWVkIGJlZm9yZSBpdCdzIGludm9rZWQuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMudHJhaWxpbmc9dHJ1ZV1cbiAgICogIFNwZWNpZnkgaW52b2tpbmcgb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGRlYm91bmNlZCBmdW5jdGlvbi5cbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogLy8gQXZvaWQgY29zdGx5IGNhbGN1bGF0aW9ucyB3aGlsZSB0aGUgd2luZG93IHNpemUgaXMgaW4gZmx1eC5cbiAgICogalF1ZXJ5KHdpbmRvdykub24oJ3Jlc2l6ZScsIF8uZGVib3VuY2UoY2FsY3VsYXRlTGF5b3V0LCAxNTApKTtcbiAgICpcbiAgICogLy8gSW52b2tlIGBzZW5kTWFpbGAgd2hlbiBjbGlja2VkLCBkZWJvdW5jaW5nIHN1YnNlcXVlbnQgY2FsbHMuXG4gICAqIGpRdWVyeShlbGVtZW50KS5vbignY2xpY2snLCBfLmRlYm91bmNlKHNlbmRNYWlsLCAzMDAsIHtcbiAgICogICAnbGVhZGluZyc6IHRydWUsXG4gICAqICAgJ3RyYWlsaW5nJzogZmFsc2VcbiAgICogfSkpO1xuICAgKlxuICAgKiAvLyBFbnN1cmUgYGJhdGNoTG9nYCBpcyBpbnZva2VkIG9uY2UgYWZ0ZXIgMSBzZWNvbmQgb2YgZGVib3VuY2VkIGNhbGxzLlxuICAgKiB2YXIgZGVib3VuY2VkID0gXy5kZWJvdW5jZShiYXRjaExvZywgMjUwLCB7ICdtYXhXYWl0JzogMTAwMCB9KTtcbiAgICogdmFyIHNvdXJjZSA9IG5ldyBFdmVudFNvdXJjZSgnL3N0cmVhbScpO1xuICAgKiBqUXVlcnkoc291cmNlKS5vbignbWVzc2FnZScsIGRlYm91bmNlZCk7XG4gICAqXG4gICAqIC8vIENhbmNlbCB0aGUgdHJhaWxpbmcgZGVib3VuY2VkIGludm9jYXRpb24uXG4gICAqIGpRdWVyeSh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIGRlYm91bmNlZC5jYW5jZWwpO1xuICAgKi9cbiAgZnVuY3Rpb24gZGVib3VuY2UoZnVuYywgd2FpdCwgb3B0aW9ucykge1xuICAgIHZhciBsYXN0QXJncyxcbiAgICAgICAgbGFzdFRoaXMsXG4gICAgICAgIG1heFdhaXQsXG4gICAgICAgIHJlc3VsdCxcbiAgICAgICAgdGltZXJJZCxcbiAgICAgICAgbGFzdENhbGxUaW1lLFxuICAgICAgICBsYXN0SW52b2tlVGltZSA9IDAsXG4gICAgICAgIGxlYWRpbmcgPSBmYWxzZSxcbiAgICAgICAgbWF4aW5nID0gZmFsc2UsXG4gICAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICAgIGlmICh0eXBlb2YgZnVuYyAhPSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKEZVTkNfRVJST1JfVEVYVCQxKTtcbiAgICB9XG4gICAgd2FpdCA9IHRvTnVtYmVyXzEod2FpdCkgfHwgMDtcbiAgICBpZiAoaXNPYmplY3RfMShvcHRpb25zKSkge1xuICAgICAgbGVhZGluZyA9ICEhb3B0aW9ucy5sZWFkaW5nO1xuICAgICAgbWF4aW5nID0gJ21heFdhaXQnIGluIG9wdGlvbnM7XG4gICAgICBtYXhXYWl0ID0gbWF4aW5nID8gbmF0aXZlTWF4KHRvTnVtYmVyXzEob3B0aW9ucy5tYXhXYWl0KSB8fCAwLCB3YWl0KSA6IG1heFdhaXQ7XG4gICAgICB0cmFpbGluZyA9ICd0cmFpbGluZycgaW4gb3B0aW9ucyA/ICEhb3B0aW9ucy50cmFpbGluZyA6IHRyYWlsaW5nO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGludm9rZUZ1bmModGltZSkge1xuICAgICAgdmFyIGFyZ3MgPSBsYXN0QXJncyxcbiAgICAgICAgICB0aGlzQXJnID0gbGFzdFRoaXM7XG5cbiAgICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgICBsYXN0SW52b2tlVGltZSA9IHRpbWU7XG4gICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KHRoaXNBcmcsIGFyZ3MpO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBsZWFkaW5nRWRnZSh0aW1lKSB7XG4gICAgICAvLyBSZXNldCBhbnkgYG1heFdhaXRgIHRpbWVyLlxuICAgICAgbGFzdEludm9rZVRpbWUgPSB0aW1lO1xuICAgICAgLy8gU3RhcnQgdGhlIHRpbWVyIGZvciB0aGUgdHJhaWxpbmcgZWRnZS5cbiAgICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgICAvLyBJbnZva2UgdGhlIGxlYWRpbmcgZWRnZS5cbiAgICAgIHJldHVybiBsZWFkaW5nID8gaW52b2tlRnVuYyh0aW1lKSA6IHJlc3VsdDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZW1haW5pbmdXYWl0KHRpbWUpIHtcbiAgICAgIHZhciB0aW1lU2luY2VMYXN0Q2FsbCA9IHRpbWUgLSBsYXN0Q2FsbFRpbWUsXG4gICAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZSxcbiAgICAgICAgICB0aW1lV2FpdGluZyA9IHdhaXQgLSB0aW1lU2luY2VMYXN0Q2FsbDtcblxuICAgICAgcmV0dXJuIG1heGluZ1xuICAgICAgICA/IG5hdGl2ZU1pbih0aW1lV2FpdGluZywgbWF4V2FpdCAtIHRpbWVTaW5jZUxhc3RJbnZva2UpXG4gICAgICAgIDogdGltZVdhaXRpbmc7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc2hvdWxkSW52b2tlKHRpbWUpIHtcbiAgICAgIHZhciB0aW1lU2luY2VMYXN0Q2FsbCA9IHRpbWUgLSBsYXN0Q2FsbFRpbWUsXG4gICAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZTtcblxuICAgICAgLy8gRWl0aGVyIHRoaXMgaXMgdGhlIGZpcnN0IGNhbGwsIGFjdGl2aXR5IGhhcyBzdG9wcGVkIGFuZCB3ZSdyZSBhdCB0aGVcbiAgICAgIC8vIHRyYWlsaW5nIGVkZ2UsIHRoZSBzeXN0ZW0gdGltZSBoYXMgZ29uZSBiYWNrd2FyZHMgYW5kIHdlJ3JlIHRyZWF0aW5nXG4gICAgICAvLyBpdCBhcyB0aGUgdHJhaWxpbmcgZWRnZSwgb3Igd2UndmUgaGl0IHRoZSBgbWF4V2FpdGAgbGltaXQuXG4gICAgICByZXR1cm4gKGxhc3RDYWxsVGltZSA9PT0gdW5kZWZpbmVkIHx8ICh0aW1lU2luY2VMYXN0Q2FsbCA+PSB3YWl0KSB8fFxuICAgICAgICAodGltZVNpbmNlTGFzdENhbGwgPCAwKSB8fCAobWF4aW5nICYmIHRpbWVTaW5jZUxhc3RJbnZva2UgPj0gbWF4V2FpdCkpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRpbWVyRXhwaXJlZCgpIHtcbiAgICAgIHZhciB0aW1lID0gbm93XzEoKTtcbiAgICAgIGlmIChzaG91bGRJbnZva2UodGltZSkpIHtcbiAgICAgICAgcmV0dXJuIHRyYWlsaW5nRWRnZSh0aW1lKTtcbiAgICAgIH1cbiAgICAgIC8vIFJlc3RhcnQgdGhlIHRpbWVyLlxuICAgICAgdGltZXJJZCA9IHNldFRpbWVvdXQodGltZXJFeHBpcmVkLCByZW1haW5pbmdXYWl0KHRpbWUpKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB0cmFpbGluZ0VkZ2UodGltZSkge1xuICAgICAgdGltZXJJZCA9IHVuZGVmaW5lZDtcblxuICAgICAgLy8gT25seSBpbnZva2UgaWYgd2UgaGF2ZSBgbGFzdEFyZ3NgIHdoaWNoIG1lYW5zIGBmdW5jYCBoYXMgYmVlblxuICAgICAgLy8gZGVib3VuY2VkIGF0IGxlYXN0IG9uY2UuXG4gICAgICBpZiAodHJhaWxpbmcgJiYgbGFzdEFyZ3MpIHtcbiAgICAgICAgcmV0dXJuIGludm9rZUZ1bmModGltZSk7XG4gICAgICB9XG4gICAgICBsYXN0QXJncyA9IGxhc3RUaGlzID0gdW5kZWZpbmVkO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjYW5jZWwoKSB7XG4gICAgICBpZiAodGltZXJJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lcklkKTtcbiAgICAgIH1cbiAgICAgIGxhc3RJbnZva2VUaW1lID0gMDtcbiAgICAgIGxhc3RBcmdzID0gbGFzdENhbGxUaW1lID0gbGFzdFRoaXMgPSB0aW1lcklkID0gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGZsdXNoKCkge1xuICAgICAgcmV0dXJuIHRpbWVySWQgPT09IHVuZGVmaW5lZCA/IHJlc3VsdCA6IHRyYWlsaW5nRWRnZShub3dfMSgpKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBkZWJvdW5jZWQoKSB7XG4gICAgICB2YXIgdGltZSA9IG5vd18xKCksXG4gICAgICAgICAgaXNJbnZva2luZyA9IHNob3VsZEludm9rZSh0aW1lKTtcblxuICAgICAgbGFzdEFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICBsYXN0VGhpcyA9IHRoaXM7XG4gICAgICBsYXN0Q2FsbFRpbWUgPSB0aW1lO1xuXG4gICAgICBpZiAoaXNJbnZva2luZykge1xuICAgICAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgcmV0dXJuIGxlYWRpbmdFZGdlKGxhc3RDYWxsVGltZSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG1heGluZykge1xuICAgICAgICAgIC8vIEhhbmRsZSBpbnZvY2F0aW9ucyBpbiBhIHRpZ2h0IGxvb3AuXG4gICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVySWQpO1xuICAgICAgICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgICAgICAgcmV0dXJuIGludm9rZUZ1bmMobGFzdENhbGxUaW1lKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKHRpbWVySWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gICAgZGVib3VuY2VkLmNhbmNlbCA9IGNhbmNlbDtcbiAgICBkZWJvdW5jZWQuZmx1c2ggPSBmbHVzaDtcbiAgICByZXR1cm4gZGVib3VuY2VkO1xuICB9XG5cbiAgdmFyIGRlYm91bmNlXzEgPSBkZWJvdW5jZTtcblxuICB2YXIgcGVyZm9ybWFuY2UgPSBfd2luZG93ID8gX3dpbmRvdy5wZXJmb3JtYW5jZSA6IG51bGw7XG4gIHZhciBwbm93ID0gcGVyZm9ybWFuY2UgJiYgcGVyZm9ybWFuY2Uubm93ID8gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBwZXJmb3JtYW5jZS5ub3coKTtcbiAgfSA6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gRGF0ZS5ub3coKTtcbiAgfTtcblxuICB2YXIgcmFmID0gZnVuY3Rpb24gKCkge1xuICAgIGlmIChfd2luZG93KSB7XG4gICAgICBpZiAoX3dpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgIF93aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZuKTtcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSBpZiAoX3dpbmRvdy5tb3pSZXF1ZXN0QW5pbWF0aW9uRnJhbWUpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgIF93aW5kb3cubW96UmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZuKTtcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSBpZiAoX3dpbmRvdy53ZWJraXRSZXF1ZXN0QW5pbWF0aW9uRnJhbWUpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgIF93aW5kb3cud2Via2l0UmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZuKTtcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSBpZiAoX3dpbmRvdy5tc1JlcXVlc3RBbmltYXRpb25GcmFtZSkge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgICAgX3dpbmRvdy5tc1JlcXVlc3RBbmltYXRpb25GcmFtZShmbik7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIChmbikge1xuICAgICAgaWYgKGZuKSB7XG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGZuKHBub3coKSk7XG4gICAgICAgIH0sIDEwMDAgLyA2MCk7XG4gICAgICB9XG4gICAgfTtcbiAgfSgpO1xuXG4gIHZhciByZXF1ZXN0QW5pbWF0aW9uRnJhbWUgPSBmdW5jdGlvbiByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZm4pIHtcbiAgICByZXR1cm4gcmFmKGZuKTtcbiAgfTtcbiAgdmFyIHBlcmZvcm1hbmNlTm93ID0gcG5vdztcblxuICB2YXIgREVGQVVMVF9IQVNIX1NFRUQgPSA5MjYxO1xuICB2YXIgSyA9IDY1NTk5OyAvLyAzNyBhbHNvIHdvcmtzIHByZXR0eSB3ZWxsXG5cbiAgdmFyIERFRkFVTFRfSEFTSF9TRUVEX0FMVCA9IDUzODE7XG4gIHZhciBoYXNoSXRlcmFibGVJbnRzID0gZnVuY3Rpb24gaGFzaEl0ZXJhYmxlSW50cyhpdGVyYXRvcikge1xuICAgIHZhciBzZWVkID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiBERUZBVUxUX0hBU0hfU0VFRDtcbiAgICAvLyBzZGJtL3N0cmluZy1oYXNoXG4gICAgdmFyIGhhc2ggPSBzZWVkO1xuICAgIHZhciBlbnRyeTtcblxuICAgIGZvciAoOzspIHtcbiAgICAgIGVudHJ5ID0gaXRlcmF0b3IubmV4dCgpO1xuXG4gICAgICBpZiAoZW50cnkuZG9uZSkge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgaGFzaCA9IGhhc2ggKiBLICsgZW50cnkudmFsdWUgfCAwO1xuICAgIH1cblxuICAgIHJldHVybiBoYXNoO1xuICB9O1xuICB2YXIgaGFzaEludCA9IGZ1bmN0aW9uIGhhc2hJbnQobnVtKSB7XG4gICAgdmFyIHNlZWQgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IERFRkFVTFRfSEFTSF9TRUVEO1xuICAgIC8vIHNkYm0vc3RyaW5nLWhhc2hcbiAgICByZXR1cm4gc2VlZCAqIEsgKyBudW0gfCAwO1xuICB9O1xuICB2YXIgaGFzaEludEFsdCA9IGZ1bmN0aW9uIGhhc2hJbnRBbHQobnVtKSB7XG4gICAgdmFyIHNlZWQgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IERFRkFVTFRfSEFTSF9TRUVEX0FMVDtcbiAgICAvLyBkamIyL3N0cmluZy1oYXNoXG4gICAgcmV0dXJuIChzZWVkIDw8IDUpICsgc2VlZCArIG51bSB8IDA7XG4gIH07XG4gIHZhciBjb21iaW5lSGFzaGVzID0gZnVuY3Rpb24gY29tYmluZUhhc2hlcyhoYXNoMSwgaGFzaDIpIHtcbiAgICByZXR1cm4gaGFzaDEgKiAweDIwMDAwMCArIGhhc2gyO1xuICB9O1xuICB2YXIgY29tYmluZUhhc2hlc0FycmF5ID0gZnVuY3Rpb24gY29tYmluZUhhc2hlc0FycmF5KGhhc2hlcykge1xuICAgIHJldHVybiBoYXNoZXNbMF0gKiAweDIwMDAwMCArIGhhc2hlc1sxXTtcbiAgfTtcbiAgdmFyIGhhc2hBcnJheXMgPSBmdW5jdGlvbiBoYXNoQXJyYXlzKGhhc2hlczEsIGhhc2hlczIpIHtcbiAgICByZXR1cm4gW2hhc2hJbnQoaGFzaGVzMVswXSwgaGFzaGVzMlswXSksIGhhc2hJbnRBbHQoaGFzaGVzMVsxXSwgaGFzaGVzMlsxXSldO1xuICB9O1xuICB2YXIgaGFzaEludHNBcnJheSA9IGZ1bmN0aW9uIGhhc2hJbnRzQXJyYXkoaW50cywgc2VlZCkge1xuICAgIHZhciBlbnRyeSA9IHtcbiAgICAgIHZhbHVlOiAwLFxuICAgICAgZG9uZTogZmFsc2VcbiAgICB9O1xuICAgIHZhciBpID0gMDtcbiAgICB2YXIgbGVuZ3RoID0gaW50cy5sZW5ndGg7XG4gICAgdmFyIGl0ZXJhdG9yID0ge1xuICAgICAgbmV4dDogZnVuY3Rpb24gbmV4dCgpIHtcbiAgICAgICAgaWYgKGkgPCBsZW5ndGgpIHtcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IGludHNbaSsrXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBlbnRyeS5kb25lID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbnRyeTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHJldHVybiBoYXNoSXRlcmFibGVJbnRzKGl0ZXJhdG9yLCBzZWVkKTtcbiAgfTtcbiAgdmFyIGhhc2hTdHJpbmcgPSBmdW5jdGlvbiBoYXNoU3RyaW5nKHN0ciwgc2VlZCkge1xuICAgIHZhciBlbnRyeSA9IHtcbiAgICAgIHZhbHVlOiAwLFxuICAgICAgZG9uZTogZmFsc2VcbiAgICB9O1xuICAgIHZhciBpID0gMDtcbiAgICB2YXIgbGVuZ3RoID0gc3RyLmxlbmd0aDtcbiAgICB2YXIgaXRlcmF0b3IgPSB7XG4gICAgICBuZXh0OiBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICBpZiAoaSA8IGxlbmd0aCkge1xuICAgICAgICAgIGVudHJ5LnZhbHVlID0gc3RyLmNoYXJDb2RlQXQoaSsrKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBlbnRyeS5kb25lID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbnRyeTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHJldHVybiBoYXNoSXRlcmFibGVJbnRzKGl0ZXJhdG9yLCBzZWVkKTtcbiAgfTtcbiAgdmFyIGhhc2hTdHJpbmdzID0gZnVuY3Rpb24gaGFzaFN0cmluZ3MoKSB7XG4gICAgcmV0dXJuIGhhc2hTdHJpbmdzQXJyYXkoYXJndW1lbnRzKTtcbiAgfTtcbiAgdmFyIGhhc2hTdHJpbmdzQXJyYXkgPSBmdW5jdGlvbiBoYXNoU3RyaW5nc0FycmF5KHN0cnMpIHtcbiAgICB2YXIgaGFzaDtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc3Rycy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHN0ciA9IHN0cnNbaV07XG5cbiAgICAgIGlmIChpID09PSAwKSB7XG4gICAgICAgIGhhc2ggPSBoYXNoU3RyaW5nKHN0cik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoYXNoID0gaGFzaFN0cmluZyhzdHIsIGhhc2gpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBoYXNoO1xuICB9O1xuXG4gIC8qZ2xvYmFsIGNvbnNvbGUgKi9cbiAgdmFyIHdhcm5pbmdzRW5hYmxlZCA9IHRydWU7XG4gIHZhciB3YXJuU3VwcG9ydGVkID0gY29uc29sZS53YXJuICE9IG51bGw7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tY29uc29sZVxuXG4gIHZhciB0cmFjZVN1cHBvcnRlZCA9IGNvbnNvbGUudHJhY2UgIT0gbnVsbDsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1jb25zb2xlXG5cbiAgdmFyIE1BWF9JTlQkMSA9IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSIHx8IDkwMDcxOTkyNTQ3NDA5OTE7XG4gIHZhciB0cnVlaWZ5ID0gZnVuY3Rpb24gdHJ1ZWlmeSgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfTtcbiAgdmFyIGZhbHNpZnkgPSBmdW5jdGlvbiBmYWxzaWZ5KCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfTtcbiAgdmFyIHplcm9pZnkgPSBmdW5jdGlvbiB6ZXJvaWZ5KCkge1xuICAgIHJldHVybiAwO1xuICB9O1xuICB2YXIgbm9vcCQxID0gZnVuY3Rpb24gbm9vcCgpIHt9O1xuICB2YXIgZXJyb3IgPSBmdW5jdGlvbiBlcnJvcihtc2cpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IobXNnKTtcbiAgfTtcbiAgdmFyIHdhcm5pbmdzID0gZnVuY3Rpb24gd2FybmluZ3MoZW5hYmxlZCkge1xuICAgIGlmIChlbmFibGVkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHdhcm5pbmdzRW5hYmxlZCA9ICEhZW5hYmxlZDtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHdhcm5pbmdzRW5hYmxlZDtcbiAgICB9XG4gIH07XG4gIHZhciB3YXJuID0gZnVuY3Rpb24gd2Fybihtc2cpIHtcbiAgICAvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG4gICAgaWYgKCF3YXJuaW5ncygpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHdhcm5TdXBwb3J0ZWQpIHtcbiAgICAgIGNvbnNvbGUud2Fybihtc2cpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmxvZyhtc2cpO1xuXG4gICAgICBpZiAodHJhY2VTdXBwb3J0ZWQpIHtcbiAgICAgICAgY29uc29sZS50cmFjZSgpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcbiAgLyogZXNsaW50LWVuYWJsZSAqL1xuXG4gIHZhciBjbG9uZSA9IGZ1bmN0aW9uIGNsb25lKG9iaikge1xuICAgIHJldHVybiBleHRlbmQoe30sIG9iaik7XG4gIH07IC8vIGdldHMgYSBzaGFsbG93IGNvcHkgb2YgdGhlIGFyZ3VtZW50XG5cbiAgdmFyIGNvcHkgPSBmdW5jdGlvbiBjb3B5KG9iaikge1xuICAgIGlmIChvYmogPT0gbnVsbCkge1xuICAgICAgcmV0dXJuIG9iajtcbiAgICB9XG5cbiAgICBpZiAoYXJyYXkob2JqKSkge1xuICAgICAgcmV0dXJuIG9iai5zbGljZSgpO1xuICAgIH0gZWxzZSBpZiAocGxhaW5PYmplY3Qob2JqKSkge1xuICAgICAgcmV0dXJuIGNsb25lKG9iaik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBvYmo7XG4gICAgfVxuICB9O1xuICB2YXIgY29weUFycmF5JDEgPSBmdW5jdGlvbiBjb3B5QXJyYXkoYXJyKSB7XG4gICAgcmV0dXJuIGFyci5zbGljZSgpO1xuICB9O1xuICB2YXIgdXVpZCA9IGZ1bmN0aW9uIHV1aWQoYSwgYlxuICAvKiBwbGFjZWhvbGRlcnMgKi9cbiAgKSB7XG4gICAgZm9yICggLy8gbG9vcCA6KVxuICAgIGIgPSBhID0gJyc7IC8vIGIgLSByZXN1bHQgLCBhIC0gbnVtZXJpYyBsZXRpYWJsZVxuICAgIGErKyA8IDM2OyAvL1xuICAgIGIgKz0gYSAqIDUxICYgNTIgLy8gaWYgXCJhXCIgaXMgbm90IDkgb3IgMTQgb3IgMTkgb3IgMjRcbiAgICA/IC8vICByZXR1cm4gYSByYW5kb20gbnVtYmVyIG9yIDRcbiAgICAoYSBeIDE1IC8vIGlmIFwiYVwiIGlzIG5vdCAxNVxuICAgID8gLy8gZ2VuZXJhdGUgYSByYW5kb20gbnVtYmVyIGZyb20gMCB0byAxNVxuICAgIDggXiBNYXRoLnJhbmRvbSgpICogKGEgXiAyMCA/IDE2IDogNCkgLy8gdW5sZXNzIFwiYVwiIGlzIDIwLCBpbiB3aGljaCBjYXNlIGEgcmFuZG9tIG51bWJlciBmcm9tIDggdG8gMTFcbiAgICA6IDQgLy8gIG90aGVyd2lzZSA0XG4gICAgKS50b1N0cmluZygxNikgOiAnLScgLy8gIGluIG90aGVyIGNhc2VzIChpZiBcImFcIiBpcyA5LDE0LDE5LDI0KSBpbnNlcnQgXCItXCJcbiAgICApIHtcbiAgICB9XG5cbiAgICByZXR1cm4gYjtcbiAgfTtcbiAgdmFyIF9zdGF0aWNFbXB0eU9iamVjdCA9IHt9O1xuICB2YXIgc3RhdGljRW1wdHlPYmplY3QgPSBmdW5jdGlvbiBzdGF0aWNFbXB0eU9iamVjdCgpIHtcbiAgICByZXR1cm4gX3N0YXRpY0VtcHR5T2JqZWN0O1xuICB9O1xuICB2YXIgZGVmYXVsdHMkZyA9IGZ1bmN0aW9uIGRlZmF1bHRzKF9kZWZhdWx0cykge1xuICAgIHZhciBrZXlzID0gT2JqZWN0LmtleXMoX2RlZmF1bHRzKTtcbiAgICByZXR1cm4gZnVuY3Rpb24gKG9wdHMpIHtcbiAgICAgIHZhciBmaWxsZWRPcHRzID0ge307XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIga2V5ID0ga2V5c1tpXTtcbiAgICAgICAgdmFyIG9wdFZhbCA9IG9wdHMgPT0gbnVsbCA/IHVuZGVmaW5lZCA6IG9wdHNba2V5XTtcbiAgICAgICAgZmlsbGVkT3B0c1trZXldID0gb3B0VmFsID09PSB1bmRlZmluZWQgPyBfZGVmYXVsdHNba2V5XSA6IG9wdFZhbDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZpbGxlZE9wdHM7XG4gICAgfTtcbiAgfTtcbiAgdmFyIHJlbW92ZUZyb21BcnJheSA9IGZ1bmN0aW9uIHJlbW92ZUZyb21BcnJheShhcnIsIGVsZSwgb25lQ29weSkge1xuICAgIGZvciAodmFyIGkgPSBhcnIubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIGlmIChhcnJbaV0gPT09IGVsZSkge1xuICAgICAgICBhcnIuc3BsaWNlKGksIDEpO1xuXG4gICAgICAgIGlmIChvbmVDb3B5KSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH07XG4gIHZhciBjbGVhckFycmF5ID0gZnVuY3Rpb24gY2xlYXJBcnJheShhcnIpIHtcbiAgICBhcnIuc3BsaWNlKDAsIGFyci5sZW5ndGgpO1xuICB9O1xuICB2YXIgcHVzaCA9IGZ1bmN0aW9uIHB1c2goYXJyLCBvdGhlckFycikge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb3RoZXJBcnIubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBlbCA9IG90aGVyQXJyW2ldO1xuICAgICAgYXJyLnB1c2goZWwpO1xuICAgIH1cbiAgfTtcbiAgdmFyIGdldFByZWZpeGVkUHJvcGVydHkgPSBmdW5jdGlvbiBnZXRQcmVmaXhlZFByb3BlcnR5KG9iaiwgcHJvcE5hbWUsIHByZWZpeCkge1xuICAgIGlmIChwcmVmaXgpIHtcbiAgICAgIHByb3BOYW1lID0gcHJlcGVuZENhbWVsKHByZWZpeCwgcHJvcE5hbWUpOyAvLyBlLmcuIChsYWJlbFdpZHRoLCBzb3VyY2UpID0+IHNvdXJjZUxhYmVsV2lkdGhcbiAgICB9XG5cbiAgICByZXR1cm4gb2JqW3Byb3BOYW1lXTtcbiAgfTtcbiAgdmFyIHNldFByZWZpeGVkUHJvcGVydHkgPSBmdW5jdGlvbiBzZXRQcmVmaXhlZFByb3BlcnR5KG9iaiwgcHJvcE5hbWUsIHByZWZpeCwgdmFsdWUpIHtcbiAgICBpZiAocHJlZml4KSB7XG4gICAgICBwcm9wTmFtZSA9IHByZXBlbmRDYW1lbChwcmVmaXgsIHByb3BOYW1lKTsgLy8gZS5nLiAobGFiZWxXaWR0aCwgc291cmNlKSA9PiBzb3VyY2VMYWJlbFdpZHRoXG4gICAgfVxuXG4gICAgb2JqW3Byb3BOYW1lXSA9IHZhbHVlO1xuICB9O1xuXG4gIC8qIGdsb2JhbCBNYXAgKi9cbiAgdmFyIE9iamVjdE1hcCA9IC8qI19fUFVSRV9fKi9mdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gT2JqZWN0TWFwKCkge1xuICAgICAgX2NsYXNzQ2FsbENoZWNrKHRoaXMsIE9iamVjdE1hcCk7XG5cbiAgICAgIHRoaXMuX29iaiA9IHt9O1xuICAgIH1cblxuICAgIF9jcmVhdGVDbGFzcyhPYmplY3RNYXAsIFt7XG4gICAgICBrZXk6IFwic2V0XCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gc2V0KGtleSwgdmFsKSB7XG4gICAgICAgIHRoaXMuX29ialtrZXldID0gdmFsO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiZGVsZXRlXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gX2RlbGV0ZShrZXkpIHtcbiAgICAgICAgdGhpcy5fb2JqW2tleV0gPSB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJjbGVhclwiLFxuICAgICAgdmFsdWU6IGZ1bmN0aW9uIGNsZWFyKCkge1xuICAgICAgICB0aGlzLl9vYmogPSB7fTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiaGFzXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gaGFzKGtleSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fb2JqW2tleV0gIT09IHVuZGVmaW5lZDtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiZ2V0XCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gZ2V0KGtleSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fb2JqW2tleV07XG4gICAgICB9XG4gICAgfV0pO1xuXG4gICAgcmV0dXJuIE9iamVjdE1hcDtcbiAgfSgpO1xuXG4gIHZhciBNYXAkMiA9IHR5cGVvZiBNYXAgIT09ICd1bmRlZmluZWQnID8gTWFwIDogT2JqZWN0TWFwO1xuXG4gIC8qIGdsb2JhbCBTZXQgKi9cbiAgdmFyIHVuZGVmID0gXCJ1bmRlZmluZWRcIiA7XG5cbiAgdmFyIE9iamVjdFNldCA9IC8qI19fUFVSRV9fKi9mdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gT2JqZWN0U2V0KGFycmF5T3JPYmplY3RTZXQpIHtcbiAgICAgIF9jbGFzc0NhbGxDaGVjayh0aGlzLCBPYmplY3RTZXQpO1xuXG4gICAgICB0aGlzLl9vYmogPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuICAgICAgdGhpcy5zaXplID0gMDtcblxuICAgICAgaWYgKGFycmF5T3JPYmplY3RTZXQgIT0gbnVsbCkge1xuICAgICAgICB2YXIgYXJyO1xuXG4gICAgICAgIGlmIChhcnJheU9yT2JqZWN0U2V0Lmluc3RhbmNlU3RyaW5nICE9IG51bGwgJiYgYXJyYXlPck9iamVjdFNldC5pbnN0YW5jZVN0cmluZygpID09PSB0aGlzLmluc3RhbmNlU3RyaW5nKCkpIHtcbiAgICAgICAgICBhcnIgPSBhcnJheU9yT2JqZWN0U2V0LnRvQXJyYXkoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBhcnIgPSBhcnJheU9yT2JqZWN0U2V0O1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcnIubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB0aGlzLmFkZChhcnJbaV0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgX2NyZWF0ZUNsYXNzKE9iamVjdFNldCwgW3tcbiAgICAgIGtleTogXCJpbnN0YW5jZVN0cmluZ1wiLFxuICAgICAgdmFsdWU6IGZ1bmN0aW9uIGluc3RhbmNlU3RyaW5nKCkge1xuICAgICAgICByZXR1cm4gJ3NldCc7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcImFkZFwiLFxuICAgICAgdmFsdWU6IGZ1bmN0aW9uIGFkZCh2YWwpIHtcbiAgICAgICAgdmFyIG8gPSB0aGlzLl9vYmo7XG5cbiAgICAgICAgaWYgKG9bdmFsXSAhPT0gMSkge1xuICAgICAgICAgIG9bdmFsXSA9IDE7XG4gICAgICAgICAgdGhpcy5zaXplKys7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiZGVsZXRlXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gX2RlbGV0ZSh2YWwpIHtcbiAgICAgICAgdmFyIG8gPSB0aGlzLl9vYmo7XG5cbiAgICAgICAgaWYgKG9bdmFsXSA9PT0gMSkge1xuICAgICAgICAgIG9bdmFsXSA9IDA7XG4gICAgICAgICAgdGhpcy5zaXplLS07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiY2xlYXJcIixcbiAgICAgIHZhbHVlOiBmdW5jdGlvbiBjbGVhcigpIHtcbiAgICAgICAgdGhpcy5fb2JqID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiaGFzXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gaGFzKHZhbCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fb2JqW3ZhbF0gPT09IDE7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcInRvQXJyYXlcIixcbiAgICAgIHZhbHVlOiBmdW5jdGlvbiB0b0FycmF5KCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLl9vYmopLmZpbHRlcihmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgcmV0dXJuIF90aGlzLmhhcyhrZXkpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiZm9yRWFjaFwiLFxuICAgICAgdmFsdWU6IGZ1bmN0aW9uIGZvckVhY2goY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudG9BcnJheSgpLmZvckVhY2goY2FsbGJhY2ssIHRoaXNBcmcpO1xuICAgICAgfVxuICAgIH1dKTtcblxuICAgIHJldHVybiBPYmplY3RTZXQ7XG4gIH0oKTtcblxuICB2YXIgU2V0JDEgPSAodHlwZW9mIFNldCA9PT0gXCJ1bmRlZmluZWRcIiA/IFwidW5kZWZpbmVkXCIgOiBfdHlwZW9mKFNldCkpICE9PSB1bmRlZiA/IFNldCA6IE9iamVjdFNldDtcblxuICB2YXIgRWxlbWVudCA9IGZ1bmN0aW9uIEVsZW1lbnQoY3ksIHBhcmFtcykge1xuICAgIHZhciByZXN0b3JlID0gYXJndW1lbnRzLmxlbmd0aCA+IDIgJiYgYXJndW1lbnRzWzJdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMl0gOiB0cnVlO1xuXG4gICAgaWYgKGN5ID09PSB1bmRlZmluZWQgfHwgcGFyYW1zID09PSB1bmRlZmluZWQgfHwgIWNvcmUoY3kpKSB7XG4gICAgICBlcnJvcignQW4gZWxlbWVudCBtdXN0IGhhdmUgYSBjb3JlIHJlZmVyZW5jZSBhbmQgcGFyYW1ldGVycyBzZXQnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZ3JvdXAgPSBwYXJhbXMuZ3JvdXA7IC8vIHRyeSB0byBhdXRvbWF0aWNhbGx5IGluZmVyIHRoZSBncm91cCBpZiB1bnNwZWNpZmllZFxuXG4gICAgaWYgKGdyb3VwID09IG51bGwpIHtcbiAgICAgIGlmIChwYXJhbXMuZGF0YSAmJiBwYXJhbXMuZGF0YS5zb3VyY2UgIT0gbnVsbCAmJiBwYXJhbXMuZGF0YS50YXJnZXQgIT0gbnVsbCkge1xuICAgICAgICBncm91cCA9ICdlZGdlcyc7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBncm91cCA9ICdub2Rlcyc7XG4gICAgICB9XG4gICAgfSAvLyB2YWxpZGF0ZSBncm91cFxuXG5cbiAgICBpZiAoZ3JvdXAgIT09ICdub2RlcycgJiYgZ3JvdXAgIT09ICdlZGdlcycpIHtcbiAgICAgIGVycm9yKCdBbiBlbGVtZW50IG11c3QgYmUgb2YgdHlwZSBgbm9kZXNgIG9yIGBlZGdlc2A7IHlvdSBzcGVjaWZpZWQgYCcgKyBncm91cCArICdgJyk7XG4gICAgICByZXR1cm47XG4gICAgfSAvLyBtYWtlIHRoZSBlbGVtZW50IGFycmF5LWxpa2UsIGp1c3QgbGlrZSBhIGNvbGxlY3Rpb25cblxuXG4gICAgdGhpcy5sZW5ndGggPSAxO1xuICAgIHRoaXNbMF0gPSB0aGlzOyAvLyBOT1RFOiB3aGVuIHNvbWV0aGluZyBpcyBhZGRlZCBoZXJlLCBhZGQgYWxzbyB0byBlbGUuanNvbigpXG5cbiAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlID0ge1xuICAgICAgY3k6IGN5LFxuICAgICAgc2luZ2xlOiB0cnVlLFxuICAgICAgLy8gaW5kaWNhdGVzIHRoaXMgaXMgYW4gZWxlbWVudFxuICAgICAgZGF0YTogcGFyYW1zLmRhdGEgfHwge30sXG4gICAgICAvLyBkYXRhIG9iamVjdFxuICAgICAgcG9zaXRpb246IHBhcmFtcy5wb3NpdGlvbiB8fCB7XG4gICAgICAgIHg6IDAsXG4gICAgICAgIHk6IDBcbiAgICAgIH0sXG4gICAgICAvLyAoeCwgeSkgcG9zaXRpb24gcGFpclxuICAgICAgYXV0b1dpZHRoOiB1bmRlZmluZWQsXG4gICAgICAvLyB3aWR0aCBhbmQgaGVpZ2h0IG9mIG5vZGVzIGNhbGN1bGF0ZWQgYnkgdGhlIHJlbmRlcmVyIHdoZW4gc2V0IHRvIHNwZWNpYWwgJ2F1dG8nIHZhbHVlXG4gICAgICBhdXRvSGVpZ2h0OiB1bmRlZmluZWQsXG4gICAgICBhdXRvUGFkZGluZzogdW5kZWZpbmVkLFxuICAgICAgY29tcG91bmRCb3VuZHNDbGVhbjogZmFsc2UsXG4gICAgICAvLyB3aGV0aGVyIHRoZSBjb21wb3VuZCBkaW1lbnNpb25zIG5lZWQgdG8gYmUgcmVjYWxjdWxhdGVkIHRoZSBuZXh0IHRpbWUgZGltZW5zaW9ucyBhcmUgcmVhZFxuICAgICAgbGlzdGVuZXJzOiBbXSxcbiAgICAgIC8vIGFycmF5IG9mIGJvdW5kIGxpc3RlbmVyc1xuICAgICAgZ3JvdXA6IGdyb3VwLFxuICAgICAgLy8gc3RyaW5nOyAnbm9kZXMnIG9yICdlZGdlcydcbiAgICAgIHN0eWxlOiB7fSxcbiAgICAgIC8vIHByb3BlcnRpZXMgYXMgc2V0IGJ5IHRoZSBzdHlsZVxuICAgICAgcnN0eWxlOiB7fSxcbiAgICAgIC8vIHByb3BlcnRpZXMgZm9yIHN0eWxlIHNlbnQgZnJvbSB0aGUgcmVuZGVyZXIgdG8gdGhlIGNvcmVcbiAgICAgIHN0eWxlQ3h0czogW10sXG4gICAgICAvLyBhcHBsaWVkIHN0eWxlIGNvbnRleHRzIGZyb20gdGhlIHN0eWxlclxuICAgICAgc3R5bGVLZXlzOiB7fSxcbiAgICAgIC8vIHBlci1ncm91cCBrZXlzIG9mIHN0eWxlIHByb3BlcnR5IHZhbHVlc1xuICAgICAgcmVtb3ZlZDogdHJ1ZSxcbiAgICAgIC8vIHdoZXRoZXIgaXQncyBpbnNpZGUgdGhlIHZpczsgdHJ1ZSBpZiByZW1vdmVkIChzZXQgdHJ1ZSBoZXJlIHNpbmNlIHdlIGNhbGwgcmVzdG9yZSlcbiAgICAgIHNlbGVjdGVkOiBwYXJhbXMuc2VsZWN0ZWQgPyB0cnVlIDogZmFsc2UsXG4gICAgICAvLyB3aGV0aGVyIGl0J3Mgc2VsZWN0ZWRcbiAgICAgIHNlbGVjdGFibGU6IHBhcmFtcy5zZWxlY3RhYmxlID09PSB1bmRlZmluZWQgPyB0cnVlIDogcGFyYW1zLnNlbGVjdGFibGUgPyB0cnVlIDogZmFsc2UsXG4gICAgICAvLyB3aGV0aGVyIGl0J3Mgc2VsZWN0YWJsZVxuICAgICAgbG9ja2VkOiBwYXJhbXMubG9ja2VkID8gdHJ1ZSA6IGZhbHNlLFxuICAgICAgLy8gd2hldGhlciB0aGUgZWxlbWVudCBpcyBsb2NrZWQgKGNhbm5vdCBiZSBtb3ZlZClcbiAgICAgIGdyYWJiZWQ6IGZhbHNlLFxuICAgICAgLy8gd2hldGhlciB0aGUgZWxlbWVudCBpcyBncmFiYmVkIGJ5IHRoZSBtb3VzZTsgcmVuZGVyZXIgc2V0cyB0aGlzIHByaXZhdGVseVxuICAgICAgZ3JhYmJhYmxlOiBwYXJhbXMuZ3JhYmJhYmxlID09PSB1bmRlZmluZWQgPyB0cnVlIDogcGFyYW1zLmdyYWJiYWJsZSA/IHRydWUgOiBmYWxzZSxcbiAgICAgIC8vIHdoZXRoZXIgdGhlIGVsZW1lbnQgY2FuIGJlIGdyYWJiZWRcbiAgICAgIHBhbm5hYmxlOiBwYXJhbXMucGFubmFibGUgPT09IHVuZGVmaW5lZCA/IGdyb3VwID09PSAnZWRnZXMnID8gdHJ1ZSA6IGZhbHNlIDogcGFyYW1zLnBhbm5hYmxlID8gdHJ1ZSA6IGZhbHNlLFxuICAgICAgLy8gd2hldGhlciB0aGUgZWxlbWVudCBoYXMgcGFzc3Rocm91Z2ggcGFubmluZyBlbmFibGVkXG4gICAgICBhY3RpdmU6IGZhbHNlLFxuICAgICAgLy8gd2hldGhlciB0aGUgZWxlbWVudCBpcyBhY3RpdmUgZnJvbSB1c2VyIGludGVyYWN0aW9uXG4gICAgICBjbGFzc2VzOiBuZXcgU2V0JDEoKSxcbiAgICAgIC8vIG1hcCAoIGNsYXNzTmFtZSA9PiB0cnVlIClcbiAgICAgIGFuaW1hdGlvbjoge1xuICAgICAgICAvLyBvYmplY3QgZm9yIGN1cnJlbnRseS1ydW5uaW5nIGFuaW1hdGlvbnNcbiAgICAgICAgY3VycmVudDogW10sXG4gICAgICAgIHF1ZXVlOiBbXVxuICAgICAgfSxcbiAgICAgIHJzY3JhdGNoOiB7fSxcbiAgICAgIC8vIG9iamVjdCBpbiB3aGljaCB0aGUgcmVuZGVyZXIgY2FuIHN0b3JlIGluZm9ybWF0aW9uXG4gICAgICBzY3JhdGNoOiBwYXJhbXMuc2NyYXRjaCB8fCB7fSxcbiAgICAgIC8vIHNjcmF0Y2ggb2JqZWN0c1xuICAgICAgZWRnZXM6IFtdLFxuICAgICAgLy8gYXJyYXkgb2YgY29ubmVjdGVkIGVkZ2VzXG4gICAgICBjaGlsZHJlbjogW10sXG4gICAgICAvLyBhcnJheSBvZiBjaGlsZHJlblxuICAgICAgcGFyZW50OiBwYXJhbXMucGFyZW50ICYmIHBhcmFtcy5wYXJlbnQuaXNOb2RlKCkgPyBwYXJhbXMucGFyZW50IDogbnVsbCxcbiAgICAgIC8vIHBhcmVudCByZWZcbiAgICAgIHRyYXZlcnNhbENhY2hlOiB7fSxcbiAgICAgIC8vIGNhY2hlIG9mIG91dHB1dCBvZiB0cmF2ZXJzYWwgZnVuY3Rpb25zXG4gICAgICBiYWNrZ3JvdW5kaW5nOiBmYWxzZSxcbiAgICAgIC8vIHdoZXRoZXIgYmFja2dyb3VuZCBpbWFnZXMgYXJlIGxvYWRpbmdcbiAgICAgIGJiQ2FjaGU6IG51bGwsXG4gICAgICAvLyBjYWNoZSBvZiB0aGUgY3VycmVudCBib3VuZGluZyBib3hcbiAgICAgIGJiQ2FjaGVTaGlmdDoge1xuICAgICAgICB4OiAwLFxuICAgICAgICB5OiAwXG4gICAgICB9LFxuICAgICAgLy8gc2hpZnQgYXBwbGllZCB0byBjYWNoZWQgYmIgdG8gYmUgYXBwbGllZCBvbiBuZXh0IGdldFxuICAgICAgYm9keUJvdW5kczogbnVsbCxcbiAgICAgIC8vIGJvdW5kcyBjYWNoZSBvZiBlbGVtZW50IGJvZHksIHcvbyBvdmVybGF5XG4gICAgICBvdmVybGF5Qm91bmRzOiBudWxsLFxuICAgICAgLy8gYm91bmRzIGNhY2hlIG9mIGVsZW1lbnQgYm9keSwgaW5jbHVkaW5nIG92ZXJsYXlcbiAgICAgIGxhYmVsQm91bmRzOiB7XG4gICAgICAgIC8vIGJvdW5kcyBjYWNoZSBvZiBsYWJlbHNcbiAgICAgICAgYWxsOiBudWxsLFxuICAgICAgICBzb3VyY2U6IG51bGwsXG4gICAgICAgIHRhcmdldDogbnVsbCxcbiAgICAgICAgbWFpbjogbnVsbFxuICAgICAgfSxcbiAgICAgIGFycm93Qm91bmRzOiB7XG4gICAgICAgIC8vIGJvdW5kcyBjYWNoZSBvZiBlZGdlIGFycm93c1xuICAgICAgICBzb3VyY2U6IG51bGwsXG4gICAgICAgIHRhcmdldDogbnVsbCxcbiAgICAgICAgJ21pZC1zb3VyY2UnOiBudWxsLFxuICAgICAgICAnbWlkLXRhcmdldCc6IG51bGxcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgaWYgKF9wLnBvc2l0aW9uLnggPT0gbnVsbCkge1xuICAgICAgX3AucG9zaXRpb24ueCA9IDA7XG4gICAgfVxuXG4gICAgaWYgKF9wLnBvc2l0aW9uLnkgPT0gbnVsbCkge1xuICAgICAgX3AucG9zaXRpb24ueSA9IDA7XG4gICAgfSAvLyByZW5kZXJlZFBvc2l0aW9uIG92ZXJyaWRlcyBpZiBzcGVjaWZpZWRcblxuXG4gICAgaWYgKHBhcmFtcy5yZW5kZXJlZFBvc2l0aW9uKSB7XG4gICAgICB2YXIgcnBvcyA9IHBhcmFtcy5yZW5kZXJlZFBvc2l0aW9uO1xuICAgICAgdmFyIHBhbiA9IGN5LnBhbigpO1xuICAgICAgdmFyIHpvb20gPSBjeS56b29tKCk7XG4gICAgICBfcC5wb3NpdGlvbiA9IHtcbiAgICAgICAgeDogKHJwb3MueCAtIHBhbi54KSAvIHpvb20sXG4gICAgICAgIHk6IChycG9zLnkgLSBwYW4ueSkgLyB6b29tXG4gICAgICB9O1xuICAgIH1cblxuICAgIHZhciBjbGFzc2VzID0gW107XG5cbiAgICBpZiAoYXJyYXkocGFyYW1zLmNsYXNzZXMpKSB7XG4gICAgICBjbGFzc2VzID0gcGFyYW1zLmNsYXNzZXM7XG4gICAgfSBlbHNlIGlmIChzdHJpbmcocGFyYW1zLmNsYXNzZXMpKSB7XG4gICAgICBjbGFzc2VzID0gcGFyYW1zLmNsYXNzZXMuc3BsaXQoL1xccysvKTtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBpID0gMCwgbCA9IGNsYXNzZXMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICB2YXIgY2xzID0gY2xhc3Nlc1tpXTtcblxuICAgICAgaWYgKCFjbHMgfHwgY2xzID09PSAnJykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgX3AuY2xhc3Nlcy5hZGQoY2xzKTtcbiAgICB9XG5cbiAgICB0aGlzLmNyZWF0ZUVtaXR0ZXIoKTtcbiAgICB2YXIgYnlwYXNzID0gcGFyYW1zLnN0eWxlIHx8IHBhcmFtcy5jc3M7XG5cbiAgICBpZiAoYnlwYXNzKSB7XG4gICAgICB3YXJuKCdTZXR0aW5nIGEgYHN0eWxlYCBieXBhc3MgYXQgZWxlbWVudCBjcmVhdGlvbiBzaG91bGQgYmUgZG9uZSBvbmx5IHdoZW4gYWJzb2x1dGVseSBuZWNlc3NhcnkuICBUcnkgdG8gdXNlIHRoZSBzdHlsZXNoZWV0IGluc3RlYWQuJyk7XG4gICAgICB0aGlzLnN0eWxlKGJ5cGFzcyk7XG4gICAgfVxuXG4gICAgaWYgKHJlc3RvcmUgPT09IHVuZGVmaW5lZCB8fCByZXN0b3JlKSB7XG4gICAgICB0aGlzLnJlc3RvcmUoKTtcbiAgICB9XG4gIH07XG5cbiAgdmFyIGRlZmluZVNlYXJjaCA9IGZ1bmN0aW9uIGRlZmluZVNlYXJjaChwYXJhbXMpIHtcbiAgICBwYXJhbXMgPSB7XG4gICAgICBiZnM6IHBhcmFtcy5iZnMgfHwgIXBhcmFtcy5kZnMsXG4gICAgICBkZnM6IHBhcmFtcy5kZnMgfHwgIXBhcmFtcy5iZnNcbiAgICB9OyAvLyBmcm9tIHBzZXVkb2NvZGUgb24gd2lraXBlZGlhXG5cbiAgICByZXR1cm4gZnVuY3Rpb24gc2VhcmNoRm4ocm9vdHMsIGZuLCBkaXJlY3RlZCkge1xuICAgICAgdmFyIG9wdGlvbnM7XG5cbiAgICAgIGlmIChwbGFpbk9iamVjdChyb290cykgJiYgIWVsZW1lbnRPckNvbGxlY3Rpb24ocm9vdHMpKSB7XG4gICAgICAgIG9wdGlvbnMgPSByb290cztcbiAgICAgICAgcm9vdHMgPSBvcHRpb25zLnJvb3RzIHx8IG9wdGlvbnMucm9vdDtcbiAgICAgICAgZm4gPSBvcHRpb25zLnZpc2l0O1xuICAgICAgICBkaXJlY3RlZCA9IG9wdGlvbnMuZGlyZWN0ZWQ7XG4gICAgICB9XG5cbiAgICAgIGRpcmVjdGVkID0gYXJndW1lbnRzLmxlbmd0aCA9PT0gMiAmJiAhZm4kNihmbikgPyBmbiA6IGRpcmVjdGVkO1xuICAgICAgZm4gPSBmbiQ2KGZuKSA/IGZuIDogZnVuY3Rpb24gKCkge307XG4gICAgICB2YXIgY3kgPSB0aGlzLl9wcml2YXRlLmN5O1xuICAgICAgdmFyIHYgPSByb290cyA9IHN0cmluZyhyb290cykgPyB0aGlzLmZpbHRlcihyb290cykgOiByb290cztcbiAgICAgIHZhciBRID0gW107XG4gICAgICB2YXIgY29ubmVjdGVkTm9kZXMgPSBbXTtcbiAgICAgIHZhciBjb25uZWN0ZWRCeSA9IHt9O1xuICAgICAgdmFyIGlkMmRlcHRoID0ge307XG4gICAgICB2YXIgViA9IHt9O1xuICAgICAgdmFyIGogPSAwO1xuICAgICAgdmFyIGZvdW5kO1xuXG4gICAgICB2YXIgX3RoaXMkYnlHcm91cCA9IHRoaXMuYnlHcm91cCgpLFxuICAgICAgICAgIG5vZGVzID0gX3RoaXMkYnlHcm91cC5ub2RlcyxcbiAgICAgICAgICBlZGdlcyA9IF90aGlzJGJ5R3JvdXAuZWRnZXM7IC8vIGVucXVldWUgdlxuXG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdi5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgdmkgPSB2W2ldO1xuICAgICAgICB2YXIgdmlJZCA9IHZpLmlkKCk7XG5cbiAgICAgICAgaWYgKHZpLmlzTm9kZSgpKSB7XG4gICAgICAgICAgUS51bnNoaWZ0KHZpKTtcblxuICAgICAgICAgIGlmIChwYXJhbXMuYmZzKSB7XG4gICAgICAgICAgICBWW3ZpSWRdID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbm5lY3RlZE5vZGVzLnB1c2godmkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlkMmRlcHRoW3ZpSWRdID0gMDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB2YXIgX2xvb3AgPSBmdW5jdGlvbiBfbG9vcCgpIHtcbiAgICAgICAgdmFyIHYgPSBwYXJhbXMuYmZzID8gUS5zaGlmdCgpIDogUS5wb3AoKTtcbiAgICAgICAgdmFyIHZJZCA9IHYuaWQoKTtcblxuICAgICAgICBpZiAocGFyYW1zLmRmcykge1xuICAgICAgICAgIGlmIChWW3ZJZF0pIHtcbiAgICAgICAgICAgIHJldHVybiBcImNvbnRpbnVlXCI7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgVlt2SWRdID0gdHJ1ZTtcbiAgICAgICAgICBjb25uZWN0ZWROb2Rlcy5wdXNoKHYpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRlcHRoID0gaWQyZGVwdGhbdklkXTtcbiAgICAgICAgdmFyIHByZXZFZGdlID0gY29ubmVjdGVkQnlbdklkXTtcbiAgICAgICAgdmFyIHNyYyA9IHByZXZFZGdlICE9IG51bGwgPyBwcmV2RWRnZS5zb3VyY2UoKSA6IG51bGw7XG4gICAgICAgIHZhciB0Z3QgPSBwcmV2RWRnZSAhPSBudWxsID8gcHJldkVkZ2UudGFyZ2V0KCkgOiBudWxsO1xuICAgICAgICB2YXIgcHJldk5vZGUgPSBwcmV2RWRnZSA9PSBudWxsID8gdW5kZWZpbmVkIDogdi5zYW1lKHNyYykgPyB0Z3RbMF0gOiBzcmNbMF07XG4gICAgICAgIHZhciByZXQgPSB2b2lkIDA7XG4gICAgICAgIHJldCA9IGZuKHYsIHByZXZFZGdlLCBwcmV2Tm9kZSwgaisrLCBkZXB0aCk7XG5cbiAgICAgICAgaWYgKHJldCA9PT0gdHJ1ZSkge1xuICAgICAgICAgIGZvdW5kID0gdjtcbiAgICAgICAgICByZXR1cm4gXCJicmVha1wiO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJldCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICByZXR1cm4gXCJicmVha1wiO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHZ3RWRnZXMgPSB2LmNvbm5lY3RlZEVkZ2VzKCkuZmlsdGVyKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgcmV0dXJuICghZGlyZWN0ZWQgfHwgZS5zb3VyY2UoKS5zYW1lKHYpKSAmJiBlZGdlcy5oYXMoZSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IHZ3RWRnZXMubGVuZ3RoOyBfaTIrKykge1xuICAgICAgICAgIHZhciBlID0gdndFZGdlc1tfaTJdO1xuICAgICAgICAgIHZhciB3ID0gZS5jb25uZWN0ZWROb2RlcygpLmZpbHRlcihmdW5jdGlvbiAobikge1xuICAgICAgICAgICAgcmV0dXJuICFuLnNhbWUodikgJiYgbm9kZXMuaGFzKG4pO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIHZhciB3SWQgPSB3LmlkKCk7XG5cbiAgICAgICAgICBpZiAody5sZW5ndGggIT09IDAgJiYgIVZbd0lkXSkge1xuICAgICAgICAgICAgdyA9IHdbMF07XG4gICAgICAgICAgICBRLnB1c2godyk7XG5cbiAgICAgICAgICAgIGlmIChwYXJhbXMuYmZzKSB7XG4gICAgICAgICAgICAgIFZbd0lkXSA9IHRydWU7XG4gICAgICAgICAgICAgIGNvbm5lY3RlZE5vZGVzLnB1c2godyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbm5lY3RlZEJ5W3dJZF0gPSBlO1xuICAgICAgICAgICAgaWQyZGVwdGhbd0lkXSA9IGlkMmRlcHRoW3ZJZF0gKyAxO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgd2hpbGUgKFEubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgIHZhciBfcmV0ID0gX2xvb3AoKTtcblxuICAgICAgICBpZiAoX3JldCA9PT0gXCJjb250aW51ZVwiKSBjb250aW51ZTtcbiAgICAgICAgaWYgKF9yZXQgPT09IFwiYnJlYWtcIikgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIHZhciBjb25uZWN0ZWRFbGVzID0gY3kuY29sbGVjdGlvbigpO1xuXG4gICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgY29ubmVjdGVkTm9kZXMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciBub2RlID0gY29ubmVjdGVkTm9kZXNbX2ldO1xuICAgICAgICB2YXIgZWRnZSA9IGNvbm5lY3RlZEJ5W25vZGUuaWQoKV07XG5cbiAgICAgICAgaWYgKGVkZ2UgIT0gbnVsbCkge1xuICAgICAgICAgIGNvbm5lY3RlZEVsZXMucHVzaChlZGdlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbm5lY3RlZEVsZXMucHVzaChub2RlKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcGF0aDogY3kuY29sbGVjdGlvbihjb25uZWN0ZWRFbGVzKSxcbiAgICAgICAgZm91bmQ6IGN5LmNvbGxlY3Rpb24oZm91bmQpXG4gICAgICB9O1xuICAgIH07XG4gIH07IC8vIHNlYXJjaCwgc3Bhbm5pbmcgdHJlZXMsIGV0Y1xuXG5cbiAgdmFyIGVsZXNmbiR2ID0ge1xuICAgIGJyZWFkdGhGaXJzdFNlYXJjaDogZGVmaW5lU2VhcmNoKHtcbiAgICAgIGJmczogdHJ1ZVxuICAgIH0pLFxuICAgIGRlcHRoRmlyc3RTZWFyY2g6IGRlZmluZVNlYXJjaCh7XG4gICAgICBkZnM6IHRydWVcbiAgICB9KVxuICB9OyAvLyBuaWNlLCBzaG9ydCBtYXRoZW1hdGljYWwgYWxpYXNcblxuICBlbGVzZm4kdi5iZnMgPSBlbGVzZm4kdi5icmVhZHRoRmlyc3RTZWFyY2g7XG4gIGVsZXNmbiR2LmRmcyA9IGVsZXNmbiR2LmRlcHRoRmlyc3RTZWFyY2g7XG5cbiAgdmFyIGhlYXAkMSA9IGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUsIGV4cG9ydHMpIHtcbiAgLy8gR2VuZXJhdGVkIGJ5IENvZmZlZVNjcmlwdCAxLjguMFxuICAoZnVuY3Rpb24oKSB7XG4gICAgdmFyIEhlYXAsIGRlZmF1bHRDbXAsIGZsb29yLCBoZWFwaWZ5LCBoZWFwcG9wLCBoZWFwcHVzaCwgaGVhcHB1c2hwb3AsIGhlYXByZXBsYWNlLCBpbnNvcnQsIG1pbiwgbmxhcmdlc3QsIG5zbWFsbGVzdCwgdXBkYXRlSXRlbSwgX3NpZnRkb3duLCBfc2lmdHVwO1xuXG4gICAgZmxvb3IgPSBNYXRoLmZsb29yLCBtaW4gPSBNYXRoLm1pbjtcblxuXG4gICAgLypcbiAgICBEZWZhdWx0IGNvbXBhcmlzb24gZnVuY3Rpb24gdG8gYmUgdXNlZFxuICAgICAqL1xuXG4gICAgZGVmYXVsdENtcCA9IGZ1bmN0aW9uKHgsIHkpIHtcbiAgICAgIGlmICh4IDwgeSkge1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgICB9XG4gICAgICBpZiAoeCA+IHkpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICB9XG4gICAgICByZXR1cm4gMDtcbiAgICB9O1xuXG5cbiAgICAvKlxuICAgIEluc2VydCBpdGVtIHggaW4gbGlzdCBhLCBhbmQga2VlcCBpdCBzb3J0ZWQgYXNzdW1pbmcgYSBpcyBzb3J0ZWQuXG4gICAgXG4gICAgSWYgeCBpcyBhbHJlYWR5IGluIGEsIGluc2VydCBpdCB0byB0aGUgcmlnaHQgb2YgdGhlIHJpZ2h0bW9zdCB4LlxuICAgIFxuICAgIE9wdGlvbmFsIGFyZ3MgbG8gKGRlZmF1bHQgMCkgYW5kIGhpIChkZWZhdWx0IGEubGVuZ3RoKSBib3VuZCB0aGUgc2xpY2VcbiAgICBvZiBhIHRvIGJlIHNlYXJjaGVkLlxuICAgICAqL1xuXG4gICAgaW5zb3J0ID0gZnVuY3Rpb24oYSwgeCwgbG8sIGhpLCBjbXApIHtcbiAgICAgIHZhciBtaWQ7XG4gICAgICBpZiAobG8gPT0gbnVsbCkge1xuICAgICAgICBsbyA9IDA7XG4gICAgICB9XG4gICAgICBpZiAoY21wID09IG51bGwpIHtcbiAgICAgICAgY21wID0gZGVmYXVsdENtcDtcbiAgICAgIH1cbiAgICAgIGlmIChsbyA8IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdsbyBtdXN0IGJlIG5vbi1uZWdhdGl2ZScpO1xuICAgICAgfVxuICAgICAgaWYgKGhpID09IG51bGwpIHtcbiAgICAgICAgaGkgPSBhLmxlbmd0aDtcbiAgICAgIH1cbiAgICAgIHdoaWxlIChsbyA8IGhpKSB7XG4gICAgICAgIG1pZCA9IGZsb29yKChsbyArIGhpKSAvIDIpO1xuICAgICAgICBpZiAoY21wKHgsIGFbbWlkXSkgPCAwKSB7XG4gICAgICAgICAgaGkgPSBtaWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbG8gPSBtaWQgKyAxO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gKFtdLnNwbGljZS5hcHBseShhLCBbbG8sIGxvIC0gbG9dLmNvbmNhdCh4KSksIHgpO1xuICAgIH07XG5cblxuICAgIC8qXG4gICAgUHVzaCBpdGVtIG9udG8gaGVhcCwgbWFpbnRhaW5pbmcgdGhlIGhlYXAgaW52YXJpYW50LlxuICAgICAqL1xuXG4gICAgaGVhcHB1c2ggPSBmdW5jdGlvbihhcnJheSwgaXRlbSwgY21wKSB7XG4gICAgICBpZiAoY21wID09IG51bGwpIHtcbiAgICAgICAgY21wID0gZGVmYXVsdENtcDtcbiAgICAgIH1cbiAgICAgIGFycmF5LnB1c2goaXRlbSk7XG4gICAgICByZXR1cm4gX3NpZnRkb3duKGFycmF5LCAwLCBhcnJheS5sZW5ndGggLSAxLCBjbXApO1xuICAgIH07XG5cblxuICAgIC8qXG4gICAgUG9wIHRoZSBzbWFsbGVzdCBpdGVtIG9mZiB0aGUgaGVhcCwgbWFpbnRhaW5pbmcgdGhlIGhlYXAgaW52YXJpYW50LlxuICAgICAqL1xuXG4gICAgaGVhcHBvcCA9IGZ1bmN0aW9uKGFycmF5LCBjbXApIHtcbiAgICAgIHZhciBsYXN0ZWx0LCByZXR1cm5pdGVtO1xuICAgICAgaWYgKGNtcCA9PSBudWxsKSB7XG4gICAgICAgIGNtcCA9IGRlZmF1bHRDbXA7XG4gICAgICB9XG4gICAgICBsYXN0ZWx0ID0gYXJyYXkucG9wKCk7XG4gICAgICBpZiAoYXJyYXkubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybml0ZW0gPSBhcnJheVswXTtcbiAgICAgICAgYXJyYXlbMF0gPSBsYXN0ZWx0O1xuICAgICAgICBfc2lmdHVwKGFycmF5LCAwLCBjbXApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuaXRlbSA9IGxhc3RlbHQ7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmV0dXJuaXRlbTtcbiAgICB9O1xuXG5cbiAgICAvKlxuICAgIFBvcCBhbmQgcmV0dXJuIHRoZSBjdXJyZW50IHNtYWxsZXN0IHZhbHVlLCBhbmQgYWRkIHRoZSBuZXcgaXRlbS5cbiAgICBcbiAgICBUaGlzIGlzIG1vcmUgZWZmaWNpZW50IHRoYW4gaGVhcHBvcCgpIGZvbGxvd2VkIGJ5IGhlYXBwdXNoKCksIGFuZCBjYW4gYmVcbiAgICBtb3JlIGFwcHJvcHJpYXRlIHdoZW4gdXNpbmcgYSBmaXhlZCBzaXplIGhlYXAuIE5vdGUgdGhhdCB0aGUgdmFsdWVcbiAgICByZXR1cm5lZCBtYXkgYmUgbGFyZ2VyIHRoYW4gaXRlbSEgVGhhdCBjb25zdHJhaW5zIHJlYXNvbmFibGUgdXNlIG9mXG4gICAgdGhpcyByb3V0aW5lIHVubGVzcyB3cml0dGVuIGFzIHBhcnQgb2YgYSBjb25kaXRpb25hbCByZXBsYWNlbWVudDpcbiAgICAgICAgaWYgaXRlbSA+IGFycmF5WzBdXG4gICAgICAgICAgaXRlbSA9IGhlYXByZXBsYWNlKGFycmF5LCBpdGVtKVxuICAgICAqL1xuXG4gICAgaGVhcHJlcGxhY2UgPSBmdW5jdGlvbihhcnJheSwgaXRlbSwgY21wKSB7XG4gICAgICB2YXIgcmV0dXJuaXRlbTtcbiAgICAgIGlmIChjbXAgPT0gbnVsbCkge1xuICAgICAgICBjbXAgPSBkZWZhdWx0Q21wO1xuICAgICAgfVxuICAgICAgcmV0dXJuaXRlbSA9IGFycmF5WzBdO1xuICAgICAgYXJyYXlbMF0gPSBpdGVtO1xuICAgICAgX3NpZnR1cChhcnJheSwgMCwgY21wKTtcbiAgICAgIHJldHVybiByZXR1cm5pdGVtO1xuICAgIH07XG5cblxuICAgIC8qXG4gICAgRmFzdCB2ZXJzaW9uIG9mIGEgaGVhcHB1c2ggZm9sbG93ZWQgYnkgYSBoZWFwcG9wLlxuICAgICAqL1xuXG4gICAgaGVhcHB1c2hwb3AgPSBmdW5jdGlvbihhcnJheSwgaXRlbSwgY21wKSB7XG4gICAgICB2YXIgX3JlZjtcbiAgICAgIGlmIChjbXAgPT0gbnVsbCkge1xuICAgICAgICBjbXAgPSBkZWZhdWx0Q21wO1xuICAgICAgfVxuICAgICAgaWYgKGFycmF5Lmxlbmd0aCAmJiBjbXAoYXJyYXlbMF0sIGl0ZW0pIDwgMCkge1xuICAgICAgICBfcmVmID0gW2FycmF5WzBdLCBpdGVtXSwgaXRlbSA9IF9yZWZbMF0sIGFycmF5WzBdID0gX3JlZlsxXTtcbiAgICAgICAgX3NpZnR1cChhcnJheSwgMCwgY21wKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBpdGVtO1xuICAgIH07XG5cblxuICAgIC8qXG4gICAgVHJhbnNmb3JtIGxpc3QgaW50byBhIGhlYXAsIGluLXBsYWNlLCBpbiBPKGFycmF5Lmxlbmd0aCkgdGltZS5cbiAgICAgKi9cblxuICAgIGhlYXBpZnkgPSBmdW5jdGlvbihhcnJheSwgY21wKSB7XG4gICAgICB2YXIgaSwgX2ksIF9sZW4sIF9yZWYxLCBfcmVzdWx0cywgX3Jlc3VsdHMxO1xuICAgICAgaWYgKGNtcCA9PSBudWxsKSB7XG4gICAgICAgIGNtcCA9IGRlZmF1bHRDbXA7XG4gICAgICB9XG4gICAgICBfcmVmMSA9IChmdW5jdGlvbigpIHtcbiAgICAgICAgX3Jlc3VsdHMxID0gW107XG4gICAgICAgIGZvciAodmFyIF9qID0gMCwgX3JlZiA9IGZsb29yKGFycmF5Lmxlbmd0aCAvIDIpOyAwIDw9IF9yZWYgPyBfaiA8IF9yZWYgOiBfaiA+IF9yZWY7IDAgPD0gX3JlZiA/IF9qKysgOiBfai0tKXsgX3Jlc3VsdHMxLnB1c2goX2opOyB9XG4gICAgICAgIHJldHVybiBfcmVzdWx0czE7XG4gICAgICB9KS5hcHBseSh0aGlzKS5yZXZlcnNlKCk7XG4gICAgICBfcmVzdWx0cyA9IFtdO1xuICAgICAgZm9yIChfaSA9IDAsIF9sZW4gPSBfcmVmMS5sZW5ndGg7IF9pIDwgX2xlbjsgX2krKykge1xuICAgICAgICBpID0gX3JlZjFbX2ldO1xuICAgICAgICBfcmVzdWx0cy5wdXNoKF9zaWZ0dXAoYXJyYXksIGksIGNtcCkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIF9yZXN1bHRzO1xuICAgIH07XG5cblxuICAgIC8qXG4gICAgVXBkYXRlIHRoZSBwb3NpdGlvbiBvZiB0aGUgZ2l2ZW4gaXRlbSBpbiB0aGUgaGVhcC5cbiAgICBUaGlzIGZ1bmN0aW9uIHNob3VsZCBiZSBjYWxsZWQgZXZlcnkgdGltZSB0aGUgaXRlbSBpcyBiZWluZyBtb2RpZmllZC5cbiAgICAgKi9cblxuICAgIHVwZGF0ZUl0ZW0gPSBmdW5jdGlvbihhcnJheSwgaXRlbSwgY21wKSB7XG4gICAgICB2YXIgcG9zO1xuICAgICAgaWYgKGNtcCA9PSBudWxsKSB7XG4gICAgICAgIGNtcCA9IGRlZmF1bHRDbXA7XG4gICAgICB9XG4gICAgICBwb3MgPSBhcnJheS5pbmRleE9mKGl0ZW0pO1xuICAgICAgaWYgKHBvcyA9PT0gLTEpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgX3NpZnRkb3duKGFycmF5LCAwLCBwb3MsIGNtcCk7XG4gICAgICByZXR1cm4gX3NpZnR1cChhcnJheSwgcG9zLCBjbXApO1xuICAgIH07XG5cblxuICAgIC8qXG4gICAgRmluZCB0aGUgbiBsYXJnZXN0IGVsZW1lbnRzIGluIGEgZGF0YXNldC5cbiAgICAgKi9cblxuICAgIG5sYXJnZXN0ID0gZnVuY3Rpb24oYXJyYXksIG4sIGNtcCkge1xuICAgICAgdmFyIGVsZW0sIHJlc3VsdCwgX2ksIF9sZW4sIF9yZWY7XG4gICAgICBpZiAoY21wID09IG51bGwpIHtcbiAgICAgICAgY21wID0gZGVmYXVsdENtcDtcbiAgICAgIH1cbiAgICAgIHJlc3VsdCA9IGFycmF5LnNsaWNlKDAsIG4pO1xuICAgICAgaWYgKCFyZXN1bHQubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9XG4gICAgICBoZWFwaWZ5KHJlc3VsdCwgY21wKTtcbiAgICAgIF9yZWYgPSBhcnJheS5zbGljZShuKTtcbiAgICAgIGZvciAoX2kgPSAwLCBfbGVuID0gX3JlZi5sZW5ndGg7IF9pIDwgX2xlbjsgX2krKykge1xuICAgICAgICBlbGVtID0gX3JlZltfaV07XG4gICAgICAgIGhlYXBwdXNocG9wKHJlc3VsdCwgZWxlbSwgY21wKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQuc29ydChjbXApLnJldmVyc2UoKTtcbiAgICB9O1xuXG5cbiAgICAvKlxuICAgIEZpbmQgdGhlIG4gc21hbGxlc3QgZWxlbWVudHMgaW4gYSBkYXRhc2V0LlxuICAgICAqL1xuXG4gICAgbnNtYWxsZXN0ID0gZnVuY3Rpb24oYXJyYXksIG4sIGNtcCkge1xuICAgICAgdmFyIGVsZW0sIGxvcywgcmVzdWx0LCBfaSwgX2osIF9sZW4sIF9yZWYsIF9yZWYxLCBfcmVzdWx0cztcbiAgICAgIGlmIChjbXAgPT0gbnVsbCkge1xuICAgICAgICBjbXAgPSBkZWZhdWx0Q21wO1xuICAgICAgfVxuICAgICAgaWYgKG4gKiAxMCA8PSBhcnJheS5sZW5ndGgpIHtcbiAgICAgICAgcmVzdWx0ID0gYXJyYXkuc2xpY2UoMCwgbikuc29ydChjbXApO1xuICAgICAgICBpZiAoIXJlc3VsdC5sZW5ndGgpIHtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICAgIGxvcyA9IHJlc3VsdFtyZXN1bHQubGVuZ3RoIC0gMV07XG4gICAgICAgIF9yZWYgPSBhcnJheS5zbGljZShuKTtcbiAgICAgICAgZm9yIChfaSA9IDAsIF9sZW4gPSBfcmVmLmxlbmd0aDsgX2kgPCBfbGVuOyBfaSsrKSB7XG4gICAgICAgICAgZWxlbSA9IF9yZWZbX2ldO1xuICAgICAgICAgIGlmIChjbXAoZWxlbSwgbG9zKSA8IDApIHtcbiAgICAgICAgICAgIGluc29ydChyZXN1bHQsIGVsZW0sIDAsIG51bGwsIGNtcCk7XG4gICAgICAgICAgICByZXN1bHQucG9wKCk7XG4gICAgICAgICAgICBsb3MgPSByZXN1bHRbcmVzdWx0Lmxlbmd0aCAtIDFdO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfVxuICAgICAgaGVhcGlmeShhcnJheSwgY21wKTtcbiAgICAgIF9yZXN1bHRzID0gW107XG4gICAgICBmb3IgKF9qID0gMCwgX3JlZjEgPSBtaW4obiwgYXJyYXkubGVuZ3RoKTsgMCA8PSBfcmVmMSA/IF9qIDwgX3JlZjEgOiBfaiA+IF9yZWYxOyAwIDw9IF9yZWYxID8gKytfaiA6IC0tX2opIHtcbiAgICAgICAgX3Jlc3VsdHMucHVzaChoZWFwcG9wKGFycmF5LCBjbXApKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBfcmVzdWx0cztcbiAgICB9O1xuXG4gICAgX3NpZnRkb3duID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0cG9zLCBwb3MsIGNtcCkge1xuICAgICAgdmFyIG5ld2l0ZW0sIHBhcmVudCwgcGFyZW50cG9zO1xuICAgICAgaWYgKGNtcCA9PSBudWxsKSB7XG4gICAgICAgIGNtcCA9IGRlZmF1bHRDbXA7XG4gICAgICB9XG4gICAgICBuZXdpdGVtID0gYXJyYXlbcG9zXTtcbiAgICAgIHdoaWxlIChwb3MgPiBzdGFydHBvcykge1xuICAgICAgICBwYXJlbnRwb3MgPSAocG9zIC0gMSkgPj4gMTtcbiAgICAgICAgcGFyZW50ID0gYXJyYXlbcGFyZW50cG9zXTtcbiAgICAgICAgaWYgKGNtcChuZXdpdGVtLCBwYXJlbnQpIDwgMCkge1xuICAgICAgICAgIGFycmF5W3Bvc10gPSBwYXJlbnQ7XG4gICAgICAgICAgcG9zID0gcGFyZW50cG9zO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGFycmF5W3Bvc10gPSBuZXdpdGVtO1xuICAgIH07XG5cbiAgICBfc2lmdHVwID0gZnVuY3Rpb24oYXJyYXksIHBvcywgY21wKSB7XG4gICAgICB2YXIgY2hpbGRwb3MsIGVuZHBvcywgbmV3aXRlbSwgcmlnaHRwb3MsIHN0YXJ0cG9zO1xuICAgICAgaWYgKGNtcCA9PSBudWxsKSB7XG4gICAgICAgIGNtcCA9IGRlZmF1bHRDbXA7XG4gICAgICB9XG4gICAgICBlbmRwb3MgPSBhcnJheS5sZW5ndGg7XG4gICAgICBzdGFydHBvcyA9IHBvcztcbiAgICAgIG5ld2l0ZW0gPSBhcnJheVtwb3NdO1xuICAgICAgY2hpbGRwb3MgPSAyICogcG9zICsgMTtcbiAgICAgIHdoaWxlIChjaGlsZHBvcyA8IGVuZHBvcykge1xuICAgICAgICByaWdodHBvcyA9IGNoaWxkcG9zICsgMTtcbiAgICAgICAgaWYgKHJpZ2h0cG9zIDwgZW5kcG9zICYmICEoY21wKGFycmF5W2NoaWxkcG9zXSwgYXJyYXlbcmlnaHRwb3NdKSA8IDApKSB7XG4gICAgICAgICAgY2hpbGRwb3MgPSByaWdodHBvcztcbiAgICAgICAgfVxuICAgICAgICBhcnJheVtwb3NdID0gYXJyYXlbY2hpbGRwb3NdO1xuICAgICAgICBwb3MgPSBjaGlsZHBvcztcbiAgICAgICAgY2hpbGRwb3MgPSAyICogcG9zICsgMTtcbiAgICAgIH1cbiAgICAgIGFycmF5W3Bvc10gPSBuZXdpdGVtO1xuICAgICAgcmV0dXJuIF9zaWZ0ZG93bihhcnJheSwgc3RhcnRwb3MsIHBvcywgY21wKTtcbiAgICB9O1xuXG4gICAgSGVhcCA9IChmdW5jdGlvbigpIHtcbiAgICAgIEhlYXAucHVzaCA9IGhlYXBwdXNoO1xuXG4gICAgICBIZWFwLnBvcCA9IGhlYXBwb3A7XG5cbiAgICAgIEhlYXAucmVwbGFjZSA9IGhlYXByZXBsYWNlO1xuXG4gICAgICBIZWFwLnB1c2hwb3AgPSBoZWFwcHVzaHBvcDtcblxuICAgICAgSGVhcC5oZWFwaWZ5ID0gaGVhcGlmeTtcblxuICAgICAgSGVhcC51cGRhdGVJdGVtID0gdXBkYXRlSXRlbTtcblxuICAgICAgSGVhcC5ubGFyZ2VzdCA9IG5sYXJnZXN0O1xuXG4gICAgICBIZWFwLm5zbWFsbGVzdCA9IG5zbWFsbGVzdDtcblxuICAgICAgZnVuY3Rpb24gSGVhcChjbXApIHtcbiAgICAgICAgdGhpcy5jbXAgPSBjbXAgIT0gbnVsbCA/IGNtcCA6IGRlZmF1bHRDbXA7XG4gICAgICAgIHRoaXMubm9kZXMgPSBbXTtcbiAgICAgIH1cblxuICAgICAgSGVhcC5wcm90b3R5cGUucHVzaCA9IGZ1bmN0aW9uKHgpIHtcbiAgICAgICAgcmV0dXJuIGhlYXBwdXNoKHRoaXMubm9kZXMsIHgsIHRoaXMuY21wKTtcbiAgICAgIH07XG5cbiAgICAgIEhlYXAucHJvdG90eXBlLnBvcCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gaGVhcHBvcCh0aGlzLm5vZGVzLCB0aGlzLmNtcCk7XG4gICAgICB9O1xuXG4gICAgICBIZWFwLnByb3RvdHlwZS5wZWVrID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm5vZGVzWzBdO1xuICAgICAgfTtcblxuICAgICAgSGVhcC5wcm90b3R5cGUuY29udGFpbnMgPSBmdW5jdGlvbih4KSB7XG4gICAgICAgIHJldHVybiB0aGlzLm5vZGVzLmluZGV4T2YoeCkgIT09IC0xO1xuICAgICAgfTtcblxuICAgICAgSGVhcC5wcm90b3R5cGUucmVwbGFjZSA9IGZ1bmN0aW9uKHgpIHtcbiAgICAgICAgcmV0dXJuIGhlYXByZXBsYWNlKHRoaXMubm9kZXMsIHgsIHRoaXMuY21wKTtcbiAgICAgIH07XG5cbiAgICAgIEhlYXAucHJvdG90eXBlLnB1c2hwb3AgPSBmdW5jdGlvbih4KSB7XG4gICAgICAgIHJldHVybiBoZWFwcHVzaHBvcCh0aGlzLm5vZGVzLCB4LCB0aGlzLmNtcCk7XG4gICAgICB9O1xuXG4gICAgICBIZWFwLnByb3RvdHlwZS5oZWFwaWZ5ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBoZWFwaWZ5KHRoaXMubm9kZXMsIHRoaXMuY21wKTtcbiAgICAgIH07XG5cbiAgICAgIEhlYXAucHJvdG90eXBlLnVwZGF0ZUl0ZW0gPSBmdW5jdGlvbih4KSB7XG4gICAgICAgIHJldHVybiB1cGRhdGVJdGVtKHRoaXMubm9kZXMsIHgsIHRoaXMuY21wKTtcbiAgICAgIH07XG5cbiAgICAgIEhlYXAucHJvdG90eXBlLmNsZWFyID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm5vZGVzID0gW107XG4gICAgICB9O1xuXG4gICAgICBIZWFwLnByb3RvdHlwZS5lbXB0eSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5ub2Rlcy5sZW5ndGggPT09IDA7XG4gICAgICB9O1xuXG4gICAgICBIZWFwLnByb3RvdHlwZS5zaXplID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm5vZGVzLmxlbmd0aDtcbiAgICAgIH07XG5cbiAgICAgIEhlYXAucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBoZWFwO1xuICAgICAgICBoZWFwID0gbmV3IEhlYXAoKTtcbiAgICAgICAgaGVhcC5ub2RlcyA9IHRoaXMubm9kZXMuc2xpY2UoMCk7XG4gICAgICAgIHJldHVybiBoZWFwO1xuICAgICAgfTtcblxuICAgICAgSGVhcC5wcm90b3R5cGUudG9BcnJheSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5ub2Rlcy5zbGljZSgwKTtcbiAgICAgIH07XG5cbiAgICAgIEhlYXAucHJvdG90eXBlLmluc2VydCA9IEhlYXAucHJvdG90eXBlLnB1c2g7XG5cbiAgICAgIEhlYXAucHJvdG90eXBlLnRvcCA9IEhlYXAucHJvdG90eXBlLnBlZWs7XG5cbiAgICAgIEhlYXAucHJvdG90eXBlLmZyb250ID0gSGVhcC5wcm90b3R5cGUucGVlaztcblxuICAgICAgSGVhcC5wcm90b3R5cGUuaGFzID0gSGVhcC5wcm90b3R5cGUuY29udGFpbnM7XG5cbiAgICAgIEhlYXAucHJvdG90eXBlLmNvcHkgPSBIZWFwLnByb3RvdHlwZS5jbG9uZTtcblxuICAgICAgcmV0dXJuIEhlYXA7XG5cbiAgICB9KSgpO1xuXG4gICAgKGZ1bmN0aW9uKHJvb3QsIGZhY3RvcnkpIHtcbiAgICAgIHtcbiAgICAgICAgcmV0dXJuIG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeSgpO1xuICAgICAgfVxuICAgIH0pKHRoaXMsIGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIEhlYXA7XG4gICAgfSk7XG5cbiAgfSkuY2FsbChjb21tb25qc0dsb2JhbCk7XG4gIH0pO1xuXG4gIHZhciBoZWFwID0gaGVhcCQxO1xuXG4gIHZhciBkaWprc3RyYURlZmF1bHRzID0gZGVmYXVsdHMkZyh7XG4gICAgcm9vdDogbnVsbCxcbiAgICB3ZWlnaHQ6IGZ1bmN0aW9uIHdlaWdodChlZGdlKSB7XG4gICAgICByZXR1cm4gMTtcbiAgICB9LFxuICAgIGRpcmVjdGVkOiBmYWxzZVxuICB9KTtcbiAgdmFyIGVsZXNmbiR1ID0ge1xuICAgIGRpamtzdHJhOiBmdW5jdGlvbiBkaWprc3RyYShvcHRpb25zKSB7XG4gICAgICBpZiAoIXBsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzO1xuICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgIHJvb3Q6IGFyZ3NbMF0sXG4gICAgICAgICAgd2VpZ2h0OiBhcmdzWzFdLFxuICAgICAgICAgIGRpcmVjdGVkOiBhcmdzWzJdXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIHZhciBfZGlqa3N0cmFEZWZhdWx0cyA9IGRpamtzdHJhRGVmYXVsdHMob3B0aW9ucyksXG4gICAgICAgICAgcm9vdCA9IF9kaWprc3RyYURlZmF1bHRzLnJvb3QsXG4gICAgICAgICAgd2VpZ2h0ID0gX2RpamtzdHJhRGVmYXVsdHMud2VpZ2h0LFxuICAgICAgICAgIGRpcmVjdGVkID0gX2RpamtzdHJhRGVmYXVsdHMuZGlyZWN0ZWQ7XG5cbiAgICAgIHZhciBlbGVzID0gdGhpcztcbiAgICAgIHZhciB3ZWlnaHRGbiA9IHdlaWdodDtcbiAgICAgIHZhciBzb3VyY2UgPSBzdHJpbmcocm9vdCkgPyB0aGlzLmZpbHRlcihyb290KVswXSA6IHJvb3RbMF07XG4gICAgICB2YXIgZGlzdCA9IHt9O1xuICAgICAgdmFyIHByZXYgPSB7fTtcbiAgICAgIHZhciBrbm93bkRpc3QgPSB7fTtcblxuICAgICAgdmFyIF90aGlzJGJ5R3JvdXAgPSB0aGlzLmJ5R3JvdXAoKSxcbiAgICAgICAgICBub2RlcyA9IF90aGlzJGJ5R3JvdXAubm9kZXMsXG4gICAgICAgICAgZWRnZXMgPSBfdGhpcyRieUdyb3VwLmVkZ2VzO1xuXG4gICAgICBlZGdlcy51bm1lcmdlQnkoZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICByZXR1cm4gZWxlLmlzTG9vcCgpO1xuICAgICAgfSk7XG5cbiAgICAgIHZhciBnZXREaXN0ID0gZnVuY3Rpb24gZ2V0RGlzdChub2RlKSB7XG4gICAgICAgIHJldHVybiBkaXN0W25vZGUuaWQoKV07XG4gICAgICB9O1xuXG4gICAgICB2YXIgc2V0RGlzdCA9IGZ1bmN0aW9uIHNldERpc3Qobm9kZSwgZCkge1xuICAgICAgICBkaXN0W25vZGUuaWQoKV0gPSBkO1xuICAgICAgICBRLnVwZGF0ZUl0ZW0obm9kZSk7XG4gICAgICB9O1xuXG4gICAgICB2YXIgUSA9IG5ldyBoZWFwKGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBnZXREaXN0KGEpIC0gZ2V0RGlzdChiKTtcbiAgICAgIH0pO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBub2RlID0gbm9kZXNbaV07XG4gICAgICAgIGRpc3Rbbm9kZS5pZCgpXSA9IG5vZGUuc2FtZShzb3VyY2UpID8gMCA6IEluZmluaXR5O1xuICAgICAgICBRLnB1c2gobm9kZSk7XG4gICAgICB9XG5cbiAgICAgIHZhciBkaXN0QmV0d2VlbiA9IGZ1bmN0aW9uIGRpc3RCZXR3ZWVuKHUsIHYpIHtcbiAgICAgICAgdmFyIHV2cyA9IChkaXJlY3RlZCA/IHUuZWRnZXNUbyh2KSA6IHUuZWRnZXNXaXRoKHYpKS5pbnRlcnNlY3QoZWRnZXMpO1xuICAgICAgICB2YXIgc21hbGxlc3REaXN0YW5jZSA9IEluZmluaXR5O1xuICAgICAgICB2YXIgc21hbGxlc3RFZGdlO1xuXG4gICAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCB1dnMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgdmFyIGVkZ2UgPSB1dnNbX2ldO1xuXG4gICAgICAgICAgdmFyIF93ZWlnaHQgPSB3ZWlnaHRGbihlZGdlKTtcblxuICAgICAgICAgIGlmIChfd2VpZ2h0IDwgc21hbGxlc3REaXN0YW5jZSB8fCAhc21hbGxlc3RFZGdlKSB7XG4gICAgICAgICAgICBzbWFsbGVzdERpc3RhbmNlID0gX3dlaWdodDtcbiAgICAgICAgICAgIHNtYWxsZXN0RWRnZSA9IGVkZ2U7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBlZGdlOiBzbWFsbGVzdEVkZ2UsXG4gICAgICAgICAgZGlzdDogc21hbGxlc3REaXN0YW5jZVxuICAgICAgICB9O1xuICAgICAgfTtcblxuICAgICAgd2hpbGUgKFEuc2l6ZSgpID4gMCkge1xuICAgICAgICB2YXIgdSA9IFEucG9wKCk7XG4gICAgICAgIHZhciBzbWFsbGV0c0Rpc3QgPSBnZXREaXN0KHUpO1xuICAgICAgICB2YXIgdWlkID0gdS5pZCgpO1xuICAgICAgICBrbm93bkRpc3RbdWlkXSA9IHNtYWxsZXRzRGlzdDtcblxuICAgICAgICBpZiAoc21hbGxldHNEaXN0ID09PSBJbmZpbml0eSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIG5laWdoYm9ycyA9IHUubmVpZ2hib3Job29kKCkuaW50ZXJzZWN0KG5vZGVzKTtcblxuICAgICAgICBmb3IgKHZhciBfaTIgPSAwOyBfaTIgPCBuZWlnaGJvcnMubGVuZ3RoOyBfaTIrKykge1xuICAgICAgICAgIHZhciB2ID0gbmVpZ2hib3JzW19pMl07XG4gICAgICAgICAgdmFyIHZpZCA9IHYuaWQoKTtcbiAgICAgICAgICB2YXIgdkRpc3QgPSBkaXN0QmV0d2Vlbih1LCB2KTtcbiAgICAgICAgICB2YXIgYWx0ID0gc21hbGxldHNEaXN0ICsgdkRpc3QuZGlzdDtcblxuICAgICAgICAgIGlmIChhbHQgPCBnZXREaXN0KHYpKSB7XG4gICAgICAgICAgICBzZXREaXN0KHYsIGFsdCk7XG4gICAgICAgICAgICBwcmV2W3ZpZF0gPSB7XG4gICAgICAgICAgICAgIG5vZGU6IHUsXG4gICAgICAgICAgICAgIGVkZ2U6IHZEaXN0LmVkZ2VcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuICAgICAgICB9IC8vIGZvclxuXG4gICAgICB9IC8vIHdoaWxlXG5cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZGlzdGFuY2VUbzogZnVuY3Rpb24gZGlzdGFuY2VUbyhub2RlKSB7XG4gICAgICAgICAgdmFyIHRhcmdldCA9IHN0cmluZyhub2RlKSA/IG5vZGVzLmZpbHRlcihub2RlKVswXSA6IG5vZGVbMF07XG4gICAgICAgICAgcmV0dXJuIGtub3duRGlzdFt0YXJnZXQuaWQoKV07XG4gICAgICAgIH0sXG4gICAgICAgIHBhdGhUbzogZnVuY3Rpb24gcGF0aFRvKG5vZGUpIHtcbiAgICAgICAgICB2YXIgdGFyZ2V0ID0gc3RyaW5nKG5vZGUpID8gbm9kZXMuZmlsdGVyKG5vZGUpWzBdIDogbm9kZVswXTtcbiAgICAgICAgICB2YXIgUyA9IFtdO1xuICAgICAgICAgIHZhciB1ID0gdGFyZ2V0O1xuICAgICAgICAgIHZhciB1aWQgPSB1LmlkKCk7XG5cbiAgICAgICAgICBpZiAodGFyZ2V0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIFMudW5zaGlmdCh0YXJnZXQpO1xuXG4gICAgICAgICAgICB3aGlsZSAocHJldlt1aWRdKSB7XG4gICAgICAgICAgICAgIHZhciBwID0gcHJldlt1aWRdO1xuICAgICAgICAgICAgICBTLnVuc2hpZnQocC5lZGdlKTtcbiAgICAgICAgICAgICAgUy51bnNoaWZ0KHAubm9kZSk7XG4gICAgICAgICAgICAgIHUgPSBwLm5vZGU7XG4gICAgICAgICAgICAgIHVpZCA9IHUuaWQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gZWxlcy5zcGF3bihTKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9XG4gIH07XG5cbiAgdmFyIGVsZXNmbiR0ID0ge1xuICAgIC8vIGtydXNrYWwncyBhbGdvcml0aG0gKGZpbmRzIG1pbiBzcGFubmluZyB0cmVlLCBhc3N1bWluZyB1bmRpcmVjdGVkIGdyYXBoKVxuICAgIC8vIGltcGxlbWVudGVkIGZyb20gcHNldWRvY29kZSBmcm9tIHdpa2lwZWRpYVxuICAgIGtydXNrYWw6IGZ1bmN0aW9uIGtydXNrYWwod2VpZ2h0Rm4pIHtcbiAgICAgIHdlaWdodEZuID0gd2VpZ2h0Rm4gfHwgZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICB9O1xuXG4gICAgICB2YXIgX3RoaXMkYnlHcm91cCA9IHRoaXMuYnlHcm91cCgpLFxuICAgICAgICAgIG5vZGVzID0gX3RoaXMkYnlHcm91cC5ub2RlcyxcbiAgICAgICAgICBlZGdlcyA9IF90aGlzJGJ5R3JvdXAuZWRnZXM7XG5cbiAgICAgIHZhciBudW1Ob2RlcyA9IG5vZGVzLmxlbmd0aDtcbiAgICAgIHZhciBmb3Jlc3QgPSBuZXcgQXJyYXkobnVtTm9kZXMpO1xuICAgICAgdmFyIEEgPSBub2RlczsgLy8gYXNzdW1lcyBieUdyb3VwKCkgY3JlYXRlcyBuZXcgY29sbGVjdGlvbnMgdGhhdCBjYW4gYmUgc2FmZWx5IG11dGF0ZWRcblxuICAgICAgdmFyIGZpbmRTZXRJbmRleCA9IGZ1bmN0aW9uIGZpbmRTZXRJbmRleChlbGUpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBmb3Jlc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWxlcyA9IGZvcmVzdFtpXTtcblxuICAgICAgICAgIGlmIChlbGVzLmhhcyhlbGUpKSB7XG4gICAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07IC8vIHN0YXJ0IHdpdGggb25lIGZvcmVzdCBwZXIgbm9kZVxuXG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbnVtTm9kZXM7IGkrKykge1xuICAgICAgICBmb3Jlc3RbaV0gPSB0aGlzLnNwYXduKG5vZGVzW2ldKTtcbiAgICAgIH1cblxuICAgICAgdmFyIFMgPSBlZGdlcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiB3ZWlnaHRGbihhKSAtIHdlaWdodEZuKGIpO1xuICAgICAgfSk7XG5cbiAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBTLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgZWRnZSA9IFNbX2ldO1xuICAgICAgICB2YXIgdSA9IGVkZ2Uuc291cmNlKClbMF07XG4gICAgICAgIHZhciB2ID0gZWRnZS50YXJnZXQoKVswXTtcbiAgICAgICAgdmFyIHNldFVJbmRleCA9IGZpbmRTZXRJbmRleCh1KTtcbiAgICAgICAgdmFyIHNldFZJbmRleCA9IGZpbmRTZXRJbmRleCh2KTtcbiAgICAgICAgdmFyIHNldFUgPSBmb3Jlc3Rbc2V0VUluZGV4XTtcbiAgICAgICAgdmFyIHNldFYgPSBmb3Jlc3Rbc2V0VkluZGV4XTtcblxuICAgICAgICBpZiAoc2V0VUluZGV4ICE9PSBzZXRWSW5kZXgpIHtcbiAgICAgICAgICBBLm1lcmdlKGVkZ2UpOyAvLyBjb21iaW5lIGZvcmVzdHMgZm9yIHUgYW5kIHZcblxuICAgICAgICAgIHNldFUubWVyZ2Uoc2V0Vik7XG4gICAgICAgICAgZm9yZXN0LnNwbGljZShzZXRWSW5kZXgsIDEpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBBO1xuICAgIH1cbiAgfTtcblxuICB2YXIgYVN0YXJEZWZhdWx0cyA9IGRlZmF1bHRzJGcoe1xuICAgIHJvb3Q6IG51bGwsXG4gICAgZ29hbDogbnVsbCxcbiAgICB3ZWlnaHQ6IGZ1bmN0aW9uIHdlaWdodChlZGdlKSB7XG4gICAgICByZXR1cm4gMTtcbiAgICB9LFxuICAgIGhldXJpc3RpYzogZnVuY3Rpb24gaGV1cmlzdGljKGVkZ2UpIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH0sXG4gICAgZGlyZWN0ZWQ6IGZhbHNlXG4gIH0pO1xuICB2YXIgZWxlc2ZuJHMgPSB7XG4gICAgLy8gSW1wbGVtZW50ZWQgZnJvbSBwc2V1ZG9jb2RlIGZyb20gd2lraXBlZGlhXG4gICAgYVN0YXI6IGZ1bmN0aW9uIGFTdGFyKG9wdGlvbnMpIHtcbiAgICAgIHZhciBjeSA9IHRoaXMuY3koKTtcblxuICAgICAgdmFyIF9hU3RhckRlZmF1bHRzID0gYVN0YXJEZWZhdWx0cyhvcHRpb25zKSxcbiAgICAgICAgICByb290ID0gX2FTdGFyRGVmYXVsdHMucm9vdCxcbiAgICAgICAgICBnb2FsID0gX2FTdGFyRGVmYXVsdHMuZ29hbCxcbiAgICAgICAgICBoZXVyaXN0aWMgPSBfYVN0YXJEZWZhdWx0cy5oZXVyaXN0aWMsXG4gICAgICAgICAgZGlyZWN0ZWQgPSBfYVN0YXJEZWZhdWx0cy5kaXJlY3RlZCxcbiAgICAgICAgICB3ZWlnaHQgPSBfYVN0YXJEZWZhdWx0cy53ZWlnaHQ7XG5cbiAgICAgIHJvb3QgPSBjeS5jb2xsZWN0aW9uKHJvb3QpWzBdO1xuICAgICAgZ29hbCA9IGN5LmNvbGxlY3Rpb24oZ29hbClbMF07XG4gICAgICB2YXIgc2lkID0gcm9vdC5pZCgpO1xuICAgICAgdmFyIHRpZCA9IGdvYWwuaWQoKTtcbiAgICAgIHZhciBnU2NvcmUgPSB7fTtcbiAgICAgIHZhciBmU2NvcmUgPSB7fTtcbiAgICAgIHZhciBjbG9zZWRTZXRJZHMgPSB7fTtcbiAgICAgIHZhciBvcGVuU2V0ID0gbmV3IGhlYXAoZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgICAgcmV0dXJuIGZTY29yZVthLmlkKCldIC0gZlNjb3JlW2IuaWQoKV07XG4gICAgICB9KTtcbiAgICAgIHZhciBvcGVuU2V0SWRzID0gbmV3IFNldCQxKCk7XG4gICAgICB2YXIgY2FtZUZyb20gPSB7fTtcbiAgICAgIHZhciBjYW1lRnJvbUVkZ2UgPSB7fTtcblxuICAgICAgdmFyIGFkZFRvT3BlblNldCA9IGZ1bmN0aW9uIGFkZFRvT3BlblNldChlbGUsIGlkKSB7XG4gICAgICAgIG9wZW5TZXQucHVzaChlbGUpO1xuICAgICAgICBvcGVuU2V0SWRzLmFkZChpZCk7XG4gICAgICB9O1xuXG4gICAgICB2YXIgY01pbiwgY01pbklkO1xuXG4gICAgICB2YXIgcG9wRnJvbU9wZW5TZXQgPSBmdW5jdGlvbiBwb3BGcm9tT3BlblNldCgpIHtcbiAgICAgICAgY01pbiA9IG9wZW5TZXQucG9wKCk7XG4gICAgICAgIGNNaW5JZCA9IGNNaW4uaWQoKTtcbiAgICAgICAgb3BlblNldElkc1tcImRlbGV0ZVwiXShjTWluSWQpO1xuICAgICAgfTtcblxuICAgICAgdmFyIGlzSW5PcGVuU2V0ID0gZnVuY3Rpb24gaXNJbk9wZW5TZXQoaWQpIHtcbiAgICAgICAgcmV0dXJuIG9wZW5TZXRJZHMuaGFzKGlkKTtcbiAgICAgIH07XG5cbiAgICAgIGFkZFRvT3BlblNldChyb290LCBzaWQpO1xuICAgICAgZ1Njb3JlW3NpZF0gPSAwO1xuICAgICAgZlNjb3JlW3NpZF0gPSBoZXVyaXN0aWMocm9vdCk7IC8vIENvdW50ZXJcblxuICAgICAgdmFyIHN0ZXBzID0gMDsgLy8gTWFpbiBsb29wXG5cbiAgICAgIHdoaWxlIChvcGVuU2V0LnNpemUoKSA+IDApIHtcbiAgICAgICAgcG9wRnJvbU9wZW5TZXQoKTtcbiAgICAgICAgc3RlcHMrKzsgLy8gSWYgd2UndmUgZm91bmQgb3VyIGdvYWwsIHRoZW4gd2UgYXJlIGRvbmVcblxuICAgICAgICBpZiAoY01pbklkID09PSB0aWQpIHtcbiAgICAgICAgICB2YXIgcGF0aCA9IFtdO1xuICAgICAgICAgIHZhciBwYXRoTm9kZSA9IGdvYWw7XG4gICAgICAgICAgdmFyIHBhdGhOb2RlSWQgPSB0aWQ7XG4gICAgICAgICAgdmFyIHBhdGhFZGdlID0gY2FtZUZyb21FZGdlW3BhdGhOb2RlSWRdO1xuXG4gICAgICAgICAgZm9yICg7Oykge1xuICAgICAgICAgICAgcGF0aC51bnNoaWZ0KHBhdGhOb2RlKTtcblxuICAgICAgICAgICAgaWYgKHBhdGhFZGdlICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgcGF0aC51bnNoaWZ0KHBhdGhFZGdlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcGF0aE5vZGUgPSBjYW1lRnJvbVtwYXRoTm9kZUlkXTtcblxuICAgICAgICAgICAgaWYgKHBhdGhOb2RlID09IG51bGwpIHtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHBhdGhOb2RlSWQgPSBwYXRoTm9kZS5pZCgpO1xuICAgICAgICAgICAgcGF0aEVkZ2UgPSBjYW1lRnJvbUVkZ2VbcGF0aE5vZGVJZF07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGZvdW5kOiB0cnVlLFxuICAgICAgICAgICAgZGlzdGFuY2U6IGdTY29yZVtjTWluSWRdLFxuICAgICAgICAgICAgcGF0aDogdGhpcy5zcGF3bihwYXRoKSxcbiAgICAgICAgICAgIHN0ZXBzOiBzdGVwc1xuICAgICAgICAgIH07XG4gICAgICAgIH0gLy8gQWRkIGNNaW4gdG8gcHJvY2Vzc2VkIG5vZGVzXG5cblxuICAgICAgICBjbG9zZWRTZXRJZHNbY01pbklkXSA9IHRydWU7IC8vIFVwZGF0ZSBzY29yZXMgZm9yIG5laWdoYm9ycyBvZiBjTWluXG4gICAgICAgIC8vIFRha2UgaW50byBhY2NvdW50IGlmIGdyYXBoIGlzIGRpcmVjdGVkIG9yIG5vdFxuXG4gICAgICAgIHZhciB2d0VkZ2VzID0gY01pbi5fcHJpdmF0ZS5lZGdlcztcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZ3RWRnZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZSA9IHZ3RWRnZXNbaV07IC8vIGVkZ2UgbXVzdCBiZSBpbiBzZXQgb2YgY2FsbGluZyBlbGVzXG5cbiAgICAgICAgICBpZiAoIXRoaXMuaGFzRWxlbWVudFdpdGhJZChlLmlkKCkpKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9IC8vIGNNaW4gbXVzdCBiZSB0aGUgc291cmNlIG9mIGVkZ2UgaWYgZGlyZWN0ZWRcblxuXG4gICAgICAgICAgaWYgKGRpcmVjdGVkICYmIGUuZGF0YSgnc291cmNlJykgIT09IGNNaW5JZCkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdmFyIHdTcmMgPSBlLnNvdXJjZSgpO1xuICAgICAgICAgIHZhciB3VGd0ID0gZS50YXJnZXQoKTtcbiAgICAgICAgICB2YXIgdyA9IHdTcmMuaWQoKSAhPT0gY01pbklkID8gd1NyYyA6IHdUZ3Q7XG4gICAgICAgICAgdmFyIHdpZCA9IHcuaWQoKTsgLy8gbm9kZSBtdXN0IGJlIGluIHNldCBvZiBjYWxsaW5nIGVsZXNcblxuICAgICAgICAgIGlmICghdGhpcy5oYXNFbGVtZW50V2l0aElkKHdpZCkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH0gLy8gaWYgbm9kZSBpcyBpbiBjbG9zZWRTZXQsIGlnbm9yZSBpdFxuXG5cbiAgICAgICAgICBpZiAoY2xvc2VkU2V0SWRzW3dpZF0pIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH0gLy8gTmV3IHRlbnRhdGl2ZSBzY29yZSBmb3Igbm9kZSB3XG5cblxuICAgICAgICAgIHZhciB0ZW1wU2NvcmUgPSBnU2NvcmVbY01pbklkXSArIHdlaWdodChlKTsgLy8gVXBkYXRlIGdTY29yZSBmb3Igbm9kZSB3IGlmOlxuICAgICAgICAgIC8vICAgdyBub3QgcHJlc2VudCBpbiBvcGVuU2V0XG4gICAgICAgICAgLy8gT1JcbiAgICAgICAgICAvLyAgIHRlbnRhdGl2ZSBnU2NvcmUgaXMgbGVzcyB0aGFuIHByZXZpb3VzIHZhbHVlXG4gICAgICAgICAgLy8gdyBub3QgaW4gb3BlblNldFxuXG4gICAgICAgICAgaWYgKCFpc0luT3BlblNldCh3aWQpKSB7XG4gICAgICAgICAgICBnU2NvcmVbd2lkXSA9IHRlbXBTY29yZTtcbiAgICAgICAgICAgIGZTY29yZVt3aWRdID0gdGVtcFNjb3JlICsgaGV1cmlzdGljKHcpO1xuICAgICAgICAgICAgYWRkVG9PcGVuU2V0KHcsIHdpZCk7XG4gICAgICAgICAgICBjYW1lRnJvbVt3aWRdID0gY01pbjtcbiAgICAgICAgICAgIGNhbWVGcm9tRWRnZVt3aWRdID0gZTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH0gLy8gdyBhbHJlYWR5IGluIG9wZW5TZXQsIGJ1dCB3aXRoIGdyZWF0ZXIgZ1Njb3JlXG5cblxuICAgICAgICAgIGlmICh0ZW1wU2NvcmUgPCBnU2NvcmVbd2lkXSkge1xuICAgICAgICAgICAgZ1Njb3JlW3dpZF0gPSB0ZW1wU2NvcmU7XG4gICAgICAgICAgICBmU2NvcmVbd2lkXSA9IHRlbXBTY29yZSArIGhldXJpc3RpYyh3KTtcbiAgICAgICAgICAgIGNhbWVGcm9tW3dpZF0gPSBjTWluO1xuICAgICAgICAgICAgY2FtZUZyb21FZGdlW3dpZF0gPSBlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSAvLyBFbmQgb2YgbmVpZ2hib3JzIHVwZGF0ZVxuXG4gICAgICB9IC8vIEVuZCBvZiBtYWluIGxvb3BcbiAgICAgIC8vIElmIHdlJ3ZlIHJlYWNoZWQgaGVyZSwgdGhlbiB3ZSd2ZSBub3QgcmVhY2hlZCBvdXIgZ29hbFxuXG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGZvdW5kOiBmYWxzZSxcbiAgICAgICAgZGlzdGFuY2U6IHVuZGVmaW5lZCxcbiAgICAgICAgcGF0aDogdW5kZWZpbmVkLFxuICAgICAgICBzdGVwczogc3RlcHNcbiAgICAgIH07XG4gICAgfVxuICB9OyAvLyBlbGVzZm5cblxuICB2YXIgZmxveWRXYXJzaGFsbERlZmF1bHRzID0gZGVmYXVsdHMkZyh7XG4gICAgd2VpZ2h0OiBmdW5jdGlvbiB3ZWlnaHQoZWRnZSkge1xuICAgICAgcmV0dXJuIDE7XG4gICAgfSxcbiAgICBkaXJlY3RlZDogZmFsc2VcbiAgfSk7XG4gIHZhciBlbGVzZm4kciA9IHtcbiAgICAvLyBJbXBsZW1lbnRlZCBmcm9tIHBzZXVkb2NvZGUgZnJvbSB3aWtpcGVkaWFcbiAgICBmbG95ZFdhcnNoYWxsOiBmdW5jdGlvbiBmbG95ZFdhcnNoYWxsKG9wdGlvbnMpIHtcbiAgICAgIHZhciBjeSA9IHRoaXMuY3koKTtcblxuICAgICAgdmFyIF9mbG95ZFdhcnNoYWxsRGVmYXVsdCA9IGZsb3lkV2Fyc2hhbGxEZWZhdWx0cyhvcHRpb25zKSxcbiAgICAgICAgICB3ZWlnaHQgPSBfZmxveWRXYXJzaGFsbERlZmF1bHQud2VpZ2h0LFxuICAgICAgICAgIGRpcmVjdGVkID0gX2Zsb3lkV2Fyc2hhbGxEZWZhdWx0LmRpcmVjdGVkO1xuXG4gICAgICB2YXIgd2VpZ2h0Rm4gPSB3ZWlnaHQ7XG5cbiAgICAgIHZhciBfdGhpcyRieUdyb3VwID0gdGhpcy5ieUdyb3VwKCksXG4gICAgICAgICAgbm9kZXMgPSBfdGhpcyRieUdyb3VwLm5vZGVzLFxuICAgICAgICAgIGVkZ2VzID0gX3RoaXMkYnlHcm91cC5lZGdlcztcblxuICAgICAgdmFyIE4gPSBub2Rlcy5sZW5ndGg7XG4gICAgICB2YXIgTnNxID0gTiAqIE47XG5cbiAgICAgIHZhciBpbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZihub2RlKSB7XG4gICAgICAgIHJldHVybiBub2Rlcy5pbmRleE9mKG5vZGUpO1xuICAgICAgfTtcblxuICAgICAgdmFyIGF0SW5kZXggPSBmdW5jdGlvbiBhdEluZGV4KGkpIHtcbiAgICAgICAgcmV0dXJuIG5vZGVzW2ldO1xuICAgICAgfTsgLy8gSW5pdGlhbGl6ZSBkaXN0YW5jZSBtYXRyaXhcblxuXG4gICAgICB2YXIgZGlzdCA9IG5ldyBBcnJheShOc3EpO1xuXG4gICAgICBmb3IgKHZhciBuID0gMDsgbiA8IE5zcTsgbisrKSB7XG4gICAgICAgIHZhciBqID0gbiAlIE47XG4gICAgICAgIHZhciBpID0gKG4gLSBqKSAvIE47XG5cbiAgICAgICAgaWYgKGkgPT09IGopIHtcbiAgICAgICAgICBkaXN0W25dID0gMDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBkaXN0W25dID0gSW5maW5pdHk7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gSW5pdGlhbGl6ZSBtYXRyaXggdXNlZCBmb3IgcGF0aCByZWNvbnN0cnVjdGlvblxuICAgICAgLy8gSW5pdGlhbGl6ZSBkaXN0YW5jZSBtYXRyaXhcblxuXG4gICAgICB2YXIgbmV4dCA9IG5ldyBBcnJheShOc3EpO1xuICAgICAgdmFyIGVkZ2VOZXh0ID0gbmV3IEFycmF5KE5zcSk7IC8vIFByb2Nlc3MgZWRnZXNcblxuICAgICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IGVkZ2VzLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgZWRnZSA9IGVkZ2VzW19pXTtcbiAgICAgICAgdmFyIHNyYyA9IGVkZ2Uuc291cmNlKClbMF07XG4gICAgICAgIHZhciB0Z3QgPSBlZGdlLnRhcmdldCgpWzBdO1xuXG4gICAgICAgIGlmIChzcmMgPT09IHRndCkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9IC8vIGV4Y2x1ZGUgbG9vcHNcblxuXG4gICAgICAgIHZhciBzID0gaW5kZXhPZihzcmMpO1xuICAgICAgICB2YXIgdCA9IGluZGV4T2YodGd0KTtcbiAgICAgICAgdmFyIHN0ID0gcyAqIE4gKyB0OyAvLyBzb3VyY2UgdG8gdGFyZ2V0IGluZGV4XG5cbiAgICAgICAgdmFyIF93ZWlnaHQgPSB3ZWlnaHRGbihlZGdlKTsgLy8gQ2hlY2sgaWYgYWxyZWFkeSBwcm9jZXNzIGFub3RoZXIgZWRnZSBiZXR3ZWVuIHNhbWUgMiBub2Rlc1xuXG5cbiAgICAgICAgaWYgKGRpc3Rbc3RdID4gX3dlaWdodCkge1xuICAgICAgICAgIGRpc3Rbc3RdID0gX3dlaWdodDtcbiAgICAgICAgICBuZXh0W3N0XSA9IHQ7XG4gICAgICAgICAgZWRnZU5leHRbc3RdID0gZWRnZTtcbiAgICAgICAgfSAvLyBJZiB1bmRpcmVjdGVkIGdyYXBoLCBwcm9jZXNzICdyZXZlcnNlZCcgZWRnZVxuXG5cbiAgICAgICAgaWYgKCFkaXJlY3RlZCkge1xuICAgICAgICAgIHZhciB0cyA9IHQgKiBOICsgczsgLy8gdGFyZ2V0IHRvIHNvdXJjZSBpbmRleFxuXG4gICAgICAgICAgaWYgKCFkaXJlY3RlZCAmJiBkaXN0W3RzXSA+IF93ZWlnaHQpIHtcbiAgICAgICAgICAgIGRpc3RbdHNdID0gX3dlaWdodDtcbiAgICAgICAgICAgIG5leHRbdHNdID0gcztcbiAgICAgICAgICAgIGVkZ2VOZXh0W3RzXSA9IGVkZ2U7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IC8vIE1haW4gbG9vcFxuXG5cbiAgICAgIGZvciAodmFyIGsgPSAwOyBrIDwgTjsgaysrKSB7XG4gICAgICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IE47IF9pMisrKSB7XG4gICAgICAgICAgdmFyIGlrID0gX2kyICogTiArIGs7XG5cbiAgICAgICAgICBmb3IgKHZhciBfaiA9IDA7IF9qIDwgTjsgX2orKykge1xuICAgICAgICAgICAgdmFyIGlqID0gX2kyICogTiArIF9qO1xuICAgICAgICAgICAgdmFyIGtqID0gayAqIE4gKyBfajtcblxuICAgICAgICAgICAgaWYgKGRpc3RbaWtdICsgZGlzdFtral0gPCBkaXN0W2lqXSkge1xuICAgICAgICAgICAgICBkaXN0W2lqXSA9IGRpc3RbaWtdICsgZGlzdFtral07XG4gICAgICAgICAgICAgIG5leHRbaWpdID0gbmV4dFtpa107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHZhciBnZXRBcmdFbGUgPSBmdW5jdGlvbiBnZXRBcmdFbGUoZWxlKSB7XG4gICAgICAgIHJldHVybiAoc3RyaW5nKGVsZSkgPyBjeS5maWx0ZXIoZWxlKSA6IGVsZSlbMF07XG4gICAgICB9O1xuXG4gICAgICB2YXIgaW5kZXhPZkFyZ0VsZSA9IGZ1bmN0aW9uIGluZGV4T2ZBcmdFbGUoZWxlKSB7XG4gICAgICAgIHJldHVybiBpbmRleE9mKGdldEFyZ0VsZShlbGUpKTtcbiAgICAgIH07XG5cbiAgICAgIHZhciByZXMgPSB7XG4gICAgICAgIGRpc3RhbmNlOiBmdW5jdGlvbiBkaXN0YW5jZShmcm9tLCB0bykge1xuICAgICAgICAgIHZhciBpID0gaW5kZXhPZkFyZ0VsZShmcm9tKTtcbiAgICAgICAgICB2YXIgaiA9IGluZGV4T2ZBcmdFbGUodG8pO1xuICAgICAgICAgIHJldHVybiBkaXN0W2kgKiBOICsgal07XG4gICAgICAgIH0sXG4gICAgICAgIHBhdGg6IGZ1bmN0aW9uIHBhdGgoZnJvbSwgdG8pIHtcbiAgICAgICAgICB2YXIgaSA9IGluZGV4T2ZBcmdFbGUoZnJvbSk7XG4gICAgICAgICAgdmFyIGogPSBpbmRleE9mQXJnRWxlKHRvKTtcbiAgICAgICAgICB2YXIgZnJvbU5vZGUgPSBhdEluZGV4KGkpO1xuXG4gICAgICAgICAgaWYgKGkgPT09IGopIHtcbiAgICAgICAgICAgIHJldHVybiBmcm9tTm9kZS5jb2xsZWN0aW9uKCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKG5leHRbaSAqIE4gKyBqXSA9PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gY3kuY29sbGVjdGlvbigpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHZhciBwYXRoID0gY3kuY29sbGVjdGlvbigpO1xuICAgICAgICAgIHZhciBwcmV2ID0gaTtcbiAgICAgICAgICB2YXIgZWRnZTtcbiAgICAgICAgICBwYXRoLm1lcmdlKGZyb21Ob2RlKTtcblxuICAgICAgICAgIHdoaWxlIChpICE9PSBqKSB7XG4gICAgICAgICAgICBwcmV2ID0gaTtcbiAgICAgICAgICAgIGkgPSBuZXh0W2kgKiBOICsgal07XG4gICAgICAgICAgICBlZGdlID0gZWRnZU5leHRbcHJldiAqIE4gKyBpXTtcbiAgICAgICAgICAgIHBhdGgubWVyZ2UoZWRnZSk7XG4gICAgICAgICAgICBwYXRoLm1lcmdlKGF0SW5kZXgoaSkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBwYXRoO1xuICAgICAgICB9XG4gICAgICB9O1xuICAgICAgcmV0dXJuIHJlcztcbiAgICB9IC8vIGZsb3lkV2Fyc2hhbGxcblxuICB9OyAvLyBlbGVzZm5cblxuICB2YXIgYmVsbG1hbkZvcmREZWZhdWx0cyA9IGRlZmF1bHRzJGcoe1xuICAgIHdlaWdodDogZnVuY3Rpb24gd2VpZ2h0KGVkZ2UpIHtcbiAgICAgIHJldHVybiAxO1xuICAgIH0sXG4gICAgZGlyZWN0ZWQ6IGZhbHNlLFxuICAgIHJvb3Q6IG51bGxcbiAgfSk7XG4gIHZhciBlbGVzZm4kcSA9IHtcbiAgICAvLyBJbXBsZW1lbnRlZCBmcm9tIHBzZXVkb2NvZGUgZnJvbSB3aWtpcGVkaWFcbiAgICBiZWxsbWFuRm9yZDogZnVuY3Rpb24gYmVsbG1hbkZvcmQob3B0aW9ucykge1xuICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgdmFyIF9iZWxsbWFuRm9yZERlZmF1bHRzID0gYmVsbG1hbkZvcmREZWZhdWx0cyhvcHRpb25zKSxcbiAgICAgICAgICB3ZWlnaHQgPSBfYmVsbG1hbkZvcmREZWZhdWx0cy53ZWlnaHQsXG4gICAgICAgICAgZGlyZWN0ZWQgPSBfYmVsbG1hbkZvcmREZWZhdWx0cy5kaXJlY3RlZCxcbiAgICAgICAgICByb290ID0gX2JlbGxtYW5Gb3JkRGVmYXVsdHMucm9vdDtcblxuICAgICAgdmFyIHdlaWdodEZuID0gd2VpZ2h0O1xuICAgICAgdmFyIGVsZXMgPSB0aGlzO1xuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuXG4gICAgICB2YXIgX3RoaXMkYnlHcm91cCA9IHRoaXMuYnlHcm91cCgpLFxuICAgICAgICAgIGVkZ2VzID0gX3RoaXMkYnlHcm91cC5lZGdlcyxcbiAgICAgICAgICBub2RlcyA9IF90aGlzJGJ5R3JvdXAubm9kZXM7XG5cbiAgICAgIHZhciBudW1Ob2RlcyA9IG5vZGVzLmxlbmd0aDtcbiAgICAgIHZhciBpbmZvTWFwID0gbmV3IE1hcCQyKCk7XG4gICAgICB2YXIgaGFzTmVnYXRpdmVXZWlnaHRDeWNsZSA9IGZhbHNlO1xuICAgICAgdmFyIG5lZ2F0aXZlV2VpZ2h0Q3ljbGVzID0gW107XG4gICAgICByb290ID0gY3kuY29sbGVjdGlvbihyb290KVswXTsgLy8gaW4gY2FzZSBzZWxlY3RvciBwYXNzZWRcblxuICAgICAgZWRnZXMudW5tZXJnZUJ5KGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgICAgIHJldHVybiBlZGdlLmlzTG9vcCgpO1xuICAgICAgfSk7XG4gICAgICB2YXIgbnVtRWRnZXMgPSBlZGdlcy5sZW5ndGg7XG5cbiAgICAgIHZhciBnZXRJbmZvID0gZnVuY3Rpb24gZ2V0SW5mbyhub2RlKSB7XG4gICAgICAgIHZhciBvYmogPSBpbmZvTWFwLmdldChub2RlLmlkKCkpO1xuXG4gICAgICAgIGlmICghb2JqKSB7XG4gICAgICAgICAgb2JqID0ge307XG4gICAgICAgICAgaW5mb01hcC5zZXQobm9kZS5pZCgpLCBvYmopO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9iajtcbiAgICAgIH07XG5cbiAgICAgIHZhciBnZXROb2RlRnJvbVRvID0gZnVuY3Rpb24gZ2V0Tm9kZUZyb21Ubyh0bykge1xuICAgICAgICByZXR1cm4gKHN0cmluZyh0bykgPyBjeS4kKHRvKSA6IHRvKVswXTtcbiAgICAgIH07XG5cbiAgICAgIHZhciBkaXN0YW5jZVRvID0gZnVuY3Rpb24gZGlzdGFuY2VUbyh0bykge1xuICAgICAgICByZXR1cm4gZ2V0SW5mbyhnZXROb2RlRnJvbVRvKHRvKSkuZGlzdDtcbiAgICAgIH07XG5cbiAgICAgIHZhciBwYXRoVG8gPSBmdW5jdGlvbiBwYXRoVG8odG8pIHtcbiAgICAgICAgdmFyIHRoaXNTdGFydCA9IGFyZ3VtZW50cy5sZW5ndGggPiAxICYmIGFyZ3VtZW50c1sxXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzFdIDogcm9vdDtcbiAgICAgICAgdmFyIGVuZCA9IGdldE5vZGVGcm9tVG8odG8pO1xuICAgICAgICB2YXIgcGF0aCA9IFtdO1xuICAgICAgICB2YXIgbm9kZSA9IGVuZDtcblxuICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgaWYgKG5vZGUgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIF90aGlzLnNwYXduKCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdmFyIF9nZXRJbmZvID0gZ2V0SW5mbyhub2RlKSxcbiAgICAgICAgICAgICAgZWRnZSA9IF9nZXRJbmZvLmVkZ2UsXG4gICAgICAgICAgICAgIHByZWQgPSBfZ2V0SW5mby5wcmVkO1xuXG4gICAgICAgICAgcGF0aC51bnNoaWZ0KG5vZGVbMF0pO1xuXG4gICAgICAgICAgaWYgKG5vZGUuc2FtZSh0aGlzU3RhcnQpICYmIHBhdGgubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGVkZ2UgIT0gbnVsbCkge1xuICAgICAgICAgICAgcGF0aC51bnNoaWZ0KGVkZ2UpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIG5vZGUgPSBwcmVkO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZXMuc3Bhd24ocGF0aCk7XG4gICAgICB9OyAvLyBJbml0aWFsaXphdGlvbnMgeyBkaXN0LCBwcmVkLCBlZGdlIH1cblxuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG51bU5vZGVzOyBpKyspIHtcbiAgICAgICAgdmFyIG5vZGUgPSBub2Rlc1tpXTtcbiAgICAgICAgdmFyIGluZm8gPSBnZXRJbmZvKG5vZGUpO1xuXG4gICAgICAgIGlmIChub2RlLnNhbWUocm9vdCkpIHtcbiAgICAgICAgICBpbmZvLmRpc3QgPSAwO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGluZm8uZGlzdCA9IEluZmluaXR5O1xuICAgICAgICB9XG5cbiAgICAgICAgaW5mby5wcmVkID0gbnVsbDtcbiAgICAgICAgaW5mby5lZGdlID0gbnVsbDtcbiAgICAgIH0gLy8gRWRnZXMgcmVsYXhhdGlvblxuXG5cbiAgICAgIHZhciByZXBsYWNlZEVkZ2UgPSBmYWxzZTtcblxuICAgICAgdmFyIGNoZWNrRm9yRWRnZVJlcGxhY2VtZW50ID0gZnVuY3Rpb24gY2hlY2tGb3JFZGdlUmVwbGFjZW1lbnQobm9kZTEsIG5vZGUyLCBlZGdlLCBpbmZvMSwgaW5mbzIsIHdlaWdodCkge1xuICAgICAgICB2YXIgZGlzdCA9IGluZm8xLmRpc3QgKyB3ZWlnaHQ7XG5cbiAgICAgICAgaWYgKGRpc3QgPCBpbmZvMi5kaXN0ICYmICFlZGdlLnNhbWUoaW5mbzEuZWRnZSkpIHtcbiAgICAgICAgICBpbmZvMi5kaXN0ID0gZGlzdDtcbiAgICAgICAgICBpbmZvMi5wcmVkID0gbm9kZTE7XG4gICAgICAgICAgaW5mbzIuZWRnZSA9IGVkZ2U7XG4gICAgICAgICAgcmVwbGFjZWRFZGdlID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgZm9yICh2YXIgX2kgPSAxOyBfaSA8IG51bU5vZGVzOyBfaSsrKSB7XG4gICAgICAgIHJlcGxhY2VkRWRnZSA9IGZhbHNlO1xuXG4gICAgICAgIGZvciAodmFyIGUgPSAwOyBlIDwgbnVtRWRnZXM7IGUrKykge1xuICAgICAgICAgIHZhciBlZGdlID0gZWRnZXNbZV07XG4gICAgICAgICAgdmFyIHNyYyA9IGVkZ2Uuc291cmNlKCk7XG4gICAgICAgICAgdmFyIHRndCA9IGVkZ2UudGFyZ2V0KCk7XG5cbiAgICAgICAgICB2YXIgX3dlaWdodCA9IHdlaWdodEZuKGVkZ2UpO1xuXG4gICAgICAgICAgdmFyIHNyY0luZm8gPSBnZXRJbmZvKHNyYyk7XG4gICAgICAgICAgdmFyIHRndEluZm8gPSBnZXRJbmZvKHRndCk7XG4gICAgICAgICAgY2hlY2tGb3JFZGdlUmVwbGFjZW1lbnQoc3JjLCB0Z3QsIGVkZ2UsIHNyY0luZm8sIHRndEluZm8sIF93ZWlnaHQpOyAvLyBJZiB1bmRpcmVjdGVkIGdyYXBoLCB3ZSBuZWVkIHRvIHRha2UgaW50byBhY2NvdW50IHRoZSAncmV2ZXJzZScgZWRnZVxuXG4gICAgICAgICAgaWYgKCFkaXJlY3RlZCkge1xuICAgICAgICAgICAgY2hlY2tGb3JFZGdlUmVwbGFjZW1lbnQodGd0LCBzcmMsIGVkZ2UsIHRndEluZm8sIHNyY0luZm8sIF93ZWlnaHQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghcmVwbGFjZWRFZGdlKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHJlcGxhY2VkRWRnZSkge1xuICAgICAgICAvLyBDaGVjayBmb3IgbmVnYXRpdmUgd2VpZ2h0IGN5Y2xlc1xuICAgICAgICB2YXIgbmVnYXRpdmVXZWlnaHRDeWNsZUlkcyA9IFtdO1xuXG4gICAgICAgIGZvciAodmFyIF9lID0gMDsgX2UgPCBudW1FZGdlczsgX2UrKykge1xuICAgICAgICAgIHZhciBfZWRnZSA9IGVkZ2VzW19lXTtcblxuICAgICAgICAgIHZhciBfc3JjID0gX2VkZ2Uuc291cmNlKCk7XG5cbiAgICAgICAgICB2YXIgX3RndCA9IF9lZGdlLnRhcmdldCgpO1xuXG4gICAgICAgICAgdmFyIF93ZWlnaHQyID0gd2VpZ2h0Rm4oX2VkZ2UpO1xuXG4gICAgICAgICAgdmFyIHNyY0Rpc3QgPSBnZXRJbmZvKF9zcmMpLmRpc3Q7XG4gICAgICAgICAgdmFyIHRndERpc3QgPSBnZXRJbmZvKF90Z3QpLmRpc3Q7XG5cbiAgICAgICAgICBpZiAoc3JjRGlzdCArIF93ZWlnaHQyIDwgdGd0RGlzdCB8fCAhZGlyZWN0ZWQgJiYgdGd0RGlzdCArIF93ZWlnaHQyIDwgc3JjRGlzdCkge1xuICAgICAgICAgICAgaWYgKCFoYXNOZWdhdGl2ZVdlaWdodEN5Y2xlKSB7XG4gICAgICAgICAgICAgIHdhcm4oJ0dyYXBoIGNvbnRhaW5zIGEgbmVnYXRpdmUgd2VpZ2h0IGN5Y2xlIGZvciBCZWxsbWFuLUZvcmQnKTtcbiAgICAgICAgICAgICAgaGFzTmVnYXRpdmVXZWlnaHRDeWNsZSA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChvcHRpb25zLmZpbmROZWdhdGl2ZVdlaWdodEN5Y2xlcyAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgdmFyIG5lZ2F0aXZlTm9kZXMgPSBbXTtcblxuICAgICAgICAgICAgICBpZiAoc3JjRGlzdCArIF93ZWlnaHQyIDwgdGd0RGlzdCkge1xuICAgICAgICAgICAgICAgIG5lZ2F0aXZlTm9kZXMucHVzaChfc3JjKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGlmICghZGlyZWN0ZWQgJiYgdGd0RGlzdCArIF93ZWlnaHQyIDwgc3JjRGlzdCkge1xuICAgICAgICAgICAgICAgIG5lZ2F0aXZlTm9kZXMucHVzaChfdGd0KTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHZhciBudW1OZWdhdGl2ZU5vZGVzID0gbmVnYXRpdmVOb2Rlcy5sZW5ndGg7XG5cbiAgICAgICAgICAgICAgZm9yICh2YXIgbiA9IDA7IG4gPCBudW1OZWdhdGl2ZU5vZGVzOyBuKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgc3RhcnQgPSBuZWdhdGl2ZU5vZGVzW25dO1xuICAgICAgICAgICAgICAgIHZhciBjeWNsZSA9IFtzdGFydF07XG4gICAgICAgICAgICAgICAgY3ljbGUucHVzaChnZXRJbmZvKHN0YXJ0KS5lZGdlKTtcbiAgICAgICAgICAgICAgICB2YXIgX25vZGUgPSBnZXRJbmZvKHN0YXJ0KS5wcmVkO1xuXG4gICAgICAgICAgICAgICAgd2hpbGUgKGN5Y2xlLmluZGV4T2YoX25vZGUpID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgY3ljbGUucHVzaChfbm9kZSk7XG4gICAgICAgICAgICAgICAgICBjeWNsZS5wdXNoKGdldEluZm8oX25vZGUpLmVkZ2UpO1xuICAgICAgICAgICAgICAgICAgX25vZGUgPSBnZXRJbmZvKF9ub2RlKS5wcmVkO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGN5Y2xlID0gY3ljbGUuc2xpY2UoY3ljbGUuaW5kZXhPZihfbm9kZSkpO1xuICAgICAgICAgICAgICAgIHZhciBzbWFsbGVzdElkID0gY3ljbGVbMF0uaWQoKTtcbiAgICAgICAgICAgICAgICB2YXIgc21hbGxlc3RJbmRleCA9IDA7XG5cbiAgICAgICAgICAgICAgICBmb3IgKHZhciBjID0gMjsgYyA8IGN5Y2xlLmxlbmd0aDsgYyArPSAyKSB7XG4gICAgICAgICAgICAgICAgICBpZiAoY3ljbGVbY10uaWQoKSA8IHNtYWxsZXN0SWQpIHtcbiAgICAgICAgICAgICAgICAgICAgc21hbGxlc3RJZCA9IGN5Y2xlW2NdLmlkKCk7XG4gICAgICAgICAgICAgICAgICAgIHNtYWxsZXN0SW5kZXggPSBjO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGN5Y2xlID0gY3ljbGUuc2xpY2Uoc21hbGxlc3RJbmRleCkuY29uY2F0KGN5Y2xlLnNsaWNlKDAsIHNtYWxsZXN0SW5kZXgpKTtcbiAgICAgICAgICAgICAgICBjeWNsZS5wdXNoKGN5Y2xlWzBdKTtcbiAgICAgICAgICAgICAgICB2YXIgY3ljbGVJZCA9IGN5Y2xlLm1hcChmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBlbC5pZCgpO1xuICAgICAgICAgICAgICAgIH0pLmpvaW4oXCIsXCIpO1xuXG4gICAgICAgICAgICAgICAgaWYgKG5lZ2F0aXZlV2VpZ2h0Q3ljbGVJZHMuaW5kZXhPZihjeWNsZUlkKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgIG5lZ2F0aXZlV2VpZ2h0Q3ljbGVzLnB1c2goZWxlcy5zcGF3bihjeWNsZSkpO1xuICAgICAgICAgICAgICAgICAgbmVnYXRpdmVXZWlnaHRDeWNsZUlkcy5wdXNoKGN5Y2xlSWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGRpc3RhbmNlVG86IGRpc3RhbmNlVG8sXG4gICAgICAgIHBhdGhUbzogcGF0aFRvLFxuICAgICAgICBoYXNOZWdhdGl2ZVdlaWdodEN5Y2xlOiBoYXNOZWdhdGl2ZVdlaWdodEN5Y2xlLFxuICAgICAgICBuZWdhdGl2ZVdlaWdodEN5Y2xlczogbmVnYXRpdmVXZWlnaHRDeWNsZXNcbiAgICAgIH07XG4gICAgfSAvLyBiZWxsbWFuRm9yZFxuXG4gIH07IC8vIGVsZXNmblxuXG4gIHZhciBzcXJ0MiA9IE1hdGguc3FydCgyKTsgLy8gRnVuY3Rpb24gd2hpY2ggY29sYXBzZXMgMiAobWV0YSkgbm9kZXMgaW50byBvbmVcbiAgLy8gVXBkYXRlcyB0aGUgcmVtYWluaW5nIGVkZ2UgbGlzdHNcbiAgLy8gUmVjZWl2ZXMgYXMgYSBwYXJhbWF0ZXIgdGhlIGVkZ2Ugd2hpY2ggY2F1c2VzIHRoZSBjb2xsYXBzZVxuXG4gIHZhciBjb2xsYXBzZSA9IGZ1bmN0aW9uIGNvbGxhcHNlKGVkZ2VJbmRleCwgbm9kZU1hcCwgcmVtYWluaW5nRWRnZXMpIHtcbiAgICBpZiAocmVtYWluaW5nRWRnZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBlcnJvcihcIkthcmdlci1TdGVpbiBtdXN0IGJlIHJ1biBvbiBhIGNvbm5lY3RlZCAoc3ViKWdyYXBoXCIpO1xuICAgIH1cblxuICAgIHZhciBlZGdlSW5mbyA9IHJlbWFpbmluZ0VkZ2VzW2VkZ2VJbmRleF07XG4gICAgdmFyIHNvdXJjZUluID0gZWRnZUluZm9bMV07XG4gICAgdmFyIHRhcmdldEluID0gZWRnZUluZm9bMl07XG4gICAgdmFyIHBhcnRpdGlvbjEgPSBub2RlTWFwW3NvdXJjZUluXTtcbiAgICB2YXIgcGFydGl0aW9uMiA9IG5vZGVNYXBbdGFyZ2V0SW5dO1xuICAgIHZhciBuZXdFZGdlcyA9IHJlbWFpbmluZ0VkZ2VzOyAvLyByZS11c2UgYXJyYXlcbiAgICAvLyBEZWxldGUgYWxsIGVkZ2VzIGJldHdlZW4gcGFydGl0aW9uMSBhbmQgcGFydGl0aW9uMlxuXG4gICAgZm9yICh2YXIgaSA9IG5ld0VkZ2VzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB2YXIgZWRnZSA9IG5ld0VkZ2VzW2ldO1xuICAgICAgdmFyIHNyYyA9IGVkZ2VbMV07XG4gICAgICB2YXIgdGd0ID0gZWRnZVsyXTtcblxuICAgICAgaWYgKG5vZGVNYXBbc3JjXSA9PT0gcGFydGl0aW9uMSAmJiBub2RlTWFwW3RndF0gPT09IHBhcnRpdGlvbjIgfHwgbm9kZU1hcFtzcmNdID09PSBwYXJ0aXRpb24yICYmIG5vZGVNYXBbdGd0XSA9PT0gcGFydGl0aW9uMSkge1xuICAgICAgICBuZXdFZGdlcy5zcGxpY2UoaSwgMSk7XG4gICAgICB9XG4gICAgfSAvLyBBbGwgZWRnZXMgcG9pbnRpbmcgdG8gcGFydGl0aW9uMiBzaG91bGQgbm93IHBvaW50IHRvIHBhcnRpdGlvbjFcblxuXG4gICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IG5ld0VkZ2VzLmxlbmd0aDsgX2krKykge1xuICAgICAgdmFyIF9lZGdlID0gbmV3RWRnZXNbX2ldO1xuXG4gICAgICBpZiAoX2VkZ2VbMV0gPT09IHBhcnRpdGlvbjIpIHtcbiAgICAgICAgLy8gQ2hlY2sgc291cmNlXG4gICAgICAgIG5ld0VkZ2VzW19pXSA9IF9lZGdlLnNsaWNlKCk7IC8vIGNvcHlcblxuICAgICAgICBuZXdFZGdlc1tfaV1bMV0gPSBwYXJ0aXRpb24xO1xuICAgICAgfSBlbHNlIGlmIChfZWRnZVsyXSA9PT0gcGFydGl0aW9uMikge1xuICAgICAgICAvLyBDaGVjayB0YXJnZXRcbiAgICAgICAgbmV3RWRnZXNbX2ldID0gX2VkZ2Uuc2xpY2UoKTsgLy8gY29weVxuXG4gICAgICAgIG5ld0VkZ2VzW19pXVsyXSA9IHBhcnRpdGlvbjE7XG4gICAgICB9XG4gICAgfSAvLyBNb3ZlIGFsbCBub2RlcyBmcm9tIHBhcnRpdGlvbjIgdG8gcGFydGl0aW9uMVxuXG5cbiAgICBmb3IgKHZhciBfaTIgPSAwOyBfaTIgPCBub2RlTWFwLmxlbmd0aDsgX2kyKyspIHtcbiAgICAgIGlmIChub2RlTWFwW19pMl0gPT09IHBhcnRpdGlvbjIpIHtcbiAgICAgICAgbm9kZU1hcFtfaTJdID0gcGFydGl0aW9uMTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbmV3RWRnZXM7XG4gIH07IC8vIENvbnRyYWN0cyBhIGdyYXBoIHVudGlsIHdlIHJlYWNoIGEgY2VydGFpbiBudW1iZXIgb2YgbWV0YSBub2Rlc1xuXG5cbiAgdmFyIGNvbnRyYWN0VW50aWwgPSBmdW5jdGlvbiBjb250cmFjdFVudGlsKG1ldGFOb2RlTWFwLCByZW1haW5pbmdFZGdlcywgc2l6ZSwgc2l6ZUxpbWl0KSB7XG4gICAgd2hpbGUgKHNpemUgPiBzaXplTGltaXQpIHtcbiAgICAgIC8vIENob29zZSBhbiBlZGdlIHJhbmRvbWx5XG4gICAgICB2YXIgZWRnZUluZGV4ID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogcmVtYWluaW5nRWRnZXMubGVuZ3RoKTsgLy8gQ29sbGFwc2UgZ3JhcGggYmFzZWQgb24gZWRnZVxuXG4gICAgICByZW1haW5pbmdFZGdlcyA9IGNvbGxhcHNlKGVkZ2VJbmRleCwgbWV0YU5vZGVNYXAsIHJlbWFpbmluZ0VkZ2VzKTtcbiAgICAgIHNpemUtLTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVtYWluaW5nRWRnZXM7XG4gIH07XG5cbiAgdmFyIGVsZXNmbiRwID0ge1xuICAgIC8vIENvbXB1dGVzIHRoZSBtaW5pbXVtIGN1dCBvZiBhbiB1bmRpcmVjdGVkIGdyYXBoXG4gICAgLy8gUmV0dXJucyB0aGUgY29ycmVjdCBhbnN3ZXIgd2l0aCBoaWdoIHByb2JhYmlsaXR5XG4gICAga2FyZ2VyU3RlaW46IGZ1bmN0aW9uIGthcmdlclN0ZWluKCkge1xuICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgdmFyIF90aGlzJGJ5R3JvdXAgPSB0aGlzLmJ5R3JvdXAoKSxcbiAgICAgICAgICBub2RlcyA9IF90aGlzJGJ5R3JvdXAubm9kZXMsXG4gICAgICAgICAgZWRnZXMgPSBfdGhpcyRieUdyb3VwLmVkZ2VzO1xuXG4gICAgICBlZGdlcy51bm1lcmdlQnkoZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICAgICAgcmV0dXJuIGVkZ2UuaXNMb29wKCk7XG4gICAgICB9KTtcbiAgICAgIHZhciBudW1Ob2RlcyA9IG5vZGVzLmxlbmd0aDtcbiAgICAgIHZhciBudW1FZGdlcyA9IGVkZ2VzLmxlbmd0aDtcbiAgICAgIHZhciBudW1JdGVyID0gTWF0aC5jZWlsKE1hdGgucG93KE1hdGgubG9nKG51bU5vZGVzKSAvIE1hdGguTE4yLCAyKSk7XG4gICAgICB2YXIgc3RvcFNpemUgPSBNYXRoLmZsb29yKG51bU5vZGVzIC8gc3FydDIpO1xuXG4gICAgICBpZiAobnVtTm9kZXMgPCAyKSB7XG4gICAgICAgIGVycm9yKCdBdCBsZWFzdCAyIG5vZGVzIGFyZSByZXF1aXJlZCBmb3IgS2FyZ2VyLVN0ZWluIGFsZ29yaXRobScpO1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfSAvLyBOb3cgc3RvcmUgZWRnZSBkZXN0aW5hdGlvbiBhcyBpbmRleGVzXG4gICAgICAvLyBGb3JtYXQgZm9yIGVhY2ggZWRnZSAoZWRnZSBpbmRleCwgc291cmNlIG5vZGUgaW5kZXgsIHRhcmdldCBub2RlIGluZGV4KVxuXG5cbiAgICAgIHZhciBlZGdlSW5kZXhlcyA9IFtdO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG51bUVkZ2VzOyBpKyspIHtcbiAgICAgICAgdmFyIGUgPSBlZGdlc1tpXTtcbiAgICAgICAgZWRnZUluZGV4ZXMucHVzaChbaSwgbm9kZXMuaW5kZXhPZihlLnNvdXJjZSgpKSwgbm9kZXMuaW5kZXhPZihlLnRhcmdldCgpKV0pO1xuICAgICAgfSAvLyBXZSB3aWxsIHN0b3JlIHRoZSBiZXN0IGN1dCBmb3VuZCBoZXJlXG5cblxuICAgICAgdmFyIG1pbkN1dFNpemUgPSBJbmZpbml0eTtcbiAgICAgIHZhciBtaW5DdXRFZGdlSW5kZXhlcyA9IFtdO1xuICAgICAgdmFyIG1pbkN1dE5vZGVNYXAgPSBuZXcgQXJyYXkobnVtTm9kZXMpOyAvLyBJbml0aWFsIG1ldGEgbm9kZSBwYXJ0aXRpb25cblxuICAgICAgdmFyIG1ldGFOb2RlTWFwID0gbmV3IEFycmF5KG51bU5vZGVzKTtcbiAgICAgIHZhciBtZXRhTm9kZU1hcDIgPSBuZXcgQXJyYXkobnVtTm9kZXMpO1xuXG4gICAgICB2YXIgY29weU5vZGVzTWFwID0gZnVuY3Rpb24gY29weU5vZGVzTWFwKGZyb20sIHRvKSB7XG4gICAgICAgIGZvciAodmFyIF9pMyA9IDA7IF9pMyA8IG51bU5vZGVzOyBfaTMrKykge1xuICAgICAgICAgIHRvW19pM10gPSBmcm9tW19pM107XG4gICAgICAgIH1cbiAgICAgIH07IC8vIE1haW4gbG9vcFxuXG5cbiAgICAgIGZvciAodmFyIGl0ZXIgPSAwOyBpdGVyIDw9IG51bUl0ZXI7IGl0ZXIrKykge1xuICAgICAgICAvLyBSZXNldCBtZXRhIG5vZGUgcGFydGl0aW9uXG4gICAgICAgIGZvciAodmFyIF9pNCA9IDA7IF9pNCA8IG51bU5vZGVzOyBfaTQrKykge1xuICAgICAgICAgIG1ldGFOb2RlTWFwW19pNF0gPSBfaTQ7XG4gICAgICAgIH0gLy8gQ29udHJhY3QgdW50aWwgc3RvcCBwb2ludCAoc3RvcFNpemUgbm9kZXMpXG5cblxuICAgICAgICB2YXIgZWRnZXNTdGF0ZSA9IGNvbnRyYWN0VW50aWwobWV0YU5vZGVNYXAsIGVkZ2VJbmRleGVzLnNsaWNlKCksIG51bU5vZGVzLCBzdG9wU2l6ZSk7XG4gICAgICAgIHZhciBlZGdlc1N0YXRlMiA9IGVkZ2VzU3RhdGUuc2xpY2UoKTsgLy8gY29weVxuICAgICAgICAvLyBDcmVhdGUgYSBjb3B5IG9mIHRoZSBjb2xhcHNlZCBub2RlcyBzdGF0ZVxuXG4gICAgICAgIGNvcHlOb2Rlc01hcChtZXRhTm9kZU1hcCwgbWV0YU5vZGVNYXAyKTsgLy8gUnVuIDIgaXRlcmF0aW9ucyBzdGFydGluZyBpbiB0aGUgc3RvcCBzdGF0ZVxuXG4gICAgICAgIHZhciByZXMxID0gY29udHJhY3RVbnRpbChtZXRhTm9kZU1hcCwgZWRnZXNTdGF0ZSwgc3RvcFNpemUsIDIpO1xuICAgICAgICB2YXIgcmVzMiA9IGNvbnRyYWN0VW50aWwobWV0YU5vZGVNYXAyLCBlZGdlc1N0YXRlMiwgc3RvcFNpemUsIDIpOyAvLyBJcyBhbnkgb2YgdGhlIDIgcmVzdWx0cyB0aGUgYmVzdCBjdXQgc28gZmFyP1xuXG4gICAgICAgIGlmIChyZXMxLmxlbmd0aCA8PSByZXMyLmxlbmd0aCAmJiByZXMxLmxlbmd0aCA8IG1pbkN1dFNpemUpIHtcbiAgICAgICAgICBtaW5DdXRTaXplID0gcmVzMS5sZW5ndGg7XG4gICAgICAgICAgbWluQ3V0RWRnZUluZGV4ZXMgPSByZXMxO1xuICAgICAgICAgIGNvcHlOb2Rlc01hcChtZXRhTm9kZU1hcCwgbWluQ3V0Tm9kZU1hcCk7XG4gICAgICAgIH0gZWxzZSBpZiAocmVzMi5sZW5ndGggPD0gcmVzMS5sZW5ndGggJiYgcmVzMi5sZW5ndGggPCBtaW5DdXRTaXplKSB7XG4gICAgICAgICAgbWluQ3V0U2l6ZSA9IHJlczIubGVuZ3RoO1xuICAgICAgICAgIG1pbkN1dEVkZ2VJbmRleGVzID0gcmVzMjtcbiAgICAgICAgICBjb3B5Tm9kZXNNYXAobWV0YU5vZGVNYXAyLCBtaW5DdXROb2RlTWFwKTtcbiAgICAgICAgfVxuICAgICAgfSAvLyBlbmQgb2YgbWFpbiBsb29wXG4gICAgICAvLyBDb25zdHJ1Y3QgcmVzdWx0XG5cblxuICAgICAgdmFyIGN1dCA9IHRoaXMuc3Bhd24obWluQ3V0RWRnZUluZGV4ZXMubWFwKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHJldHVybiBlZGdlc1tlWzBdXTtcbiAgICAgIH0pKTtcbiAgICAgIHZhciBwYXJ0aXRpb24xID0gdGhpcy5zcGF3bigpO1xuICAgICAgdmFyIHBhcnRpdGlvbjIgPSB0aGlzLnNwYXduKCk7IC8vIHRyYXZlcnNlIG1ldGFOb2RlTWFwIGZvciBiZXN0IGN1dFxuXG4gICAgICB2YXIgd2l0bmVzc05vZGVQYXJ0aXRpb24gPSBtaW5DdXROb2RlTWFwWzBdO1xuXG4gICAgICBmb3IgKHZhciBfaTUgPSAwOyBfaTUgPCBtaW5DdXROb2RlTWFwLmxlbmd0aDsgX2k1KyspIHtcbiAgICAgICAgdmFyIHBhcnRpdGlvbklkID0gbWluQ3V0Tm9kZU1hcFtfaTVdO1xuICAgICAgICB2YXIgbm9kZSA9IG5vZGVzW19pNV07XG5cbiAgICAgICAgaWYgKHBhcnRpdGlvbklkID09PSB3aXRuZXNzTm9kZVBhcnRpdGlvbikge1xuICAgICAgICAgIHBhcnRpdGlvbjEubWVyZ2Uobm9kZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcGFydGl0aW9uMi5tZXJnZShub2RlKTtcbiAgICAgICAgfVxuICAgICAgfSAvLyBjb25zdHJ1Y3QgY29tcG9uZW50cyBjb3JyZXNwb25kaW5nIHRvIGVhY2ggZGlzam9pbnQgc3Vic2V0IG9mIG5vZGVzXG5cblxuICAgICAgdmFyIGNvbnN0cnVjdENvbXBvbmVudCA9IGZ1bmN0aW9uIGNvbnN0cnVjdENvbXBvbmVudChzdWJzZXQpIHtcbiAgICAgICAgdmFyIGNvbXBvbmVudCA9IF90aGlzLnNwYXduKCk7XG5cbiAgICAgICAgc3Vic2V0LmZvckVhY2goZnVuY3Rpb24gKG5vZGUpIHtcbiAgICAgICAgICBjb21wb25lbnQubWVyZ2Uobm9kZSk7XG4gICAgICAgICAgbm9kZS5jb25uZWN0ZWRFZGdlcygpLmZvckVhY2goZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICAgICAgICAgIC8vIGVuc3VyZSBlZGdlIGlzIHdpdGhpbiBjYWxsaW5nIGNvbGxlY3Rpb24gYW5kIGVkZ2UgaXMgbm90IGluIGN1dFxuICAgICAgICAgICAgaWYgKF90aGlzLmNvbnRhaW5zKGVkZ2UpICYmICFjdXQuY29udGFpbnMoZWRnZSkpIHtcbiAgICAgICAgICAgICAgY29tcG9uZW50Lm1lcmdlKGVkZ2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGNvbXBvbmVudDtcbiAgICAgIH07XG5cbiAgICAgIHZhciBjb21wb25lbnRzID0gW2NvbnN0cnVjdENvbXBvbmVudChwYXJ0aXRpb24xKSwgY29uc3RydWN0Q29tcG9uZW50KHBhcnRpdGlvbjIpXTtcbiAgICAgIHZhciByZXQgPSB7XG4gICAgICAgIGN1dDogY3V0LFxuICAgICAgICBjb21wb25lbnRzOiBjb21wb25lbnRzLFxuICAgICAgICAvLyBuLmIuIHBhcnRpdGlvbnMgYXJlIGluY2x1ZGVkIHRvIGJlIGNvbXBhdGlibGUgd2l0aCB0aGUgb2xkIGFwaSBzcGVjXG4gICAgICAgIC8vIChjb3VsZCBiZSByZW1vdmVkIGluIGEgZnV0dXJlIG1ham9yIHZlcnNpb24pXG4gICAgICAgIHBhcnRpdGlvbjE6IHBhcnRpdGlvbjEsXG4gICAgICAgIHBhcnRpdGlvbjI6IHBhcnRpdGlvbjJcbiAgICAgIH07XG4gICAgICByZXR1cm4gcmV0O1xuICAgIH1cbiAgfTsgLy8gZWxlc2ZuXG5cbiAgdmFyIGNvcHlQb3NpdGlvbiA9IGZ1bmN0aW9uIGNvcHlQb3NpdGlvbihwKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHg6IHAueCxcbiAgICAgIHk6IHAueVxuICAgIH07XG4gIH07XG4gIHZhciBtb2RlbFRvUmVuZGVyZWRQb3NpdGlvbiA9IGZ1bmN0aW9uIG1vZGVsVG9SZW5kZXJlZFBvc2l0aW9uKHAsIHpvb20sIHBhbikge1xuICAgIHJldHVybiB7XG4gICAgICB4OiBwLnggKiB6b29tICsgcGFuLngsXG4gICAgICB5OiBwLnkgKiB6b29tICsgcGFuLnlcbiAgICB9O1xuICB9O1xuICB2YXIgcmVuZGVyZWRUb01vZGVsUG9zaXRpb24gPSBmdW5jdGlvbiByZW5kZXJlZFRvTW9kZWxQb3NpdGlvbihwLCB6b29tLCBwYW4pIHtcbiAgICByZXR1cm4ge1xuICAgICAgeDogKHAueCAtIHBhbi54KSAvIHpvb20sXG4gICAgICB5OiAocC55IC0gcGFuLnkpIC8gem9vbVxuICAgIH07XG4gIH07XG4gIHZhciBhcnJheTJwb2ludCA9IGZ1bmN0aW9uIGFycmF5MnBvaW50KGFycikge1xuICAgIHJldHVybiB7XG4gICAgICB4OiBhcnJbMF0sXG4gICAgICB5OiBhcnJbMV1cbiAgICB9O1xuICB9O1xuICB2YXIgbWluID0gZnVuY3Rpb24gbWluKGFycikge1xuICAgIHZhciBiZWdpbiA9IGFyZ3VtZW50cy5sZW5ndGggPiAxICYmIGFyZ3VtZW50c1sxXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzFdIDogMDtcbiAgICB2YXIgZW5kID0gYXJndW1lbnRzLmxlbmd0aCA+IDIgJiYgYXJndW1lbnRzWzJdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMl0gOiBhcnIubGVuZ3RoO1xuICAgIHZhciBtaW4gPSBJbmZpbml0eTtcblxuICAgIGZvciAodmFyIGkgPSBiZWdpbjsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICB2YXIgdmFsID0gYXJyW2ldO1xuXG4gICAgICBpZiAoaXNGaW5pdGUodmFsKSkge1xuICAgICAgICBtaW4gPSBNYXRoLm1pbih2YWwsIG1pbik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG1pbjtcbiAgfTtcbiAgdmFyIG1heCA9IGZ1bmN0aW9uIG1heChhcnIpIHtcbiAgICB2YXIgYmVnaW4gPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IDA7XG4gICAgdmFyIGVuZCA9IGFyZ3VtZW50cy5sZW5ndGggPiAyICYmIGFyZ3VtZW50c1syXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzJdIDogYXJyLmxlbmd0aDtcbiAgICB2YXIgbWF4ID0gLUluZmluaXR5O1xuXG4gICAgZm9yICh2YXIgaSA9IGJlZ2luOyBpIDwgZW5kOyBpKyspIHtcbiAgICAgIHZhciB2YWwgPSBhcnJbaV07XG5cbiAgICAgIGlmIChpc0Zpbml0ZSh2YWwpKSB7XG4gICAgICAgIG1heCA9IE1hdGgubWF4KHZhbCwgbWF4KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbWF4O1xuICB9O1xuICB2YXIgbWVhbiA9IGZ1bmN0aW9uIG1lYW4oYXJyKSB7XG4gICAgdmFyIGJlZ2luID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiAwO1xuICAgIHZhciBlbmQgPSBhcmd1bWVudHMubGVuZ3RoID4gMiAmJiBhcmd1bWVudHNbMl0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1syXSA6IGFyci5sZW5ndGg7XG4gICAgdmFyIHRvdGFsID0gMDtcbiAgICB2YXIgbiA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gYmVnaW47IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdmFyIHZhbCA9IGFycltpXTtcblxuICAgICAgaWYgKGlzRmluaXRlKHZhbCkpIHtcbiAgICAgICAgdG90YWwgKz0gdmFsO1xuICAgICAgICBuKys7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRvdGFsIC8gbjtcbiAgfTtcbiAgdmFyIG1lZGlhbiA9IGZ1bmN0aW9uIG1lZGlhbihhcnIpIHtcbiAgICB2YXIgYmVnaW4gPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IDA7XG4gICAgdmFyIGVuZCA9IGFyZ3VtZW50cy5sZW5ndGggPiAyICYmIGFyZ3VtZW50c1syXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzJdIDogYXJyLmxlbmd0aDtcbiAgICB2YXIgY29weSA9IGFyZ3VtZW50cy5sZW5ndGggPiAzICYmIGFyZ3VtZW50c1szXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzNdIDogdHJ1ZTtcbiAgICB2YXIgc29ydCA9IGFyZ3VtZW50cy5sZW5ndGggPiA0ICYmIGFyZ3VtZW50c1s0XSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzRdIDogdHJ1ZTtcbiAgICB2YXIgaW5jbHVkZUhvbGVzID0gYXJndW1lbnRzLmxlbmd0aCA+IDUgJiYgYXJndW1lbnRzWzVdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbNV0gOiB0cnVlO1xuXG4gICAgaWYgKGNvcHkpIHtcbiAgICAgIGFyciA9IGFyci5zbGljZShiZWdpbiwgZW5kKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGVuZCA8IGFyci5sZW5ndGgpIHtcbiAgICAgICAgYXJyLnNwbGljZShlbmQsIGFyci5sZW5ndGggLSBlbmQpO1xuICAgICAgfVxuXG4gICAgICBpZiAoYmVnaW4gPiAwKSB7XG4gICAgICAgIGFyci5zcGxpY2UoMCwgYmVnaW4pO1xuICAgICAgfVxuICAgIH0gLy8gYWxsIG5vbiBmaW5pdGUgKGUuZy4gSW5maW5pdHksIE5hTikgZWxlbWVudHMgbXVzdCBiZSAtSW5maW5pdHkgc28gdGhleSBnbyB0byB0aGUgc3RhcnRcblxuXG4gICAgdmFyIG9mZiA9IDA7IC8vIG9mZnNldCBmcm9tIG5vbi1maW5pdGUgdmFsdWVzXG5cbiAgICBmb3IgKHZhciBpID0gYXJyLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB2YXIgdiA9IGFycltpXTtcblxuICAgICAgaWYgKGluY2x1ZGVIb2xlcykge1xuICAgICAgICBpZiAoIWlzRmluaXRlKHYpKSB7XG4gICAgICAgICAgYXJyW2ldID0gLUluZmluaXR5O1xuICAgICAgICAgIG9mZisrO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBqdXN0IHJlbW92ZSBpdCBpZiB3ZSBkb24ndCB3YW50IHRvIGNvbnNpZGVyIGhvbGVzXG4gICAgICAgIGFyci5zcGxpY2UoaSwgMSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHNvcnQpIHtcbiAgICAgIGFyci5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBhIC0gYjtcbiAgICAgIH0pOyAvLyByZXF1aXJlcyBjb3B5ID0gdHJ1ZSBpZiB5b3UgZG9uJ3Qgd2FudCB0byBjaGFuZ2UgdGhlIG9yaWdcbiAgICB9XG5cbiAgICB2YXIgbGVuID0gYXJyLmxlbmd0aDtcbiAgICB2YXIgbWlkID0gTWF0aC5mbG9vcihsZW4gLyAyKTtcblxuICAgIGlmIChsZW4gJSAyICE9PSAwKSB7XG4gICAgICByZXR1cm4gYXJyW21pZCArIDEgKyBvZmZdO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gKGFyclttaWQgLSAxICsgb2ZmXSArIGFyclttaWQgKyBvZmZdKSAvIDI7XG4gICAgfVxuICB9O1xuICB2YXIgZGVnMnJhZCA9IGZ1bmN0aW9uIGRlZzJyYWQoZGVnKSB7XG4gICAgcmV0dXJuIE1hdGguUEkgKiBkZWcgLyAxODA7XG4gIH07XG4gIHZhciBnZXRBbmdsZUZyb21EaXNwID0gZnVuY3Rpb24gZ2V0QW5nbGVGcm9tRGlzcChkaXNwWCwgZGlzcFkpIHtcbiAgICByZXR1cm4gTWF0aC5hdGFuMihkaXNwWSwgZGlzcFgpIC0gTWF0aC5QSSAvIDI7XG4gIH07XG4gIHZhciBsb2cyID0gTWF0aC5sb2cyIHx8IGZ1bmN0aW9uIChuKSB7XG4gICAgcmV0dXJuIE1hdGgubG9nKG4pIC8gTWF0aC5sb2coMik7XG4gIH07XG4gIHZhciBzaWdudW0gPSBmdW5jdGlvbiBzaWdudW0oeCkge1xuICAgIGlmICh4ID4gMCkge1xuICAgICAgcmV0dXJuIDE7XG4gICAgfSBlbHNlIGlmICh4IDwgMCkge1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gIH07XG4gIHZhciBkaXN0ID0gZnVuY3Rpb24gZGlzdChwMSwgcDIpIHtcbiAgICByZXR1cm4gTWF0aC5zcXJ0KHNxZGlzdChwMSwgcDIpKTtcbiAgfTtcbiAgdmFyIHNxZGlzdCA9IGZ1bmN0aW9uIHNxZGlzdChwMSwgcDIpIHtcbiAgICB2YXIgZHggPSBwMi54IC0gcDEueDtcbiAgICB2YXIgZHkgPSBwMi55IC0gcDEueTtcbiAgICByZXR1cm4gZHggKiBkeCArIGR5ICogZHk7XG4gIH07XG4gIHZhciBpblBsYWNlU3VtTm9ybWFsaXplID0gZnVuY3Rpb24gaW5QbGFjZVN1bU5vcm1hbGl6ZSh2KSB7XG4gICAgdmFyIGxlbmd0aCA9IHYubGVuZ3RoOyAvLyBGaXJzdCwgZ2V0IHN1bSBvZiBhbGwgZWxlbWVudHNcblxuICAgIHZhciB0b3RhbCA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB0b3RhbCArPSB2W2ldO1xuICAgIH0gLy8gTm93LCBkaXZpZGUgZWFjaCBieSB0aGUgc3VtIG9mIGFsbCBlbGVtZW50c1xuXG5cbiAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgbGVuZ3RoOyBfaSsrKSB7XG4gICAgICB2W19pXSA9IHZbX2ldIC8gdG90YWw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHY7XG4gIH07XG5cbiAgdmFyIHFiZXppZXJBdCA9IGZ1bmN0aW9uIHFiZXppZXJBdChwMCwgcDEsIHAyLCB0KSB7XG4gICAgcmV0dXJuICgxIC0gdCkgKiAoMSAtIHQpICogcDAgKyAyICogKDEgLSB0KSAqIHQgKiBwMSArIHQgKiB0ICogcDI7XG4gIH07XG4gIHZhciBxYmV6aWVyUHRBdCA9IGZ1bmN0aW9uIHFiZXppZXJQdEF0KHAwLCBwMSwgcDIsIHQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgeDogcWJlemllckF0KHAwLngsIHAxLngsIHAyLngsIHQpLFxuICAgICAgeTogcWJlemllckF0KHAwLnksIHAxLnksIHAyLnksIHQpXG4gICAgfTtcbiAgfTtcbiAgdmFyIGxpbmVBdCA9IGZ1bmN0aW9uIGxpbmVBdChwMCwgcDEsIHQsIGQpIHtcbiAgICB2YXIgdmVjID0ge1xuICAgICAgeDogcDEueCAtIHAwLngsXG4gICAgICB5OiBwMS55IC0gcDAueVxuICAgIH07XG4gICAgdmFyIHZlY0Rpc3QgPSBkaXN0KHAwLCBwMSk7XG4gICAgdmFyIG5vcm1WZWMgPSB7XG4gICAgICB4OiB2ZWMueCAvIHZlY0Rpc3QsXG4gICAgICB5OiB2ZWMueSAvIHZlY0Rpc3RcbiAgICB9O1xuICAgIHQgPSB0ID09IG51bGwgPyAwIDogdDtcbiAgICBkID0gZCAhPSBudWxsID8gZCA6IHQgKiB2ZWNEaXN0O1xuICAgIHJldHVybiB7XG4gICAgICB4OiBwMC54ICsgbm9ybVZlYy54ICogZCxcbiAgICAgIHk6IHAwLnkgKyBub3JtVmVjLnkgKiBkXG4gICAgfTtcbiAgfTtcbiAgdmFyIGJvdW5kID0gZnVuY3Rpb24gYm91bmQobWluLCB2YWwsIG1heCkge1xuICAgIHJldHVybiBNYXRoLm1heChtaW4sIE1hdGgubWluKG1heCwgdmFsKSk7XG4gIH07IC8vIG1ha2VzIGEgZnVsbCBiYiAoeDEsIHkxLCB4MiwgeTIsIHcsIGgpIGZyb20gaW1wbGljaXQgcGFyYW1zXG5cbiAgdmFyIG1ha2VCb3VuZGluZ0JveCA9IGZ1bmN0aW9uIG1ha2VCb3VuZGluZ0JveChiYikge1xuICAgIGlmIChiYiA9PSBudWxsKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB4MTogSW5maW5pdHksXG4gICAgICAgIHkxOiBJbmZpbml0eSxcbiAgICAgICAgeDI6IC1JbmZpbml0eSxcbiAgICAgICAgeTI6IC1JbmZpbml0eSxcbiAgICAgICAgdzogMCxcbiAgICAgICAgaDogMFxuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKGJiLngxICE9IG51bGwgJiYgYmIueTEgIT0gbnVsbCkge1xuICAgICAgaWYgKGJiLngyICE9IG51bGwgJiYgYmIueTIgIT0gbnVsbCAmJiBiYi54MiA+PSBiYi54MSAmJiBiYi55MiA+PSBiYi55MSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHgxOiBiYi54MSxcbiAgICAgICAgICB5MTogYmIueTEsXG4gICAgICAgICAgeDI6IGJiLngyLFxuICAgICAgICAgIHkyOiBiYi55MixcbiAgICAgICAgICB3OiBiYi54MiAtIGJiLngxLFxuICAgICAgICAgIGg6IGJiLnkyIC0gYmIueTFcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSBpZiAoYmIudyAhPSBudWxsICYmIGJiLmggIT0gbnVsbCAmJiBiYi53ID49IDAgJiYgYmIuaCA+PSAwKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgeDE6IGJiLngxLFxuICAgICAgICAgIHkxOiBiYi55MSxcbiAgICAgICAgICB4MjogYmIueDEgKyBiYi53LFxuICAgICAgICAgIHkyOiBiYi55MSArIGJiLmgsXG4gICAgICAgICAgdzogYmIudyxcbiAgICAgICAgICBoOiBiYi5oXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuICB9O1xuICB2YXIgY29weUJvdW5kaW5nQm94ID0gZnVuY3Rpb24gY29weUJvdW5kaW5nQm94KGJiKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHgxOiBiYi54MSxcbiAgICAgIHgyOiBiYi54MixcbiAgICAgIHc6IGJiLncsXG4gICAgICB5MTogYmIueTEsXG4gICAgICB5MjogYmIueTIsXG4gICAgICBoOiBiYi5oXG4gICAgfTtcbiAgfTtcbiAgdmFyIGNsZWFyQm91bmRpbmdCb3ggPSBmdW5jdGlvbiBjbGVhckJvdW5kaW5nQm94KGJiKSB7XG4gICAgYmIueDEgPSBJbmZpbml0eTtcbiAgICBiYi55MSA9IEluZmluaXR5O1xuICAgIGJiLngyID0gLUluZmluaXR5O1xuICAgIGJiLnkyID0gLUluZmluaXR5O1xuICAgIGJiLncgPSAwO1xuICAgIGJiLmggPSAwO1xuICB9O1xuICB2YXIgdXBkYXRlQm91bmRpbmdCb3ggPSBmdW5jdGlvbiB1cGRhdGVCb3VuZGluZ0JveChiYjEsIGJiMikge1xuICAgIC8vIHVwZGF0ZSBiYjEgd2l0aCBiYjIgYm91bmRzXG4gICAgYmIxLngxID0gTWF0aC5taW4oYmIxLngxLCBiYjIueDEpO1xuICAgIGJiMS54MiA9IE1hdGgubWF4KGJiMS54MiwgYmIyLngyKTtcbiAgICBiYjEudyA9IGJiMS54MiAtIGJiMS54MTtcbiAgICBiYjEueTEgPSBNYXRoLm1pbihiYjEueTEsIGJiMi55MSk7XG4gICAgYmIxLnkyID0gTWF0aC5tYXgoYmIxLnkyLCBiYjIueTIpO1xuICAgIGJiMS5oID0gYmIxLnkyIC0gYmIxLnkxO1xuICB9O1xuICB2YXIgZXhwYW5kQm91bmRpbmdCb3hCeVBvaW50ID0gZnVuY3Rpb24gZXhwYW5kQm91bmRpbmdCb3hCeVBvaW50KGJiLCB4LCB5KSB7XG4gICAgYmIueDEgPSBNYXRoLm1pbihiYi54MSwgeCk7XG4gICAgYmIueDIgPSBNYXRoLm1heChiYi54MiwgeCk7XG4gICAgYmIudyA9IGJiLngyIC0gYmIueDE7XG4gICAgYmIueTEgPSBNYXRoLm1pbihiYi55MSwgeSk7XG4gICAgYmIueTIgPSBNYXRoLm1heChiYi55MiwgeSk7XG4gICAgYmIuaCA9IGJiLnkyIC0gYmIueTE7XG4gIH07XG4gIHZhciBleHBhbmRCb3VuZGluZ0JveCA9IGZ1bmN0aW9uIGV4cGFuZEJvdW5kaW5nQm94KGJiKSB7XG4gICAgdmFyIHBhZGRpbmcgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IDA7XG4gICAgYmIueDEgLT0gcGFkZGluZztcbiAgICBiYi54MiArPSBwYWRkaW5nO1xuICAgIGJiLnkxIC09IHBhZGRpbmc7XG4gICAgYmIueTIgKz0gcGFkZGluZztcbiAgICBiYi53ID0gYmIueDIgLSBiYi54MTtcbiAgICBiYi5oID0gYmIueTIgLSBiYi55MTtcbiAgICByZXR1cm4gYmI7XG4gIH07XG4gIHZhciBleHBhbmRCb3VuZGluZ0JveFNpZGVzID0gZnVuY3Rpb24gZXhwYW5kQm91bmRpbmdCb3hTaWRlcyhiYikge1xuICAgIHZhciBwYWRkaW5nID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiBbMF07XG4gICAgdmFyIHRvcCwgcmlnaHQsIGJvdHRvbSwgbGVmdDtcblxuICAgIGlmIChwYWRkaW5nLmxlbmd0aCA9PT0gMSkge1xuICAgICAgdG9wID0gcmlnaHQgPSBib3R0b20gPSBsZWZ0ID0gcGFkZGluZ1swXTtcbiAgICB9IGVsc2UgaWYgKHBhZGRpbmcubGVuZ3RoID09PSAyKSB7XG4gICAgICB0b3AgPSBib3R0b20gPSBwYWRkaW5nWzBdO1xuICAgICAgbGVmdCA9IHJpZ2h0ID0gcGFkZGluZ1sxXTtcbiAgICB9IGVsc2UgaWYgKHBhZGRpbmcubGVuZ3RoID09PSA0KSB7XG4gICAgICB2YXIgX3BhZGRpbmcgPSBfc2xpY2VkVG9BcnJheShwYWRkaW5nLCA0KTtcblxuICAgICAgdG9wID0gX3BhZGRpbmdbMF07XG4gICAgICByaWdodCA9IF9wYWRkaW5nWzFdO1xuICAgICAgYm90dG9tID0gX3BhZGRpbmdbMl07XG4gICAgICBsZWZ0ID0gX3BhZGRpbmdbM107XG4gICAgfVxuXG4gICAgYmIueDEgLT0gbGVmdDtcbiAgICBiYi54MiArPSByaWdodDtcbiAgICBiYi55MSAtPSB0b3A7XG4gICAgYmIueTIgKz0gYm90dG9tO1xuICAgIGJiLncgPSBiYi54MiAtIGJiLngxO1xuICAgIGJiLmggPSBiYi55MiAtIGJiLnkxO1xuICAgIHJldHVybiBiYjtcbiAgfTtcblxuICB2YXIgYXNzaWduQm91bmRpbmdCb3ggPSBmdW5jdGlvbiBhc3NpZ25Cb3VuZGluZ0JveChiYjEsIGJiMikge1xuICAgIGJiMS54MSA9IGJiMi54MTtcbiAgICBiYjEueTEgPSBiYjIueTE7XG4gICAgYmIxLngyID0gYmIyLngyO1xuICAgIGJiMS55MiA9IGJiMi55MjtcbiAgICBiYjEudyA9IGJiMS54MiAtIGJiMS54MTtcbiAgICBiYjEuaCA9IGJiMS55MiAtIGJiMS55MTtcbiAgfTtcbiAgdmFyIGJvdW5kaW5nQm94ZXNJbnRlcnNlY3QgPSBmdW5jdGlvbiBib3VuZGluZ0JveGVzSW50ZXJzZWN0KGJiMSwgYmIyKSB7XG4gICAgLy8gY2FzZTogb25lIGJiIHRvIHJpZ2h0IG9mIG90aGVyXG4gICAgaWYgKGJiMS54MSA+IGJiMi54Mikge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChiYjIueDEgPiBiYjEueDIpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IC8vIGNhc2U6IG9uZSBiYiB0byBsZWZ0IG9mIG90aGVyXG5cblxuICAgIGlmIChiYjEueDIgPCBiYjIueDEpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoYmIyLngyIDwgYmIxLngxKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSAvLyBjYXNlOiBvbmUgYmIgYWJvdmUgb3RoZXJcblxuXG4gICAgaWYgKGJiMS55MiA8IGJiMi55MSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChiYjIueTIgPCBiYjEueTEpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IC8vIGNhc2U6IG9uZSBiYiBiZWxvdyBvdGhlclxuXG5cbiAgICBpZiAoYmIxLnkxID4gYmIyLnkyKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKGJiMi55MSA+IGJiMS55Mikge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gLy8gb3RoZXJ3aXNlLCBtdXN0IGhhdmUgc29tZSBvdmVybGFwXG5cblxuICAgIHJldHVybiB0cnVlO1xuICB9O1xuICB2YXIgaW5Cb3VuZGluZ0JveCA9IGZ1bmN0aW9uIGluQm91bmRpbmdCb3goYmIsIHgsIHkpIHtcbiAgICByZXR1cm4gYmIueDEgPD0geCAmJiB4IDw9IGJiLngyICYmIGJiLnkxIDw9IHkgJiYgeSA8PSBiYi55MjtcbiAgfTtcbiAgdmFyIHBvaW50SW5Cb3VuZGluZ0JveCA9IGZ1bmN0aW9uIHBvaW50SW5Cb3VuZGluZ0JveChiYiwgcHQpIHtcbiAgICByZXR1cm4gaW5Cb3VuZGluZ0JveChiYiwgcHQueCwgcHQueSk7XG4gIH07XG4gIHZhciBib3VuZGluZ0JveEluQm91bmRpbmdCb3ggPSBmdW5jdGlvbiBib3VuZGluZ0JveEluQm91bmRpbmdCb3goYmIxLCBiYjIpIHtcbiAgICByZXR1cm4gaW5Cb3VuZGluZ0JveChiYjEsIGJiMi54MSwgYmIyLnkxKSAmJiBpbkJvdW5kaW5nQm94KGJiMSwgYmIyLngyLCBiYjIueTIpO1xuICB9O1xuICB2YXIgcm91bmRSZWN0YW5nbGVJbnRlcnNlY3RMaW5lID0gZnVuY3Rpb24gcm91bmRSZWN0YW5nbGVJbnRlcnNlY3RMaW5lKHgsIHksIG5vZGVYLCBub2RlWSwgd2lkdGgsIGhlaWdodCwgcGFkZGluZykge1xuICAgIHZhciBjb3JuZXJSYWRpdXMgPSBnZXRSb3VuZFJlY3RhbmdsZVJhZGl1cyh3aWR0aCwgaGVpZ2h0KTtcbiAgICB2YXIgaGFsZldpZHRoID0gd2lkdGggLyAyO1xuICAgIHZhciBoYWxmSGVpZ2h0ID0gaGVpZ2h0IC8gMjsgLy8gQ2hlY2sgaW50ZXJzZWN0aW9ucyB3aXRoIHN0cmFpZ2h0IGxpbmUgc2VnbWVudHNcblxuICAgIHZhciBzdHJhaWdodExpbmVJbnRlcnNlY3Rpb25zOyAvLyBUb3Agc2VnbWVudCwgbGVmdCB0byByaWdodFxuXG4gICAge1xuICAgICAgdmFyIHRvcFN0YXJ0WCA9IG5vZGVYIC0gaGFsZldpZHRoICsgY29ybmVyUmFkaXVzIC0gcGFkZGluZztcbiAgICAgIHZhciB0b3BTdGFydFkgPSBub2RlWSAtIGhhbGZIZWlnaHQgLSBwYWRkaW5nO1xuICAgICAgdmFyIHRvcEVuZFggPSBub2RlWCArIGhhbGZXaWR0aCAtIGNvcm5lclJhZGl1cyArIHBhZGRpbmc7XG4gICAgICB2YXIgdG9wRW5kWSA9IHRvcFN0YXJ0WTtcbiAgICAgIHN0cmFpZ2h0TGluZUludGVyc2VjdGlvbnMgPSBmaW5pdGVMaW5lc0ludGVyc2VjdCh4LCB5LCBub2RlWCwgbm9kZVksIHRvcFN0YXJ0WCwgdG9wU3RhcnRZLCB0b3BFbmRYLCB0b3BFbmRZLCBmYWxzZSk7XG5cbiAgICAgIGlmIChzdHJhaWdodExpbmVJbnRlcnNlY3Rpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIHN0cmFpZ2h0TGluZUludGVyc2VjdGlvbnM7XG4gICAgICB9XG4gICAgfSAvLyBSaWdodCBzZWdtZW50LCB0b3AgdG8gYm90dG9tXG5cbiAgICB7XG4gICAgICB2YXIgcmlnaHRTdGFydFggPSBub2RlWCArIGhhbGZXaWR0aCArIHBhZGRpbmc7XG4gICAgICB2YXIgcmlnaHRTdGFydFkgPSBub2RlWSAtIGhhbGZIZWlnaHQgKyBjb3JuZXJSYWRpdXMgLSBwYWRkaW5nO1xuICAgICAgdmFyIHJpZ2h0RW5kWCA9IHJpZ2h0U3RhcnRYO1xuICAgICAgdmFyIHJpZ2h0RW5kWSA9IG5vZGVZICsgaGFsZkhlaWdodCAtIGNvcm5lclJhZGl1cyArIHBhZGRpbmc7XG4gICAgICBzdHJhaWdodExpbmVJbnRlcnNlY3Rpb25zID0gZmluaXRlTGluZXNJbnRlcnNlY3QoeCwgeSwgbm9kZVgsIG5vZGVZLCByaWdodFN0YXJ0WCwgcmlnaHRTdGFydFksIHJpZ2h0RW5kWCwgcmlnaHRFbmRZLCBmYWxzZSk7XG5cbiAgICAgIGlmIChzdHJhaWdodExpbmVJbnRlcnNlY3Rpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIHN0cmFpZ2h0TGluZUludGVyc2VjdGlvbnM7XG4gICAgICB9XG4gICAgfSAvLyBCb3R0b20gc2VnbWVudCwgbGVmdCB0byByaWdodFxuXG4gICAge1xuICAgICAgdmFyIGJvdHRvbVN0YXJ0WCA9IG5vZGVYIC0gaGFsZldpZHRoICsgY29ybmVyUmFkaXVzIC0gcGFkZGluZztcbiAgICAgIHZhciBib3R0b21TdGFydFkgPSBub2RlWSArIGhhbGZIZWlnaHQgKyBwYWRkaW5nO1xuICAgICAgdmFyIGJvdHRvbUVuZFggPSBub2RlWCArIGhhbGZXaWR0aCAtIGNvcm5lclJhZGl1cyArIHBhZGRpbmc7XG4gICAgICB2YXIgYm90dG9tRW5kWSA9IGJvdHRvbVN0YXJ0WTtcbiAgICAgIHN0cmFpZ2h0TGluZUludGVyc2VjdGlvbnMgPSBmaW5pdGVMaW5lc0ludGVyc2VjdCh4LCB5LCBub2RlWCwgbm9kZVksIGJvdHRvbVN0YXJ0WCwgYm90dG9tU3RhcnRZLCBib3R0b21FbmRYLCBib3R0b21FbmRZLCBmYWxzZSk7XG5cbiAgICAgIGlmIChzdHJhaWdodExpbmVJbnRlcnNlY3Rpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIHN0cmFpZ2h0TGluZUludGVyc2VjdGlvbnM7XG4gICAgICB9XG4gICAgfSAvLyBMZWZ0IHNlZ21lbnQsIHRvcCB0byBib3R0b21cblxuICAgIHtcbiAgICAgIHZhciBsZWZ0U3RhcnRYID0gbm9kZVggLSBoYWxmV2lkdGggLSBwYWRkaW5nO1xuICAgICAgdmFyIGxlZnRTdGFydFkgPSBub2RlWSAtIGhhbGZIZWlnaHQgKyBjb3JuZXJSYWRpdXMgLSBwYWRkaW5nO1xuICAgICAgdmFyIGxlZnRFbmRYID0gbGVmdFN0YXJ0WDtcbiAgICAgIHZhciBsZWZ0RW5kWSA9IG5vZGVZICsgaGFsZkhlaWdodCAtIGNvcm5lclJhZGl1cyArIHBhZGRpbmc7XG4gICAgICBzdHJhaWdodExpbmVJbnRlcnNlY3Rpb25zID0gZmluaXRlTGluZXNJbnRlcnNlY3QoeCwgeSwgbm9kZVgsIG5vZGVZLCBsZWZ0U3RhcnRYLCBsZWZ0U3RhcnRZLCBsZWZ0RW5kWCwgbGVmdEVuZFksIGZhbHNlKTtcblxuICAgICAgaWYgKHN0cmFpZ2h0TGluZUludGVyc2VjdGlvbnMubGVuZ3RoID4gMCkge1xuICAgICAgICByZXR1cm4gc3RyYWlnaHRMaW5lSW50ZXJzZWN0aW9ucztcbiAgICAgIH1cbiAgICB9IC8vIENoZWNrIGludGVyc2VjdGlvbnMgd2l0aCBhcmMgc2VnbWVudHNcblxuICAgIHZhciBhcmNJbnRlcnNlY3Rpb25zOyAvLyBUb3AgTGVmdFxuXG4gICAge1xuICAgICAgdmFyIHRvcExlZnRDZW50ZXJYID0gbm9kZVggLSBoYWxmV2lkdGggKyBjb3JuZXJSYWRpdXM7XG4gICAgICB2YXIgdG9wTGVmdENlbnRlclkgPSBub2RlWSAtIGhhbGZIZWlnaHQgKyBjb3JuZXJSYWRpdXM7XG4gICAgICBhcmNJbnRlcnNlY3Rpb25zID0gaW50ZXJzZWN0TGluZUNpcmNsZSh4LCB5LCBub2RlWCwgbm9kZVksIHRvcExlZnRDZW50ZXJYLCB0b3BMZWZ0Q2VudGVyWSwgY29ybmVyUmFkaXVzICsgcGFkZGluZyk7IC8vIEVuc3VyZSB0aGUgaW50ZXJzZWN0aW9uIGlzIG9uIHRoZSBkZXNpcmVkIHF1YXJ0ZXIgb2YgdGhlIGNpcmNsZVxuXG4gICAgICBpZiAoYXJjSW50ZXJzZWN0aW9ucy5sZW5ndGggPiAwICYmIGFyY0ludGVyc2VjdGlvbnNbMF0gPD0gdG9wTGVmdENlbnRlclggJiYgYXJjSW50ZXJzZWN0aW9uc1sxXSA8PSB0b3BMZWZ0Q2VudGVyWSkge1xuICAgICAgICByZXR1cm4gW2FyY0ludGVyc2VjdGlvbnNbMF0sIGFyY0ludGVyc2VjdGlvbnNbMV1dO1xuICAgICAgfVxuICAgIH0gLy8gVG9wIFJpZ2h0XG5cbiAgICB7XG4gICAgICB2YXIgdG9wUmlnaHRDZW50ZXJYID0gbm9kZVggKyBoYWxmV2lkdGggLSBjb3JuZXJSYWRpdXM7XG4gICAgICB2YXIgdG9wUmlnaHRDZW50ZXJZID0gbm9kZVkgLSBoYWxmSGVpZ2h0ICsgY29ybmVyUmFkaXVzO1xuICAgICAgYXJjSW50ZXJzZWN0aW9ucyA9IGludGVyc2VjdExpbmVDaXJjbGUoeCwgeSwgbm9kZVgsIG5vZGVZLCB0b3BSaWdodENlbnRlclgsIHRvcFJpZ2h0Q2VudGVyWSwgY29ybmVyUmFkaXVzICsgcGFkZGluZyk7IC8vIEVuc3VyZSB0aGUgaW50ZXJzZWN0aW9uIGlzIG9uIHRoZSBkZXNpcmVkIHF1YXJ0ZXIgb2YgdGhlIGNpcmNsZVxuXG4gICAgICBpZiAoYXJjSW50ZXJzZWN0aW9ucy5sZW5ndGggPiAwICYmIGFyY0ludGVyc2VjdGlvbnNbMF0gPj0gdG9wUmlnaHRDZW50ZXJYICYmIGFyY0ludGVyc2VjdGlvbnNbMV0gPD0gdG9wUmlnaHRDZW50ZXJZKSB7XG4gICAgICAgIHJldHVybiBbYXJjSW50ZXJzZWN0aW9uc1swXSwgYXJjSW50ZXJzZWN0aW9uc1sxXV07XG4gICAgICB9XG4gICAgfSAvLyBCb3R0b20gUmlnaHRcblxuICAgIHtcbiAgICAgIHZhciBib3R0b21SaWdodENlbnRlclggPSBub2RlWCArIGhhbGZXaWR0aCAtIGNvcm5lclJhZGl1cztcbiAgICAgIHZhciBib3R0b21SaWdodENlbnRlclkgPSBub2RlWSArIGhhbGZIZWlnaHQgLSBjb3JuZXJSYWRpdXM7XG4gICAgICBhcmNJbnRlcnNlY3Rpb25zID0gaW50ZXJzZWN0TGluZUNpcmNsZSh4LCB5LCBub2RlWCwgbm9kZVksIGJvdHRvbVJpZ2h0Q2VudGVyWCwgYm90dG9tUmlnaHRDZW50ZXJZLCBjb3JuZXJSYWRpdXMgKyBwYWRkaW5nKTsgLy8gRW5zdXJlIHRoZSBpbnRlcnNlY3Rpb24gaXMgb24gdGhlIGRlc2lyZWQgcXVhcnRlciBvZiB0aGUgY2lyY2xlXG5cbiAgICAgIGlmIChhcmNJbnRlcnNlY3Rpb25zLmxlbmd0aCA+IDAgJiYgYXJjSW50ZXJzZWN0aW9uc1swXSA+PSBib3R0b21SaWdodENlbnRlclggJiYgYXJjSW50ZXJzZWN0aW9uc1sxXSA+PSBib3R0b21SaWdodENlbnRlclkpIHtcbiAgICAgICAgcmV0dXJuIFthcmNJbnRlcnNlY3Rpb25zWzBdLCBhcmNJbnRlcnNlY3Rpb25zWzFdXTtcbiAgICAgIH1cbiAgICB9IC8vIEJvdHRvbSBMZWZ0XG5cbiAgICB7XG4gICAgICB2YXIgYm90dG9tTGVmdENlbnRlclggPSBub2RlWCAtIGhhbGZXaWR0aCArIGNvcm5lclJhZGl1cztcbiAgICAgIHZhciBib3R0b21MZWZ0Q2VudGVyWSA9IG5vZGVZICsgaGFsZkhlaWdodCAtIGNvcm5lclJhZGl1cztcbiAgICAgIGFyY0ludGVyc2VjdGlvbnMgPSBpbnRlcnNlY3RMaW5lQ2lyY2xlKHgsIHksIG5vZGVYLCBub2RlWSwgYm90dG9tTGVmdENlbnRlclgsIGJvdHRvbUxlZnRDZW50ZXJZLCBjb3JuZXJSYWRpdXMgKyBwYWRkaW5nKTsgLy8gRW5zdXJlIHRoZSBpbnRlcnNlY3Rpb24gaXMgb24gdGhlIGRlc2lyZWQgcXVhcnRlciBvZiB0aGUgY2lyY2xlXG5cbiAgICAgIGlmIChhcmNJbnRlcnNlY3Rpb25zLmxlbmd0aCA+IDAgJiYgYXJjSW50ZXJzZWN0aW9uc1swXSA8PSBib3R0b21MZWZ0Q2VudGVyWCAmJiBhcmNJbnRlcnNlY3Rpb25zWzFdID49IGJvdHRvbUxlZnRDZW50ZXJZKSB7XG4gICAgICAgIHJldHVybiBbYXJjSW50ZXJzZWN0aW9uc1swXSwgYXJjSW50ZXJzZWN0aW9uc1sxXV07XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBbXTsgLy8gaWYgbm90aGluZ1xuICB9O1xuICB2YXIgaW5MaW5lVmljaW5pdHkgPSBmdW5jdGlvbiBpbkxpbmVWaWNpbml0eSh4LCB5LCBseDEsIGx5MSwgbHgyLCBseTIsIHRvbGVyYW5jZSkge1xuICAgIHZhciB0ID0gdG9sZXJhbmNlO1xuICAgIHZhciB4MSA9IE1hdGgubWluKGx4MSwgbHgyKTtcbiAgICB2YXIgeDIgPSBNYXRoLm1heChseDEsIGx4Mik7XG4gICAgdmFyIHkxID0gTWF0aC5taW4obHkxLCBseTIpO1xuICAgIHZhciB5MiA9IE1hdGgubWF4KGx5MSwgbHkyKTtcbiAgICByZXR1cm4geDEgLSB0IDw9IHggJiYgeCA8PSB4MiArIHQgJiYgeTEgLSB0IDw9IHkgJiYgeSA8PSB5MiArIHQ7XG4gIH07XG4gIHZhciBpbkJlemllclZpY2luaXR5ID0gZnVuY3Rpb24gaW5CZXppZXJWaWNpbml0eSh4LCB5LCB4MSwgeTEsIHgyLCB5MiwgeDMsIHkzLCB0b2xlcmFuY2UpIHtcbiAgICB2YXIgYmIgPSB7XG4gICAgICB4MTogTWF0aC5taW4oeDEsIHgzLCB4MikgLSB0b2xlcmFuY2UsXG4gICAgICB4MjogTWF0aC5tYXgoeDEsIHgzLCB4MikgKyB0b2xlcmFuY2UsXG4gICAgICB5MTogTWF0aC5taW4oeTEsIHkzLCB5MikgLSB0b2xlcmFuY2UsXG4gICAgICB5MjogTWF0aC5tYXgoeTEsIHkzLCB5MikgKyB0b2xlcmFuY2VcbiAgICB9OyAvLyBpZiBvdXRzaWRlIHRoZSByb3VnaCBib3VuZGluZyBib3ggZm9yIHRoZSBiZXppZXIsIHRoZW4gaXQgY2FuJ3QgYmUgYSBoaXRcblxuICAgIGlmICh4IDwgYmIueDEgfHwgeCA+IGJiLngyIHx8IHkgPCBiYi55MSB8fCB5ID4gYmIueTIpIHtcbiAgICAgIC8vIGNvbnNvbGUubG9nKCdiZXppZXIgb3V0IG9mIHJvdWdoIGJiJylcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gY29uc29sZS5sb2coJ2RvIG1vcmUgZXhwZW5zaXZlIGNoZWNrJyk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH07XG4gIHZhciBzb2x2ZVF1YWRyYXRpYyA9IGZ1bmN0aW9uIHNvbHZlUXVhZHJhdGljKGEsIGIsIGMsIHZhbCkge1xuICAgIGMgLT0gdmFsO1xuICAgIHZhciByID0gYiAqIGIgLSA0ICogYSAqIGM7XG5cbiAgICBpZiAociA8IDApIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICB2YXIgc3FydFIgPSBNYXRoLnNxcnQocik7XG4gICAgdmFyIGRlbm9tID0gMiAqIGE7XG4gICAgdmFyIHJvb3QxID0gKC1iICsgc3FydFIpIC8gZGVub207XG4gICAgdmFyIHJvb3QyID0gKC1iIC0gc3FydFIpIC8gZGVub207XG4gICAgcmV0dXJuIFtyb290MSwgcm9vdDJdO1xuICB9O1xuICB2YXIgc29sdmVDdWJpYyA9IGZ1bmN0aW9uIHNvbHZlQ3ViaWMoYSwgYiwgYywgZCwgcmVzdWx0KSB7XG4gICAgLy8gU29sdmVzIGEgY3ViaWMgZnVuY3Rpb24sIHJldHVybnMgcm9vdCBpbiBmb3JtIFtyMSwgaTEsIHIyLCBpMiwgcjMsIGkzXSwgd2hlcmVcbiAgICAvLyByIGlzIHRoZSByZWFsIGNvbXBvbmVudCwgaSBpcyB0aGUgaW1hZ2luYXJ5IGNvbXBvbmVudFxuICAgIC8vIEFuIGltcGxlbWVudGF0aW9uIG9mIHRoZSBDYXJkYW5vIG1ldGhvZCBmcm9tIHRoZSB5ZWFyIDE1NDVcbiAgICAvLyBodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0N1YmljX2Z1bmN0aW9uI1RoZV9uYXR1cmVfb2ZfdGhlX3Jvb3RzXG4gICAgdmFyIGVwc2lsb24gPSAwLjAwMDAxOyAvLyBhdm9pZCBkaXZpc2lvbiBieSB6ZXJvIHdoaWxlIGtlZXBpbmcgdGhlIG92ZXJhbGwgZXhwcmVzc2lvbiBjbG9zZSBpbiB2YWx1ZVxuXG4gICAgaWYgKGEgPT09IDApIHtcbiAgICAgIGEgPSBlcHNpbG9uO1xuICAgIH1cblxuICAgIGIgLz0gYTtcbiAgICBjIC89IGE7XG4gICAgZCAvPSBhO1xuICAgIHZhciBkaXNjcmltaW5hbnQsIHEsIHIsIGR1bTEsIHMsIHQsIHRlcm0xLCByMTM7XG4gICAgcSA9ICgzLjAgKiBjIC0gYiAqIGIpIC8gOS4wO1xuICAgIHIgPSAtKDI3LjAgKiBkKSArIGIgKiAoOS4wICogYyAtIDIuMCAqIChiICogYikpO1xuICAgIHIgLz0gNTQuMDtcbiAgICBkaXNjcmltaW5hbnQgPSBxICogcSAqIHEgKyByICogcjtcbiAgICByZXN1bHRbMV0gPSAwO1xuICAgIHRlcm0xID0gYiAvIDMuMDtcblxuICAgIGlmIChkaXNjcmltaW5hbnQgPiAwKSB7XG4gICAgICBzID0gciArIE1hdGguc3FydChkaXNjcmltaW5hbnQpO1xuICAgICAgcyA9IHMgPCAwID8gLU1hdGgucG93KC1zLCAxLjAgLyAzLjApIDogTWF0aC5wb3cocywgMS4wIC8gMy4wKTtcbiAgICAgIHQgPSByIC0gTWF0aC5zcXJ0KGRpc2NyaW1pbmFudCk7XG4gICAgICB0ID0gdCA8IDAgPyAtTWF0aC5wb3coLXQsIDEuMCAvIDMuMCkgOiBNYXRoLnBvdyh0LCAxLjAgLyAzLjApO1xuICAgICAgcmVzdWx0WzBdID0gLXRlcm0xICsgcyArIHQ7XG4gICAgICB0ZXJtMSArPSAocyArIHQpIC8gMi4wO1xuICAgICAgcmVzdWx0WzRdID0gcmVzdWx0WzJdID0gLXRlcm0xO1xuICAgICAgdGVybTEgPSBNYXRoLnNxcnQoMy4wKSAqICgtdCArIHMpIC8gMjtcbiAgICAgIHJlc3VsdFszXSA9IHRlcm0xO1xuICAgICAgcmVzdWx0WzVdID0gLXRlcm0xO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHJlc3VsdFs1XSA9IHJlc3VsdFszXSA9IDA7XG5cbiAgICBpZiAoZGlzY3JpbWluYW50ID09PSAwKSB7XG4gICAgICByMTMgPSByIDwgMCA/IC1NYXRoLnBvdygtciwgMS4wIC8gMy4wKSA6IE1hdGgucG93KHIsIDEuMCAvIDMuMCk7XG4gICAgICByZXN1bHRbMF0gPSAtdGVybTEgKyAyLjAgKiByMTM7XG4gICAgICByZXN1bHRbNF0gPSByZXN1bHRbMl0gPSAtKHIxMyArIHRlcm0xKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBxID0gLXE7XG4gICAgZHVtMSA9IHEgKiBxICogcTtcbiAgICBkdW0xID0gTWF0aC5hY29zKHIgLyBNYXRoLnNxcnQoZHVtMSkpO1xuICAgIHIxMyA9IDIuMCAqIE1hdGguc3FydChxKTtcbiAgICByZXN1bHRbMF0gPSAtdGVybTEgKyByMTMgKiBNYXRoLmNvcyhkdW0xIC8gMy4wKTtcbiAgICByZXN1bHRbMl0gPSAtdGVybTEgKyByMTMgKiBNYXRoLmNvcygoZHVtMSArIDIuMCAqIE1hdGguUEkpIC8gMy4wKTtcbiAgICByZXN1bHRbNF0gPSAtdGVybTEgKyByMTMgKiBNYXRoLmNvcygoZHVtMSArIDQuMCAqIE1hdGguUEkpIC8gMy4wKTtcbiAgICByZXR1cm47XG4gIH07XG4gIHZhciBzcWRpc3RUb1F1YWRyYXRpY0JlemllciA9IGZ1bmN0aW9uIHNxZGlzdFRvUXVhZHJhdGljQmV6aWVyKHgsIHksIHgxLCB5MSwgeDIsIHkyLCB4MywgeTMpIHtcbiAgICAvLyBGaW5kIG1pbmltdW0gZGlzdGFuY2UgYnkgdXNpbmcgdGhlIG1pbmltdW0gb2YgdGhlIGRpc3RhbmNlXG4gICAgLy8gZnVuY3Rpb24gYmV0d2VlbiB0aGUgZ2l2ZW4gcG9pbnQgYW5kIHRoZSBjdXJ2ZVxuICAgIC8vIFRoaXMgZ2l2ZXMgdGhlIGNvZWZmaWNpZW50cyBvZiB0aGUgcmVzdWx0aW5nIGN1YmljIGVxdWF0aW9uXG4gICAgLy8gd2hvc2Ugcm9vdHMgdGVsbCB1cyB3aGVyZSBhIHBvc3NpYmxlIG1pbmltdW0gaXNcbiAgICAvLyAoQ29lZmZpY2llbnRzIGFyZSBkaXZpZGVkIGJ5IDQpXG4gICAgdmFyIGEgPSAxLjAgKiB4MSAqIHgxIC0gNCAqIHgxICogeDIgKyAyICogeDEgKiB4MyArIDQgKiB4MiAqIHgyIC0gNCAqIHgyICogeDMgKyB4MyAqIHgzICsgeTEgKiB5MSAtIDQgKiB5MSAqIHkyICsgMiAqIHkxICogeTMgKyA0ICogeTIgKiB5MiAtIDQgKiB5MiAqIHkzICsgeTMgKiB5MztcbiAgICB2YXIgYiA9IDEuMCAqIDkgKiB4MSAqIHgyIC0gMyAqIHgxICogeDEgLSAzICogeDEgKiB4MyAtIDYgKiB4MiAqIHgyICsgMyAqIHgyICogeDMgKyA5ICogeTEgKiB5MiAtIDMgKiB5MSAqIHkxIC0gMyAqIHkxICogeTMgLSA2ICogeTIgKiB5MiArIDMgKiB5MiAqIHkzO1xuICAgIHZhciBjID0gMS4wICogMyAqIHgxICogeDEgLSA2ICogeDEgKiB4MiArIHgxICogeDMgLSB4MSAqIHggKyAyICogeDIgKiB4MiArIDIgKiB4MiAqIHggLSB4MyAqIHggKyAzICogeTEgKiB5MSAtIDYgKiB5MSAqIHkyICsgeTEgKiB5MyAtIHkxICogeSArIDIgKiB5MiAqIHkyICsgMiAqIHkyICogeSAtIHkzICogeTtcbiAgICB2YXIgZCA9IDEuMCAqIHgxICogeDIgLSB4MSAqIHgxICsgeDEgKiB4IC0geDIgKiB4ICsgeTEgKiB5MiAtIHkxICogeTEgKyB5MSAqIHkgLSB5MiAqIHk7IC8vIGRlYnVnKFwiY29lZmZpY2llbnRzOiBcIiArIGEgLyBhICsgXCIsIFwiICsgYiAvIGEgKyBcIiwgXCIgKyBjIC8gYSArIFwiLCBcIiArIGQgLyBhKTtcblxuICAgIHZhciByb290cyA9IFtdOyAvLyBVc2UgdGhlIGN1YmljIHNvbHZpbmcgYWxnb3JpdGhtXG5cbiAgICBzb2x2ZUN1YmljKGEsIGIsIGMsIGQsIHJvb3RzKTtcbiAgICB2YXIgemVyb1RocmVzaG9sZCA9IDAuMDAwMDAwMTtcbiAgICB2YXIgcGFyYW1zID0gW107XG5cbiAgICBmb3IgKHZhciBpbmRleCA9IDA7IGluZGV4IDwgNjsgaW5kZXggKz0gMikge1xuICAgICAgaWYgKE1hdGguYWJzKHJvb3RzW2luZGV4ICsgMV0pIDwgemVyb1RocmVzaG9sZCAmJiByb290c1tpbmRleF0gPj0gMCAmJiByb290c1tpbmRleF0gPD0gMS4wKSB7XG4gICAgICAgIHBhcmFtcy5wdXNoKHJvb3RzW2luZGV4XSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcGFyYW1zLnB1c2goMS4wKTtcbiAgICBwYXJhbXMucHVzaCgwLjApO1xuICAgIHZhciBtaW5EaXN0YW5jZVNxdWFyZWQgPSAtMTtcbiAgICB2YXIgY3VyWCwgY3VyWSwgZGlzdFNxdWFyZWQ7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBhcmFtcy5sZW5ndGg7IGkrKykge1xuICAgICAgY3VyWCA9IE1hdGgucG93KDEuMCAtIHBhcmFtc1tpXSwgMi4wKSAqIHgxICsgMi4wICogKDEgLSBwYXJhbXNbaV0pICogcGFyYW1zW2ldICogeDIgKyBwYXJhbXNbaV0gKiBwYXJhbXNbaV0gKiB4MztcbiAgICAgIGN1clkgPSBNYXRoLnBvdygxIC0gcGFyYW1zW2ldLCAyLjApICogeTEgKyAyICogKDEuMCAtIHBhcmFtc1tpXSkgKiBwYXJhbXNbaV0gKiB5MiArIHBhcmFtc1tpXSAqIHBhcmFtc1tpXSAqIHkzO1xuICAgICAgZGlzdFNxdWFyZWQgPSBNYXRoLnBvdyhjdXJYIC0geCwgMikgKyBNYXRoLnBvdyhjdXJZIC0geSwgMik7IC8vIGRlYnVnKCdkaXN0YW5jZSBmb3IgcGFyYW0gJyArIHBhcmFtc1tpXSArIFwiOiBcIiArIE1hdGguc3FydChkaXN0U3F1YXJlZCkpO1xuXG4gICAgICBpZiAobWluRGlzdGFuY2VTcXVhcmVkID49IDApIHtcbiAgICAgICAgaWYgKGRpc3RTcXVhcmVkIDwgbWluRGlzdGFuY2VTcXVhcmVkKSB7XG4gICAgICAgICAgbWluRGlzdGFuY2VTcXVhcmVkID0gZGlzdFNxdWFyZWQ7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG1pbkRpc3RhbmNlU3F1YXJlZCA9IGRpc3RTcXVhcmVkO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBtaW5EaXN0YW5jZVNxdWFyZWQ7XG4gIH07XG4gIHZhciBzcWRpc3RUb0Zpbml0ZUxpbmUgPSBmdW5jdGlvbiBzcWRpc3RUb0Zpbml0ZUxpbmUoeCwgeSwgeDEsIHkxLCB4MiwgeTIpIHtcbiAgICB2YXIgb2Zmc2V0ID0gW3ggLSB4MSwgeSAtIHkxXTtcbiAgICB2YXIgbGluZSA9IFt4MiAtIHgxLCB5MiAtIHkxXTtcbiAgICB2YXIgbGluZVNxID0gbGluZVswXSAqIGxpbmVbMF0gKyBsaW5lWzFdICogbGluZVsxXTtcbiAgICB2YXIgaHlwU3EgPSBvZmZzZXRbMF0gKiBvZmZzZXRbMF0gKyBvZmZzZXRbMV0gKiBvZmZzZXRbMV07XG4gICAgdmFyIGRvdFByb2R1Y3QgPSBvZmZzZXRbMF0gKiBsaW5lWzBdICsgb2Zmc2V0WzFdICogbGluZVsxXTtcbiAgICB2YXIgYWRqU3EgPSBkb3RQcm9kdWN0ICogZG90UHJvZHVjdCAvIGxpbmVTcTtcblxuICAgIGlmIChkb3RQcm9kdWN0IDwgMCkge1xuICAgICAgcmV0dXJuIGh5cFNxO1xuICAgIH1cblxuICAgIGlmIChhZGpTcSA+IGxpbmVTcSkge1xuICAgICAgcmV0dXJuICh4IC0geDIpICogKHggLSB4MikgKyAoeSAtIHkyKSAqICh5IC0geTIpO1xuICAgIH1cblxuICAgIHJldHVybiBoeXBTcSAtIGFkalNxO1xuICB9O1xuICB2YXIgcG9pbnRJbnNpZGVQb2x5Z29uUG9pbnRzID0gZnVuY3Rpb24gcG9pbnRJbnNpZGVQb2x5Z29uUG9pbnRzKHgsIHksIHBvaW50cykge1xuICAgIHZhciB4MSwgeTEsIHgyLCB5MjtcbiAgICB2YXIgeTM7IC8vIEludGVyc2VjdCB3aXRoIHZlcnRpY2FsIGxpbmUgdGhyb3VnaCAoeCwgeSlcblxuICAgIHZhciB1cCA9IDA7IC8vIGxldCBkb3duID0gMDtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aCAvIDI7IGkrKykge1xuICAgICAgeDEgPSBwb2ludHNbaSAqIDJdO1xuICAgICAgeTEgPSBwb2ludHNbaSAqIDIgKyAxXTtcblxuICAgICAgaWYgKGkgKyAxIDwgcG9pbnRzLmxlbmd0aCAvIDIpIHtcbiAgICAgICAgeDIgPSBwb2ludHNbKGkgKyAxKSAqIDJdO1xuICAgICAgICB5MiA9IHBvaW50c1soaSArIDEpICogMiArIDFdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgeDIgPSBwb2ludHNbKGkgKyAxIC0gcG9pbnRzLmxlbmd0aCAvIDIpICogMl07XG4gICAgICAgIHkyID0gcG9pbnRzWyhpICsgMSAtIHBvaW50cy5sZW5ndGggLyAyKSAqIDIgKyAxXTtcbiAgICAgIH1cblxuICAgICAgaWYgKHgxID09IHggJiYgeDIgPT0geCkgOyBlbHNlIGlmICh4MSA+PSB4ICYmIHggPj0geDIgfHwgeDEgPD0geCAmJiB4IDw9IHgyKSB7XG4gICAgICAgIHkzID0gKHggLSB4MSkgLyAoeDIgLSB4MSkgKiAoeTIgLSB5MSkgKyB5MTtcblxuICAgICAgICBpZiAoeTMgPiB5KSB7XG4gICAgICAgICAgdXArKztcbiAgICAgICAgfSAvLyBpZiggeTMgPCB5ICl7XG4gICAgICAgIC8vIGRvd24rKztcbiAgICAgICAgLy8gfVxuXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodXAgJSAyID09PSAwKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfTtcbiAgdmFyIHBvaW50SW5zaWRlUG9seWdvbiA9IGZ1bmN0aW9uIHBvaW50SW5zaWRlUG9seWdvbih4LCB5LCBiYXNlUG9pbnRzLCBjZW50ZXJYLCBjZW50ZXJZLCB3aWR0aCwgaGVpZ2h0LCBkaXJlY3Rpb24sIHBhZGRpbmcpIHtcbiAgICB2YXIgdHJhbnNmb3JtZWRQb2ludHMgPSBuZXcgQXJyYXkoYmFzZVBvaW50cy5sZW5ndGgpOyAvLyBHaXZlcyBuZWdhdGl2ZSBhbmdsZVxuXG4gICAgdmFyIGFuZ2xlO1xuXG4gICAgaWYgKGRpcmVjdGlvblswXSAhPSBudWxsKSB7XG4gICAgICBhbmdsZSA9IE1hdGguYXRhbihkaXJlY3Rpb25bMV0gLyBkaXJlY3Rpb25bMF0pO1xuXG4gICAgICBpZiAoZGlyZWN0aW9uWzBdIDwgMCkge1xuICAgICAgICBhbmdsZSA9IGFuZ2xlICsgTWF0aC5QSSAvIDI7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhbmdsZSA9IC1hbmdsZSAtIE1hdGguUEkgLyAyO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBhbmdsZSA9IGRpcmVjdGlvbjtcbiAgICB9XG5cbiAgICB2YXIgY29zID0gTWF0aC5jb3MoLWFuZ2xlKTtcbiAgICB2YXIgc2luID0gTWF0aC5zaW4oLWFuZ2xlKTsgLy8gICAgY29uc29sZS5sb2coXCJiYXNlOiBcIiArIGJhc2VQb2ludHMpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0cmFuc2Zvcm1lZFBvaW50cy5sZW5ndGggLyAyOyBpKyspIHtcbiAgICAgIHRyYW5zZm9ybWVkUG9pbnRzW2kgKiAyXSA9IHdpZHRoIC8gMiAqIChiYXNlUG9pbnRzW2kgKiAyXSAqIGNvcyAtIGJhc2VQb2ludHNbaSAqIDIgKyAxXSAqIHNpbik7XG4gICAgICB0cmFuc2Zvcm1lZFBvaW50c1tpICogMiArIDFdID0gaGVpZ2h0IC8gMiAqIChiYXNlUG9pbnRzW2kgKiAyICsgMV0gKiBjb3MgKyBiYXNlUG9pbnRzW2kgKiAyXSAqIHNpbik7XG4gICAgICB0cmFuc2Zvcm1lZFBvaW50c1tpICogMl0gKz0gY2VudGVyWDtcbiAgICAgIHRyYW5zZm9ybWVkUG9pbnRzW2kgKiAyICsgMV0gKz0gY2VudGVyWTtcbiAgICB9XG5cbiAgICB2YXIgcG9pbnRzO1xuXG4gICAgaWYgKHBhZGRpbmcgPiAwKSB7XG4gICAgICB2YXIgZXhwYW5kZWRMaW5lU2V0ID0gZXhwYW5kUG9seWdvbih0cmFuc2Zvcm1lZFBvaW50cywgLXBhZGRpbmcpO1xuICAgICAgcG9pbnRzID0gam9pbkxpbmVzKGV4cGFuZGVkTGluZVNldCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHBvaW50cyA9IHRyYW5zZm9ybWVkUG9pbnRzO1xuICAgIH1cblxuICAgIHJldHVybiBwb2ludEluc2lkZVBvbHlnb25Qb2ludHMoeCwgeSwgcG9pbnRzKTtcbiAgfTtcbiAgdmFyIHBvaW50SW5zaWRlUm91bmRQb2x5Z29uID0gZnVuY3Rpb24gcG9pbnRJbnNpZGVSb3VuZFBvbHlnb24oeCwgeSwgYmFzZVBvaW50cywgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCkge1xuICAgIHZhciBjdXRQb2x5Z29uUG9pbnRzID0gbmV3IEFycmF5KGJhc2VQb2ludHMubGVuZ3RoKTtcbiAgICB2YXIgaGFsZlcgPSB3aWR0aCAvIDI7XG4gICAgdmFyIGhhbGZIID0gaGVpZ2h0IC8gMjtcbiAgICB2YXIgY29ybmVyUmFkaXVzID0gZ2V0Um91bmRQb2x5Z29uUmFkaXVzKHdpZHRoLCBoZWlnaHQpO1xuICAgIHZhciBzcXVhcmVkQ29ybmVyUmFkaXVzID0gY29ybmVyUmFkaXVzICogY29ybmVyUmFkaXVzO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBiYXNlUG9pbnRzLmxlbmd0aCAvIDQ7IGkrKykge1xuICAgICAgdmFyIHNvdXJjZVV2ID0gdm9pZCAwLFxuICAgICAgICAgIGRlc3RVdiA9IHZvaWQgMDtcblxuICAgICAgaWYgKGkgPT09IDApIHtcbiAgICAgICAgc291cmNlVXYgPSBiYXNlUG9pbnRzLmxlbmd0aCAtIDI7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzb3VyY2VVdiA9IGkgKiA0IC0gMjtcbiAgICAgIH1cblxuICAgICAgZGVzdFV2ID0gaSAqIDQgKyAyO1xuICAgICAgdmFyIHB4ID0gY2VudGVyWCArIGhhbGZXICogYmFzZVBvaW50c1tpICogNF07XG4gICAgICB2YXIgcHkgPSBjZW50ZXJZICsgaGFsZkggKiBiYXNlUG9pbnRzW2kgKiA0ICsgMV07XG4gICAgICB2YXIgY29zVGhldGEgPSAtYmFzZVBvaW50c1tzb3VyY2VVdl0gKiBiYXNlUG9pbnRzW2Rlc3RVdl0gLSBiYXNlUG9pbnRzW3NvdXJjZVV2ICsgMV0gKiBiYXNlUG9pbnRzW2Rlc3RVdiArIDFdO1xuICAgICAgdmFyIG9mZnNldCA9IGNvcm5lclJhZGl1cyAvIE1hdGgudGFuKE1hdGguYWNvcyhjb3NUaGV0YSkgLyAyKTtcbiAgICAgIHZhciBjcDB4ID0gcHggLSBvZmZzZXQgKiBiYXNlUG9pbnRzW3NvdXJjZVV2XTtcbiAgICAgIHZhciBjcDB5ID0gcHkgLSBvZmZzZXQgKiBiYXNlUG9pbnRzW3NvdXJjZVV2ICsgMV07XG4gICAgICB2YXIgY3AxeCA9IHB4ICsgb2Zmc2V0ICogYmFzZVBvaW50c1tkZXN0VXZdO1xuICAgICAgdmFyIGNwMXkgPSBweSArIG9mZnNldCAqIGJhc2VQb2ludHNbZGVzdFV2ICsgMV07XG4gICAgICBjdXRQb2x5Z29uUG9pbnRzW2kgKiA0XSA9IGNwMHg7XG4gICAgICBjdXRQb2x5Z29uUG9pbnRzW2kgKiA0ICsgMV0gPSBjcDB5O1xuICAgICAgY3V0UG9seWdvblBvaW50c1tpICogNCArIDJdID0gY3AxeDtcbiAgICAgIGN1dFBvbHlnb25Qb2ludHNbaSAqIDQgKyAzXSA9IGNwMXk7XG4gICAgICB2YXIgb3J0aHggPSBiYXNlUG9pbnRzW3NvdXJjZVV2ICsgMV07XG4gICAgICB2YXIgb3J0aHkgPSAtYmFzZVBvaW50c1tzb3VyY2VVdl07XG4gICAgICB2YXIgY29zQWxwaGEgPSBvcnRoeCAqIGJhc2VQb2ludHNbZGVzdFV2XSArIG9ydGh5ICogYmFzZVBvaW50c1tkZXN0VXYgKyAxXTtcblxuICAgICAgaWYgKGNvc0FscGhhIDwgMCkge1xuICAgICAgICBvcnRoeCAqPSAtMTtcbiAgICAgICAgb3J0aHkgKj0gLTE7XG4gICAgICB9XG5cbiAgICAgIHZhciBjeCA9IGNwMHggKyBvcnRoeCAqIGNvcm5lclJhZGl1cztcbiAgICAgIHZhciBjeSA9IGNwMHkgKyBvcnRoeSAqIGNvcm5lclJhZGl1cztcbiAgICAgIHZhciBzcXVhcmVkRGlzdGFuY2UgPSBNYXRoLnBvdyhjeCAtIHgsIDIpICsgTWF0aC5wb3coY3kgLSB5LCAyKTtcblxuICAgICAgaWYgKHNxdWFyZWREaXN0YW5jZSA8PSBzcXVhcmVkQ29ybmVyUmFkaXVzKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBwb2ludEluc2lkZVBvbHlnb25Qb2ludHMoeCwgeSwgY3V0UG9seWdvblBvaW50cyk7XG4gIH07XG4gIHZhciBqb2luTGluZXMgPSBmdW5jdGlvbiBqb2luTGluZXMobGluZVNldCkge1xuICAgIHZhciB2ZXJ0aWNlcyA9IG5ldyBBcnJheShsaW5lU2V0Lmxlbmd0aCAvIDIpO1xuICAgIHZhciBjdXJyZW50TGluZVN0YXJ0WCwgY3VycmVudExpbmVTdGFydFksIGN1cnJlbnRMaW5lRW5kWCwgY3VycmVudExpbmVFbmRZO1xuICAgIHZhciBuZXh0TGluZVN0YXJ0WCwgbmV4dExpbmVTdGFydFksIG5leHRMaW5lRW5kWCwgbmV4dExpbmVFbmRZO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lU2V0Lmxlbmd0aCAvIDQ7IGkrKykge1xuICAgICAgY3VycmVudExpbmVTdGFydFggPSBsaW5lU2V0W2kgKiA0XTtcbiAgICAgIGN1cnJlbnRMaW5lU3RhcnRZID0gbGluZVNldFtpICogNCArIDFdO1xuICAgICAgY3VycmVudExpbmVFbmRYID0gbGluZVNldFtpICogNCArIDJdO1xuICAgICAgY3VycmVudExpbmVFbmRZID0gbGluZVNldFtpICogNCArIDNdO1xuXG4gICAgICBpZiAoaSA8IGxpbmVTZXQubGVuZ3RoIC8gNCAtIDEpIHtcbiAgICAgICAgbmV4dExpbmVTdGFydFggPSBsaW5lU2V0WyhpICsgMSkgKiA0XTtcbiAgICAgICAgbmV4dExpbmVTdGFydFkgPSBsaW5lU2V0WyhpICsgMSkgKiA0ICsgMV07XG4gICAgICAgIG5leHRMaW5lRW5kWCA9IGxpbmVTZXRbKGkgKyAxKSAqIDQgKyAyXTtcbiAgICAgICAgbmV4dExpbmVFbmRZID0gbGluZVNldFsoaSArIDEpICogNCArIDNdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbmV4dExpbmVTdGFydFggPSBsaW5lU2V0WzBdO1xuICAgICAgICBuZXh0TGluZVN0YXJ0WSA9IGxpbmVTZXRbMV07XG4gICAgICAgIG5leHRMaW5lRW5kWCA9IGxpbmVTZXRbMl07XG4gICAgICAgIG5leHRMaW5lRW5kWSA9IGxpbmVTZXRbM107XG4gICAgICB9XG5cbiAgICAgIHZhciBpbnRlcnNlY3Rpb24gPSBmaW5pdGVMaW5lc0ludGVyc2VjdChjdXJyZW50TGluZVN0YXJ0WCwgY3VycmVudExpbmVTdGFydFksIGN1cnJlbnRMaW5lRW5kWCwgY3VycmVudExpbmVFbmRZLCBuZXh0TGluZVN0YXJ0WCwgbmV4dExpbmVTdGFydFksIG5leHRMaW5lRW5kWCwgbmV4dExpbmVFbmRZLCB0cnVlKTtcbiAgICAgIHZlcnRpY2VzW2kgKiAyXSA9IGludGVyc2VjdGlvblswXTtcbiAgICAgIHZlcnRpY2VzW2kgKiAyICsgMV0gPSBpbnRlcnNlY3Rpb25bMV07XG4gICAgfVxuXG4gICAgcmV0dXJuIHZlcnRpY2VzO1xuICB9O1xuICB2YXIgZXhwYW5kUG9seWdvbiA9IGZ1bmN0aW9uIGV4cGFuZFBvbHlnb24ocG9pbnRzLCBwYWQpIHtcbiAgICB2YXIgZXhwYW5kZWRMaW5lU2V0ID0gbmV3IEFycmF5KHBvaW50cy5sZW5ndGggKiAyKTtcbiAgICB2YXIgY3VycmVudFBvaW50WCwgY3VycmVudFBvaW50WSwgbmV4dFBvaW50WCwgbmV4dFBvaW50WTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aCAvIDI7IGkrKykge1xuICAgICAgY3VycmVudFBvaW50WCA9IHBvaW50c1tpICogMl07XG4gICAgICBjdXJyZW50UG9pbnRZID0gcG9pbnRzW2kgKiAyICsgMV07XG5cbiAgICAgIGlmIChpIDwgcG9pbnRzLmxlbmd0aCAvIDIgLSAxKSB7XG4gICAgICAgIG5leHRQb2ludFggPSBwb2ludHNbKGkgKyAxKSAqIDJdO1xuICAgICAgICBuZXh0UG9pbnRZID0gcG9pbnRzWyhpICsgMSkgKiAyICsgMV07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuZXh0UG9pbnRYID0gcG9pbnRzWzBdO1xuICAgICAgICBuZXh0UG9pbnRZID0gcG9pbnRzWzFdO1xuICAgICAgfSAvLyBDdXJyZW50IGxpbmU6IFtjdXJyZW50UG9pbnRYLCBjdXJyZW50UG9pbnRZXSB0byBbbmV4dFBvaW50WCwgbmV4dFBvaW50WV1cbiAgICAgIC8vIEFzc3VtZSBDQ1cgcG9seWdvbiB3aW5kaW5nXG5cblxuICAgICAgdmFyIG9mZnNldFggPSBuZXh0UG9pbnRZIC0gY3VycmVudFBvaW50WTtcbiAgICAgIHZhciBvZmZzZXRZID0gLShuZXh0UG9pbnRYIC0gY3VycmVudFBvaW50WCk7IC8vIE5vcm1hbGl6ZVxuXG4gICAgICB2YXIgb2Zmc2V0TGVuZ3RoID0gTWF0aC5zcXJ0KG9mZnNldFggKiBvZmZzZXRYICsgb2Zmc2V0WSAqIG9mZnNldFkpO1xuICAgICAgdmFyIG5vcm1hbGl6ZWRPZmZzZXRYID0gb2Zmc2V0WCAvIG9mZnNldExlbmd0aDtcbiAgICAgIHZhciBub3JtYWxpemVkT2Zmc2V0WSA9IG9mZnNldFkgLyBvZmZzZXRMZW5ndGg7XG4gICAgICBleHBhbmRlZExpbmVTZXRbaSAqIDRdID0gY3VycmVudFBvaW50WCArIG5vcm1hbGl6ZWRPZmZzZXRYICogcGFkO1xuICAgICAgZXhwYW5kZWRMaW5lU2V0W2kgKiA0ICsgMV0gPSBjdXJyZW50UG9pbnRZICsgbm9ybWFsaXplZE9mZnNldFkgKiBwYWQ7XG4gICAgICBleHBhbmRlZExpbmVTZXRbaSAqIDQgKyAyXSA9IG5leHRQb2ludFggKyBub3JtYWxpemVkT2Zmc2V0WCAqIHBhZDtcbiAgICAgIGV4cGFuZGVkTGluZVNldFtpICogNCArIDNdID0gbmV4dFBvaW50WSArIG5vcm1hbGl6ZWRPZmZzZXRZICogcGFkO1xuICAgIH1cblxuICAgIHJldHVybiBleHBhbmRlZExpbmVTZXQ7XG4gIH07XG4gIHZhciBpbnRlcnNlY3RMaW5lRWxsaXBzZSA9IGZ1bmN0aW9uIGludGVyc2VjdExpbmVFbGxpcHNlKHgsIHksIGNlbnRlclgsIGNlbnRlclksIGVsbGlwc2VXcmFkaXVzLCBlbGxpcHNlSHJhZGl1cykge1xuICAgIHZhciBkaXNwWCA9IGNlbnRlclggLSB4O1xuICAgIHZhciBkaXNwWSA9IGNlbnRlclkgLSB5O1xuICAgIGRpc3BYIC89IGVsbGlwc2VXcmFkaXVzO1xuICAgIGRpc3BZIC89IGVsbGlwc2VIcmFkaXVzO1xuICAgIHZhciBsZW4gPSBNYXRoLnNxcnQoZGlzcFggKiBkaXNwWCArIGRpc3BZICogZGlzcFkpO1xuICAgIHZhciBuZXdMZW5ndGggPSBsZW4gLSAxO1xuXG4gICAgaWYgKG5ld0xlbmd0aCA8IDApIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICB2YXIgbGVuUHJvcG9ydGlvbiA9IG5ld0xlbmd0aCAvIGxlbjtcbiAgICByZXR1cm4gWyhjZW50ZXJYIC0geCkgKiBsZW5Qcm9wb3J0aW9uICsgeCwgKGNlbnRlclkgLSB5KSAqIGxlblByb3BvcnRpb24gKyB5XTtcbiAgfTtcbiAgdmFyIGNoZWNrSW5FbGxpcHNlID0gZnVuY3Rpb24gY2hlY2tJbkVsbGlwc2UoeCwgeSwgd2lkdGgsIGhlaWdodCwgY2VudGVyWCwgY2VudGVyWSwgcGFkZGluZykge1xuICAgIHggLT0gY2VudGVyWDtcbiAgICB5IC09IGNlbnRlclk7XG4gICAgeCAvPSB3aWR0aCAvIDIgKyBwYWRkaW5nO1xuICAgIHkgLz0gaGVpZ2h0IC8gMiArIHBhZGRpbmc7XG4gICAgcmV0dXJuIHggKiB4ICsgeSAqIHkgPD0gMTtcbiAgfTsgLy8gUmV0dXJucyBpbnRlcnNlY3Rpb25zIG9mIGluY3JlYXNpbmcgZGlzdGFuY2UgZnJvbSBsaW5lJ3Mgc3RhcnQgcG9pbnRcblxuICB2YXIgaW50ZXJzZWN0TGluZUNpcmNsZSA9IGZ1bmN0aW9uIGludGVyc2VjdExpbmVDaXJjbGUoeDEsIHkxLCB4MiwgeTIsIGNlbnRlclgsIGNlbnRlclksIHJhZGl1cykge1xuICAgIC8vIENhbGN1bGF0ZSBkLCBkaXJlY3Rpb24gdmVjdG9yIG9mIGxpbmVcbiAgICB2YXIgZCA9IFt4MiAtIHgxLCB5MiAtIHkxXTsgLy8gRGlyZWN0aW9uIHZlY3RvciBvZiBsaW5lXG5cbiAgICB2YXIgZiA9IFt4MSAtIGNlbnRlclgsIHkxIC0gY2VudGVyWV07XG4gICAgdmFyIGEgPSBkWzBdICogZFswXSArIGRbMV0gKiBkWzFdO1xuICAgIHZhciBiID0gMiAqIChmWzBdICogZFswXSArIGZbMV0gKiBkWzFdKTtcbiAgICB2YXIgYyA9IGZbMF0gKiBmWzBdICsgZlsxXSAqIGZbMV0gLSByYWRpdXMgKiByYWRpdXM7XG4gICAgdmFyIGRpc2NyaW1pbmFudCA9IGIgKiBiIC0gNCAqIGEgKiBjO1xuXG4gICAgaWYgKGRpc2NyaW1pbmFudCA8IDApIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICB2YXIgdDEgPSAoLWIgKyBNYXRoLnNxcnQoZGlzY3JpbWluYW50KSkgLyAoMiAqIGEpO1xuICAgIHZhciB0MiA9ICgtYiAtIE1hdGguc3FydChkaXNjcmltaW5hbnQpKSAvICgyICogYSk7XG4gICAgdmFyIHRNaW4gPSBNYXRoLm1pbih0MSwgdDIpO1xuICAgIHZhciB0TWF4ID0gTWF0aC5tYXgodDEsIHQyKTtcbiAgICB2YXIgaW5SYW5nZVBhcmFtcyA9IFtdO1xuXG4gICAgaWYgKHRNaW4gPj0gMCAmJiB0TWluIDw9IDEpIHtcbiAgICAgIGluUmFuZ2VQYXJhbXMucHVzaCh0TWluKTtcbiAgICB9XG5cbiAgICBpZiAodE1heCA+PSAwICYmIHRNYXggPD0gMSkge1xuICAgICAgaW5SYW5nZVBhcmFtcy5wdXNoKHRNYXgpO1xuICAgIH1cblxuICAgIGlmIChpblJhbmdlUGFyYW1zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIHZhciBuZWFySW50ZXJzZWN0aW9uWCA9IGluUmFuZ2VQYXJhbXNbMF0gKiBkWzBdICsgeDE7XG4gICAgdmFyIG5lYXJJbnRlcnNlY3Rpb25ZID0gaW5SYW5nZVBhcmFtc1swXSAqIGRbMV0gKyB5MTtcblxuICAgIGlmIChpblJhbmdlUGFyYW1zLmxlbmd0aCA+IDEpIHtcbiAgICAgIGlmIChpblJhbmdlUGFyYW1zWzBdID09IGluUmFuZ2VQYXJhbXNbMV0pIHtcbiAgICAgICAgcmV0dXJuIFtuZWFySW50ZXJzZWN0aW9uWCwgbmVhckludGVyc2VjdGlvblldO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIGZhckludGVyc2VjdGlvblggPSBpblJhbmdlUGFyYW1zWzFdICogZFswXSArIHgxO1xuICAgICAgICB2YXIgZmFySW50ZXJzZWN0aW9uWSA9IGluUmFuZ2VQYXJhbXNbMV0gKiBkWzFdICsgeTE7XG4gICAgICAgIHJldHVybiBbbmVhckludGVyc2VjdGlvblgsIG5lYXJJbnRlcnNlY3Rpb25ZLCBmYXJJbnRlcnNlY3Rpb25YLCBmYXJJbnRlcnNlY3Rpb25ZXTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIFtuZWFySW50ZXJzZWN0aW9uWCwgbmVhckludGVyc2VjdGlvblldO1xuICAgIH1cbiAgfTtcbiAgdmFyIG1pZE9mVGhyZWUgPSBmdW5jdGlvbiBtaWRPZlRocmVlKGEsIGIsIGMpIHtcbiAgICBpZiAoYiA8PSBhICYmIGEgPD0gYyB8fCBjIDw9IGEgJiYgYSA8PSBiKSB7XG4gICAgICByZXR1cm4gYTtcbiAgICB9IGVsc2UgaWYgKGEgPD0gYiAmJiBiIDw9IGMgfHwgYyA8PSBiICYmIGIgPD0gYSkge1xuICAgICAgcmV0dXJuIGI7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBjO1xuICAgIH1cbiAgfTsgLy8gKHgxLHkxKT0+KHgyLHkyKSBpbnRlcnNlY3Qgd2l0aCAoeDMseTMpPT4oeDQseTQpXG5cbiAgdmFyIGZpbml0ZUxpbmVzSW50ZXJzZWN0ID0gZnVuY3Rpb24gZmluaXRlTGluZXNJbnRlcnNlY3QoeDEsIHkxLCB4MiwgeTIsIHgzLCB5MywgeDQsIHk0LCBpbmZpbml0ZUxpbmVzKSB7XG4gICAgdmFyIGR4MTMgPSB4MSAtIHgzO1xuICAgIHZhciBkeDIxID0geDIgLSB4MTtcbiAgICB2YXIgZHg0MyA9IHg0IC0geDM7XG4gICAgdmFyIGR5MTMgPSB5MSAtIHkzO1xuICAgIHZhciBkeTIxID0geTIgLSB5MTtcbiAgICB2YXIgZHk0MyA9IHk0IC0geTM7XG4gICAgdmFyIHVhX3QgPSBkeDQzICogZHkxMyAtIGR5NDMgKiBkeDEzO1xuICAgIHZhciB1Yl90ID0gZHgyMSAqIGR5MTMgLSBkeTIxICogZHgxMztcbiAgICB2YXIgdV9iID0gZHk0MyAqIGR4MjEgLSBkeDQzICogZHkyMTtcblxuICAgIGlmICh1X2IgIT09IDApIHtcbiAgICAgIHZhciB1YSA9IHVhX3QgLyB1X2I7XG4gICAgICB2YXIgdWIgPSB1Yl90IC8gdV9iO1xuICAgICAgdmFyIGZscHRUaHJlc2hvbGQgPSAwLjAwMTtcblxuICAgICAgdmFyIF9taW4gPSAwIC0gZmxwdFRocmVzaG9sZDtcblxuICAgICAgdmFyIF9tYXggPSAxICsgZmxwdFRocmVzaG9sZDtcblxuICAgICAgaWYgKF9taW4gPD0gdWEgJiYgdWEgPD0gX21heCAmJiBfbWluIDw9IHViICYmIHViIDw9IF9tYXgpIHtcbiAgICAgICAgcmV0dXJuIFt4MSArIHVhICogZHgyMSwgeTEgKyB1YSAqIGR5MjFdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKCFpbmZpbml0ZUxpbmVzKSB7XG4gICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBbeDEgKyB1YSAqIGR4MjEsIHkxICsgdWEgKiBkeTIxXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAodWFfdCA9PT0gMCB8fCB1Yl90ID09PSAwKSB7XG4gICAgICAgIC8vIFBhcmFsbGVsLCBjb2luY2lkZW50IGxpbmVzLiBDaGVjayBpZiBvdmVybGFwXG4gICAgICAgIC8vIENoZWNrIGVuZHBvaW50IG9mIHNlY29uZCBsaW5lXG4gICAgICAgIGlmIChtaWRPZlRocmVlKHgxLCB4MiwgeDQpID09PSB4NCkge1xuICAgICAgICAgIHJldHVybiBbeDQsIHk0XTtcbiAgICAgICAgfSAvLyBDaGVjayBzdGFydCBwb2ludCBvZiBzZWNvbmQgbGluZVxuXG5cbiAgICAgICAgaWYgKG1pZE9mVGhyZWUoeDEsIHgyLCB4MykgPT09IHgzKSB7XG4gICAgICAgICAgcmV0dXJuIFt4MywgeTNdO1xuICAgICAgICB9IC8vIEVuZHBvaW50IG9mIGZpcnN0IGxpbmVcblxuXG4gICAgICAgIGlmIChtaWRPZlRocmVlKHgzLCB4NCwgeDIpID09PSB4Mikge1xuICAgICAgICAgIHJldHVybiBbeDIsIHkyXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFBhcmFsbGVsLCBub24tY29pbmNpZGVudFxuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG4gICAgfVxuICB9OyAvLyBtYXRoLnBvbHlnb25JbnRlcnNlY3RMaW5lKCB4LCB5LCBiYXNlUG9pbnRzLCBjZW50ZXJYLCBjZW50ZXJZLCB3aWR0aCwgaGVpZ2h0LCBwYWRkaW5nIClcbiAgLy8gaW50ZXJzZWN0IGEgbm9kZSBwb2x5Z29uIChwdHMgdHJhbnNmb3JtZWQpXG4gIC8vXG4gIC8vIG1hdGgucG9seWdvbkludGVyc2VjdExpbmUoIHgsIHksIGJhc2VQb2ludHMsIGNlbnRlclgsIGNlbnRlclkgKVxuICAvLyBpbnRlcnNlY3QgdGhlIHBvaW50cyAobm8gdHJhbnNmb3JtKVxuXG4gIHZhciBwb2x5Z29uSW50ZXJzZWN0TGluZSA9IGZ1bmN0aW9uIHBvbHlnb25JbnRlcnNlY3RMaW5lKHgsIHksIGJhc2VQb2ludHMsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQsIHBhZGRpbmcpIHtcbiAgICB2YXIgaW50ZXJzZWN0aW9ucyA9IFtdO1xuICAgIHZhciBpbnRlcnNlY3Rpb247XG4gICAgdmFyIHRyYW5zZm9ybWVkUG9pbnRzID0gbmV3IEFycmF5KGJhc2VQb2ludHMubGVuZ3RoKTtcbiAgICB2YXIgZG9UcmFuc2Zvcm0gPSB0cnVlO1xuXG4gICAgaWYgKHdpZHRoID09IG51bGwpIHtcbiAgICAgIGRvVHJhbnNmb3JtID0gZmFsc2U7XG4gICAgfVxuXG4gICAgdmFyIHBvaW50cztcblxuICAgIGlmIChkb1RyYW5zZm9ybSkge1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0cmFuc2Zvcm1lZFBvaW50cy5sZW5ndGggLyAyOyBpKyspIHtcbiAgICAgICAgdHJhbnNmb3JtZWRQb2ludHNbaSAqIDJdID0gYmFzZVBvaW50c1tpICogMl0gKiB3aWR0aCArIGNlbnRlclg7XG4gICAgICAgIHRyYW5zZm9ybWVkUG9pbnRzW2kgKiAyICsgMV0gPSBiYXNlUG9pbnRzW2kgKiAyICsgMV0gKiBoZWlnaHQgKyBjZW50ZXJZO1xuICAgICAgfVxuXG4gICAgICBpZiAocGFkZGluZyA+IDApIHtcbiAgICAgICAgdmFyIGV4cGFuZGVkTGluZVNldCA9IGV4cGFuZFBvbHlnb24odHJhbnNmb3JtZWRQb2ludHMsIC1wYWRkaW5nKTtcbiAgICAgICAgcG9pbnRzID0gam9pbkxpbmVzKGV4cGFuZGVkTGluZVNldCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwb2ludHMgPSB0cmFuc2Zvcm1lZFBvaW50cztcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcG9pbnRzID0gYmFzZVBvaW50cztcbiAgICB9XG5cbiAgICB2YXIgY3VycmVudFgsIGN1cnJlbnRZLCBuZXh0WCwgbmV4dFk7XG5cbiAgICBmb3IgKHZhciBfaTIgPSAwOyBfaTIgPCBwb2ludHMubGVuZ3RoIC8gMjsgX2kyKyspIHtcbiAgICAgIGN1cnJlbnRYID0gcG9pbnRzW19pMiAqIDJdO1xuICAgICAgY3VycmVudFkgPSBwb2ludHNbX2kyICogMiArIDFdO1xuXG4gICAgICBpZiAoX2kyIDwgcG9pbnRzLmxlbmd0aCAvIDIgLSAxKSB7XG4gICAgICAgIG5leHRYID0gcG9pbnRzWyhfaTIgKyAxKSAqIDJdO1xuICAgICAgICBuZXh0WSA9IHBvaW50c1soX2kyICsgMSkgKiAyICsgMV07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuZXh0WCA9IHBvaW50c1swXTtcbiAgICAgICAgbmV4dFkgPSBwb2ludHNbMV07XG4gICAgICB9XG5cbiAgICAgIGludGVyc2VjdGlvbiA9IGZpbml0ZUxpbmVzSW50ZXJzZWN0KHgsIHksIGNlbnRlclgsIGNlbnRlclksIGN1cnJlbnRYLCBjdXJyZW50WSwgbmV4dFgsIG5leHRZKTtcblxuICAgICAgaWYgKGludGVyc2VjdGlvbi5sZW5ndGggIT09IDApIHtcbiAgICAgICAgaW50ZXJzZWN0aW9ucy5wdXNoKGludGVyc2VjdGlvblswXSwgaW50ZXJzZWN0aW9uWzFdKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gaW50ZXJzZWN0aW9ucztcbiAgfTtcbiAgdmFyIHJvdW5kUG9seWdvbkludGVyc2VjdExpbmUgPSBmdW5jdGlvbiByb3VuZFBvbHlnb25JbnRlcnNlY3RMaW5lKHgsIHksIGJhc2VQb2ludHMsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQsIHBhZGRpbmcpIHtcbiAgICB2YXIgaW50ZXJzZWN0aW9ucyA9IFtdO1xuICAgIHZhciBpbnRlcnNlY3Rpb247XG4gICAgdmFyIGxpbmVzID0gbmV3IEFycmF5KGJhc2VQb2ludHMubGVuZ3RoKTtcbiAgICB2YXIgaGFsZlcgPSB3aWR0aCAvIDI7XG4gICAgdmFyIGhhbGZIID0gaGVpZ2h0IC8gMjtcbiAgICB2YXIgY29ybmVyUmFkaXVzID0gZ2V0Um91bmRQb2x5Z29uUmFkaXVzKHdpZHRoLCBoZWlnaHQpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBiYXNlUG9pbnRzLmxlbmd0aCAvIDQ7IGkrKykge1xuICAgICAgdmFyIHNvdXJjZVV2ID0gdm9pZCAwLFxuICAgICAgICAgIGRlc3RVdiA9IHZvaWQgMDtcblxuICAgICAgaWYgKGkgPT09IDApIHtcbiAgICAgICAgc291cmNlVXYgPSBiYXNlUG9pbnRzLmxlbmd0aCAtIDI7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzb3VyY2VVdiA9IGkgKiA0IC0gMjtcbiAgICAgIH1cblxuICAgICAgZGVzdFV2ID0gaSAqIDQgKyAyO1xuICAgICAgdmFyIHB4ID0gY2VudGVyWCArIGhhbGZXICogYmFzZVBvaW50c1tpICogNF07XG4gICAgICB2YXIgcHkgPSBjZW50ZXJZICsgaGFsZkggKiBiYXNlUG9pbnRzW2kgKiA0ICsgMV07XG4gICAgICB2YXIgY29zVGhldGEgPSAtYmFzZVBvaW50c1tzb3VyY2VVdl0gKiBiYXNlUG9pbnRzW2Rlc3RVdl0gLSBiYXNlUG9pbnRzW3NvdXJjZVV2ICsgMV0gKiBiYXNlUG9pbnRzW2Rlc3RVdiArIDFdO1xuICAgICAgdmFyIG9mZnNldCA9IGNvcm5lclJhZGl1cyAvIE1hdGgudGFuKE1hdGguYWNvcyhjb3NUaGV0YSkgLyAyKTtcbiAgICAgIHZhciBjcDB4ID0gcHggLSBvZmZzZXQgKiBiYXNlUG9pbnRzW3NvdXJjZVV2XTtcbiAgICAgIHZhciBjcDB5ID0gcHkgLSBvZmZzZXQgKiBiYXNlUG9pbnRzW3NvdXJjZVV2ICsgMV07XG4gICAgICB2YXIgY3AxeCA9IHB4ICsgb2Zmc2V0ICogYmFzZVBvaW50c1tkZXN0VXZdO1xuICAgICAgdmFyIGNwMXkgPSBweSArIG9mZnNldCAqIGJhc2VQb2ludHNbZGVzdFV2ICsgMV07XG5cbiAgICAgIGlmIChpID09PSAwKSB7XG4gICAgICAgIGxpbmVzW2Jhc2VQb2ludHMubGVuZ3RoIC0gMl0gPSBjcDB4O1xuICAgICAgICBsaW5lc1tiYXNlUG9pbnRzLmxlbmd0aCAtIDFdID0gY3AweTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxpbmVzW2kgKiA0IC0gMl0gPSBjcDB4O1xuICAgICAgICBsaW5lc1tpICogNCAtIDFdID0gY3AweTtcbiAgICAgIH1cblxuICAgICAgbGluZXNbaSAqIDRdID0gY3AxeDtcbiAgICAgIGxpbmVzW2kgKiA0ICsgMV0gPSBjcDF5O1xuICAgICAgdmFyIG9ydGh4ID0gYmFzZVBvaW50c1tzb3VyY2VVdiArIDFdO1xuICAgICAgdmFyIG9ydGh5ID0gLWJhc2VQb2ludHNbc291cmNlVXZdO1xuICAgICAgdmFyIGNvc0FscGhhID0gb3J0aHggKiBiYXNlUG9pbnRzW2Rlc3RVdl0gKyBvcnRoeSAqIGJhc2VQb2ludHNbZGVzdFV2ICsgMV07XG5cbiAgICAgIGlmIChjb3NBbHBoYSA8IDApIHtcbiAgICAgICAgb3J0aHggKj0gLTE7XG4gICAgICAgIG9ydGh5ICo9IC0xO1xuICAgICAgfVxuXG4gICAgICB2YXIgY3ggPSBjcDB4ICsgb3J0aHggKiBjb3JuZXJSYWRpdXM7XG4gICAgICB2YXIgY3kgPSBjcDB5ICsgb3J0aHkgKiBjb3JuZXJSYWRpdXM7XG4gICAgICBpbnRlcnNlY3Rpb24gPSBpbnRlcnNlY3RMaW5lQ2lyY2xlKHgsIHksIGNlbnRlclgsIGNlbnRlclksIGN4LCBjeSwgY29ybmVyUmFkaXVzKTtcblxuICAgICAgaWYgKGludGVyc2VjdGlvbi5sZW5ndGggIT09IDApIHtcbiAgICAgICAgaW50ZXJzZWN0aW9ucy5wdXNoKGludGVyc2VjdGlvblswXSwgaW50ZXJzZWN0aW9uWzFdKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKHZhciBfaTMgPSAwOyBfaTMgPCBsaW5lcy5sZW5ndGggLyA0OyBfaTMrKykge1xuICAgICAgaW50ZXJzZWN0aW9uID0gZmluaXRlTGluZXNJbnRlcnNlY3QoeCwgeSwgY2VudGVyWCwgY2VudGVyWSwgbGluZXNbX2kzICogNF0sIGxpbmVzW19pMyAqIDQgKyAxXSwgbGluZXNbX2kzICogNCArIDJdLCBsaW5lc1tfaTMgKiA0ICsgM10sIGZhbHNlKTtcblxuICAgICAgaWYgKGludGVyc2VjdGlvbi5sZW5ndGggIT09IDApIHtcbiAgICAgICAgaW50ZXJzZWN0aW9ucy5wdXNoKGludGVyc2VjdGlvblswXSwgaW50ZXJzZWN0aW9uWzFdKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoaW50ZXJzZWN0aW9ucy5sZW5ndGggPiAyKSB7XG4gICAgICB2YXIgbG93ZXN0SW50ZXJzZWN0aW9uID0gW2ludGVyc2VjdGlvbnNbMF0sIGludGVyc2VjdGlvbnNbMV1dO1xuICAgICAgdmFyIGxvd2VzdFNxdWFyZWREaXN0YW5jZSA9IE1hdGgucG93KGxvd2VzdEludGVyc2VjdGlvblswXSAtIHgsIDIpICsgTWF0aC5wb3cobG93ZXN0SW50ZXJzZWN0aW9uWzFdIC0geSwgMik7XG5cbiAgICAgIGZvciAodmFyIF9pNCA9IDE7IF9pNCA8IGludGVyc2VjdGlvbnMubGVuZ3RoIC8gMjsgX2k0KyspIHtcbiAgICAgICAgdmFyIHNxdWFyZWREaXN0YW5jZSA9IE1hdGgucG93KGludGVyc2VjdGlvbnNbX2k0ICogMl0gLSB4LCAyKSArIE1hdGgucG93KGludGVyc2VjdGlvbnNbX2k0ICogMiArIDFdIC0geSwgMik7XG5cbiAgICAgICAgaWYgKHNxdWFyZWREaXN0YW5jZSA8PSBsb3dlc3RTcXVhcmVkRGlzdGFuY2UpIHtcbiAgICAgICAgICBsb3dlc3RJbnRlcnNlY3Rpb25bMF0gPSBpbnRlcnNlY3Rpb25zW19pNCAqIDJdO1xuICAgICAgICAgIGxvd2VzdEludGVyc2VjdGlvblsxXSA9IGludGVyc2VjdGlvbnNbX2k0ICogMiArIDFdO1xuICAgICAgICAgIGxvd2VzdFNxdWFyZWREaXN0YW5jZSA9IHNxdWFyZWREaXN0YW5jZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gbG93ZXN0SW50ZXJzZWN0aW9uO1xuICAgIH1cblxuICAgIHJldHVybiBpbnRlcnNlY3Rpb25zO1xuICB9O1xuICB2YXIgc2hvcnRlbkludGVyc2VjdGlvbiA9IGZ1bmN0aW9uIHNob3J0ZW5JbnRlcnNlY3Rpb24oaW50ZXJzZWN0aW9uLCBvZmZzZXQsIGFtb3VudCkge1xuICAgIHZhciBkaXNwID0gW2ludGVyc2VjdGlvblswXSAtIG9mZnNldFswXSwgaW50ZXJzZWN0aW9uWzFdIC0gb2Zmc2V0WzFdXTtcbiAgICB2YXIgbGVuZ3RoID0gTWF0aC5zcXJ0KGRpc3BbMF0gKiBkaXNwWzBdICsgZGlzcFsxXSAqIGRpc3BbMV0pO1xuICAgIHZhciBsZW5SYXRpbyA9IChsZW5ndGggLSBhbW91bnQpIC8gbGVuZ3RoO1xuXG4gICAgaWYgKGxlblJhdGlvIDwgMCkge1xuICAgICAgbGVuUmF0aW8gPSAwLjAwMDAxO1xuICAgIH1cblxuICAgIHJldHVybiBbb2Zmc2V0WzBdICsgbGVuUmF0aW8gKiBkaXNwWzBdLCBvZmZzZXRbMV0gKyBsZW5SYXRpbyAqIGRpc3BbMV1dO1xuICB9O1xuICB2YXIgZ2VuZXJhdGVVbml0TmdvblBvaW50c0ZpdFRvU3F1YXJlID0gZnVuY3Rpb24gZ2VuZXJhdGVVbml0TmdvblBvaW50c0ZpdFRvU3F1YXJlKHNpZGVzLCByb3RhdGlvblJhZGlhbnMpIHtcbiAgICB2YXIgcG9pbnRzID0gZ2VuZXJhdGVVbml0TmdvblBvaW50cyhzaWRlcywgcm90YXRpb25SYWRpYW5zKTtcbiAgICBwb2ludHMgPSBmaXRQb2x5Z29uVG9TcXVhcmUocG9pbnRzKTtcbiAgICByZXR1cm4gcG9pbnRzO1xuICB9O1xuICB2YXIgZml0UG9seWdvblRvU3F1YXJlID0gZnVuY3Rpb24gZml0UG9seWdvblRvU3F1YXJlKHBvaW50cykge1xuICAgIHZhciB4LCB5O1xuICAgIHZhciBzaWRlcyA9IHBvaW50cy5sZW5ndGggLyAyO1xuICAgIHZhciBtaW5YID0gSW5maW5pdHksXG4gICAgICAgIG1pblkgPSBJbmZpbml0eSxcbiAgICAgICAgbWF4WCA9IC1JbmZpbml0eSxcbiAgICAgICAgbWF4WSA9IC1JbmZpbml0eTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2lkZXM7IGkrKykge1xuICAgICAgeCA9IHBvaW50c1syICogaV07XG4gICAgICB5ID0gcG9pbnRzWzIgKiBpICsgMV07XG4gICAgICBtaW5YID0gTWF0aC5taW4obWluWCwgeCk7XG4gICAgICBtYXhYID0gTWF0aC5tYXgobWF4WCwgeCk7XG4gICAgICBtaW5ZID0gTWF0aC5taW4obWluWSwgeSk7XG4gICAgICBtYXhZID0gTWF0aC5tYXgobWF4WSwgeSk7XG4gICAgfSAvLyBzdHJldGNoIGZhY3RvcnNcblxuXG4gICAgdmFyIHN4ID0gMiAvIChtYXhYIC0gbWluWCk7XG4gICAgdmFyIHN5ID0gMiAvIChtYXhZIC0gbWluWSk7XG5cbiAgICBmb3IgKHZhciBfaTUgPSAwOyBfaTUgPCBzaWRlczsgX2k1KyspIHtcbiAgICAgIHggPSBwb2ludHNbMiAqIF9pNV0gPSBwb2ludHNbMiAqIF9pNV0gKiBzeDtcbiAgICAgIHkgPSBwb2ludHNbMiAqIF9pNSArIDFdID0gcG9pbnRzWzIgKiBfaTUgKyAxXSAqIHN5O1xuICAgICAgbWluWCA9IE1hdGgubWluKG1pblgsIHgpO1xuICAgICAgbWF4WCA9IE1hdGgubWF4KG1heFgsIHgpO1xuICAgICAgbWluWSA9IE1hdGgubWluKG1pblksIHkpO1xuICAgICAgbWF4WSA9IE1hdGgubWF4KG1heFksIHkpO1xuICAgIH1cblxuICAgIGlmIChtaW5ZIDwgLTEpIHtcbiAgICAgIGZvciAodmFyIF9pNiA9IDA7IF9pNiA8IHNpZGVzOyBfaTYrKykge1xuICAgICAgICB5ID0gcG9pbnRzWzIgKiBfaTYgKyAxXSA9IHBvaW50c1syICogX2k2ICsgMV0gKyAoLTEgLSBtaW5ZKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcG9pbnRzO1xuICB9O1xuICB2YXIgZ2VuZXJhdGVVbml0TmdvblBvaW50cyA9IGZ1bmN0aW9uIGdlbmVyYXRlVW5pdE5nb25Qb2ludHMoc2lkZXMsIHJvdGF0aW9uUmFkaWFucykge1xuICAgIHZhciBpbmNyZW1lbnQgPSAxLjAgLyBzaWRlcyAqIDIgKiBNYXRoLlBJO1xuICAgIHZhciBzdGFydEFuZ2xlID0gc2lkZXMgJSAyID09PSAwID8gTWF0aC5QSSAvIDIuMCArIGluY3JlbWVudCAvIDIuMCA6IE1hdGguUEkgLyAyLjA7XG4gICAgc3RhcnRBbmdsZSArPSByb3RhdGlvblJhZGlhbnM7XG4gICAgdmFyIHBvaW50cyA9IG5ldyBBcnJheShzaWRlcyAqIDIpO1xuICAgIHZhciBjdXJyZW50QW5nbGU7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpZGVzOyBpKyspIHtcbiAgICAgIGN1cnJlbnRBbmdsZSA9IGkgKiBpbmNyZW1lbnQgKyBzdGFydEFuZ2xlO1xuICAgICAgcG9pbnRzWzIgKiBpXSA9IE1hdGguY29zKGN1cnJlbnRBbmdsZSk7IC8vIHhcblxuICAgICAgcG9pbnRzWzIgKiBpICsgMV0gPSBNYXRoLnNpbigtY3VycmVudEFuZ2xlKTsgLy8geVxuICAgIH1cblxuICAgIHJldHVybiBwb2ludHM7XG4gIH07IC8vIFNldCB0aGUgZGVmYXVsdCByYWRpdXMsIHVubGVzcyBoYWxmIG9mIHdpZHRoIG9yIGhlaWdodCBpcyBzbWFsbGVyIHRoYW4gZGVmYXVsdFxuXG4gIHZhciBnZXRSb3VuZFJlY3RhbmdsZVJhZGl1cyA9IGZ1bmN0aW9uIGdldFJvdW5kUmVjdGFuZ2xlUmFkaXVzKHdpZHRoLCBoZWlnaHQpIHtcbiAgICByZXR1cm4gTWF0aC5taW4od2lkdGggLyA0LCBoZWlnaHQgLyA0LCA4KTtcbiAgfTsgLy8gU2V0IHRoZSBkZWZhdWx0IHJhZGl1c1xuXG4gIHZhciBnZXRSb3VuZFBvbHlnb25SYWRpdXMgPSBmdW5jdGlvbiBnZXRSb3VuZFBvbHlnb25SYWRpdXMod2lkdGgsIGhlaWdodCkge1xuICAgIHJldHVybiBNYXRoLm1pbih3aWR0aCAvIDEwLCBoZWlnaHQgLyAxMCwgOCk7XG4gIH07XG4gIHZhciBnZXRDdXRSZWN0YW5nbGVDb3JuZXJMZW5ndGggPSBmdW5jdGlvbiBnZXRDdXRSZWN0YW5nbGVDb3JuZXJMZW5ndGgoKSB7XG4gICAgcmV0dXJuIDg7XG4gIH07XG4gIHZhciBiZXppZXJQdHNUb1F1YWRDb2VmZiA9IGZ1bmN0aW9uIGJlemllclB0c1RvUXVhZENvZWZmKHAwLCBwMSwgcDIpIHtcbiAgICByZXR1cm4gW3AwIC0gMiAqIHAxICsgcDIsIDIgKiAocDEgLSBwMCksIHAwXTtcbiAgfTsgLy8gZ2V0IGN1cnZlIHdpZHRoLCBoZWlnaHQsIGFuZCBjb250cm9sIHBvaW50IHBvc2l0aW9uIG9mZnNldHMgYXMgYSBwZXJjZW50YWdlIG9mIG5vZGUgaGVpZ2h0IC8gd2lkdGhcblxuICB2YXIgZ2V0QmFycmVsQ3VydmVDb25zdGFudHMgPSBmdW5jdGlvbiBnZXRCYXJyZWxDdXJ2ZUNvbnN0YW50cyh3aWR0aCwgaGVpZ2h0KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlaWdodE9mZnNldDogTWF0aC5taW4oMTUsIDAuMDUgKiBoZWlnaHQpLFxuICAgICAgd2lkdGhPZmZzZXQ6IE1hdGgubWluKDEwMCwgMC4yNSAqIHdpZHRoKSxcbiAgICAgIGN0cmxQdE9mZnNldFBjdDogMC4wNVxuICAgIH07XG4gIH07XG5cbiAgdmFyIHBhZ2VSYW5rRGVmYXVsdHMgPSBkZWZhdWx0cyRnKHtcbiAgICBkYW1waW5nRmFjdG9yOiAwLjgsXG4gICAgcHJlY2lzaW9uOiAwLjAwMDAwMSxcbiAgICBpdGVyYXRpb25zOiAyMDAsXG4gICAgd2VpZ2h0OiBmdW5jdGlvbiB3ZWlnaHQoZWRnZSkge1xuICAgICAgcmV0dXJuIDE7XG4gICAgfVxuICB9KTtcbiAgdmFyIGVsZXNmbiRvID0ge1xuICAgIHBhZ2VSYW5rOiBmdW5jdGlvbiBwYWdlUmFuayhvcHRpb25zKSB7XG4gICAgICB2YXIgX3BhZ2VSYW5rRGVmYXVsdHMgPSBwYWdlUmFua0RlZmF1bHRzKG9wdGlvbnMpLFxuICAgICAgICAgIGRhbXBpbmdGYWN0b3IgPSBfcGFnZVJhbmtEZWZhdWx0cy5kYW1waW5nRmFjdG9yLFxuICAgICAgICAgIHByZWNpc2lvbiA9IF9wYWdlUmFua0RlZmF1bHRzLnByZWNpc2lvbixcbiAgICAgICAgICBpdGVyYXRpb25zID0gX3BhZ2VSYW5rRGVmYXVsdHMuaXRlcmF0aW9ucyxcbiAgICAgICAgICB3ZWlnaHQgPSBfcGFnZVJhbmtEZWZhdWx0cy53ZWlnaHQ7XG5cbiAgICAgIHZhciBjeSA9IHRoaXMuX3ByaXZhdGUuY3k7XG5cbiAgICAgIHZhciBfdGhpcyRieUdyb3VwID0gdGhpcy5ieUdyb3VwKCksXG4gICAgICAgICAgbm9kZXMgPSBfdGhpcyRieUdyb3VwLm5vZGVzLFxuICAgICAgICAgIGVkZ2VzID0gX3RoaXMkYnlHcm91cC5lZGdlcztcblxuICAgICAgdmFyIG51bU5vZGVzID0gbm9kZXMubGVuZ3RoO1xuICAgICAgdmFyIG51bU5vZGVzU3FkID0gbnVtTm9kZXMgKiBudW1Ob2RlcztcbiAgICAgIHZhciBudW1FZGdlcyA9IGVkZ2VzLmxlbmd0aDsgLy8gQ29uc3RydWN0IHRyYW5zcG9zZWQgYWRqYWNlbmN5IG1hdHJpeFxuICAgICAgLy8gRmlyc3QgbGV0cyBoYXZlIGEgemVyb2VkIG1hdHJpeCBvZiB0aGUgcmlnaHQgc2l6ZVxuICAgICAgLy8gV2UnbGwgYWxzbyBrZWVwIHRyYWNrIG9mIHRoZSBzdW0gb2YgZWFjaCBjb2x1bW5cblxuICAgICAgdmFyIG1hdHJpeCA9IG5ldyBBcnJheShudW1Ob2Rlc1NxZCk7XG4gICAgICB2YXIgY29sdW1uU3VtID0gbmV3IEFycmF5KG51bU5vZGVzKTtcbiAgICAgIHZhciBhZGRpdGlvbmFsUHJvYiA9ICgxIC0gZGFtcGluZ0ZhY3RvcikgLyBudW1Ob2RlczsgLy8gQ3JlYXRlIG51bGwgbWF0cml4XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbnVtTm9kZXM7IGkrKykge1xuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IG51bU5vZGVzOyBqKyspIHtcbiAgICAgICAgICB2YXIgbiA9IGkgKiBudW1Ob2RlcyArIGo7XG4gICAgICAgICAgbWF0cml4W25dID0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbHVtblN1bVtpXSA9IDA7XG4gICAgICB9IC8vIE5vdywgcHJvY2VzcyBlZGdlc1xuXG5cbiAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBudW1FZGdlczsgX2krKykge1xuICAgICAgICB2YXIgZWRnZSA9IGVkZ2VzW19pXTtcbiAgICAgICAgdmFyIHNyY0lkID0gZWRnZS5kYXRhKCdzb3VyY2UnKTtcbiAgICAgICAgdmFyIHRndElkID0gZWRnZS5kYXRhKCd0YXJnZXQnKTsgLy8gRG9uJ3QgaW5jbHVkZSBsb29wcyBpbiB0aGUgbWF0cml4XG5cbiAgICAgICAgaWYgKHNyY0lkID09PSB0Z3RJZCkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHMgPSBub2Rlcy5pbmRleE9mSWQoc3JjSWQpO1xuICAgICAgICB2YXIgdCA9IG5vZGVzLmluZGV4T2ZJZCh0Z3RJZCk7XG4gICAgICAgIHZhciB3ID0gd2VpZ2h0KGVkZ2UpO1xuXG4gICAgICAgIHZhciBfbiA9IHQgKiBudW1Ob2RlcyArIHM7IC8vIFVwZGF0ZSBtYXRyaXhcblxuXG4gICAgICAgIG1hdHJpeFtfbl0gKz0gdzsgLy8gVXBkYXRlIGNvbHVtbiBzdW1cblxuICAgICAgICBjb2x1bW5TdW1bc10gKz0gdztcbiAgICAgIH0gLy8gQWRkIGFkZGl0aW9uYWwgcHJvYmFiaWxpdHkgYmFzZWQgb24gZGFtcGluZyBmYWN0b3JcbiAgICAgIC8vIEFsc28sIHRha2UgaW50byBhY2NvdW50IGNvbHVtbnMgdGhhdCBoYXZlIHN1bSA9IDBcblxuXG4gICAgICB2YXIgcCA9IDEuMCAvIG51bU5vZGVzICsgYWRkaXRpb25hbFByb2I7IC8vIFNob3J0aGFuZFxuICAgICAgLy8gVHJhdmVyc2UgbWF0cml4LCBjb2x1bW4gYnkgY29sdW1uXG5cbiAgICAgIGZvciAodmFyIF9qID0gMDsgX2ogPCBudW1Ob2RlczsgX2orKykge1xuICAgICAgICBpZiAoY29sdW1uU3VtW19qXSA9PT0gMCkge1xuICAgICAgICAgIC8vIE5vICdsaW5rcycgb3V0IGZyb20gbm9kZSBqdGgsIGFzc3VtZSBlcXVhbCBwcm9iYWJpbGl0eSBmb3IgZWFjaCBwb3NzaWJsZSBub2RlXG4gICAgICAgICAgZm9yICh2YXIgX2kyID0gMDsgX2kyIDwgbnVtTm9kZXM7IF9pMisrKSB7XG4gICAgICAgICAgICB2YXIgX24yID0gX2kyICogbnVtTm9kZXMgKyBfajtcblxuICAgICAgICAgICAgbWF0cml4W19uMl0gPSBwO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBOb2RlIGp0aCBoYXMgb3V0Z29pbmcgbGluaywgY29tcHV0ZSBub3JtYWxpemVkIHByb2JhYmlsaXRpZXNcbiAgICAgICAgICBmb3IgKHZhciBfaTMgPSAwOyBfaTMgPCBudW1Ob2RlczsgX2kzKyspIHtcbiAgICAgICAgICAgIHZhciBfbjMgPSBfaTMgKiBudW1Ob2RlcyArIF9qO1xuXG4gICAgICAgICAgICBtYXRyaXhbX24zXSA9IG1hdHJpeFtfbjNdIC8gY29sdW1uU3VtW19qXSArIGFkZGl0aW9uYWxQcm9iO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSAvLyBDb21wdXRlIGRvbWluYW50IGVpZ2VudmVjdG9yIHVzaW5nIHBvd2VyIG1ldGhvZFxuXG5cbiAgICAgIHZhciBlaWdlbnZlY3RvciA9IG5ldyBBcnJheShudW1Ob2Rlcyk7XG4gICAgICB2YXIgdGVtcCA9IG5ldyBBcnJheShudW1Ob2Rlcyk7XG4gICAgICB2YXIgcHJldmlvdXM7IC8vIFN0YXJ0IHdpdGggYSB2ZWN0b3Igb2YgYWxsIDEnc1xuICAgICAgLy8gQWxzbywgaW5pdGlhbGl6ZSBhIG51bGwgdmVjdG9yIHdoaWNoIHdpbGwgYmUgdXNlZCBhcyBzaG9ydGhhbmRcblxuICAgICAgZm9yICh2YXIgX2k0ID0gMDsgX2k0IDwgbnVtTm9kZXM7IF9pNCsrKSB7XG4gICAgICAgIGVpZ2VudmVjdG9yW19pNF0gPSAxO1xuICAgICAgfVxuXG4gICAgICBmb3IgKHZhciBpdGVyID0gMDsgaXRlciA8IGl0ZXJhdGlvbnM7IGl0ZXIrKykge1xuICAgICAgICAvLyBUZW1wIGFycmF5IHdpdGggYWxsIDAnc1xuICAgICAgICBmb3IgKHZhciBfaTUgPSAwOyBfaTUgPCBudW1Ob2RlczsgX2k1KyspIHtcbiAgICAgICAgICB0ZW1wW19pNV0gPSAwO1xuICAgICAgICB9IC8vIE11bHRpcGx5IG1hdHJpeCB3aXRoIHByZXZpb3VzIHJlc3VsdFxuXG5cbiAgICAgICAgZm9yICh2YXIgX2k2ID0gMDsgX2k2IDwgbnVtTm9kZXM7IF9pNisrKSB7XG4gICAgICAgICAgZm9yICh2YXIgX2oyID0gMDsgX2oyIDwgbnVtTm9kZXM7IF9qMisrKSB7XG4gICAgICAgICAgICB2YXIgX240ID0gX2k2ICogbnVtTm9kZXMgKyBfajI7XG5cbiAgICAgICAgICAgIHRlbXBbX2k2XSArPSBtYXRyaXhbX240XSAqIGVpZ2VudmVjdG9yW19qMl07XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaW5QbGFjZVN1bU5vcm1hbGl6ZSh0ZW1wKTtcbiAgICAgICAgcHJldmlvdXMgPSBlaWdlbnZlY3RvcjtcbiAgICAgICAgZWlnZW52ZWN0b3IgPSB0ZW1wO1xuICAgICAgICB0ZW1wID0gcHJldmlvdXM7XG4gICAgICAgIHZhciBkaWZmID0gMDsgLy8gQ29tcHV0ZSBkaWZmZXJlbmNlIChzcXVhcmVkIG1vZHVsZSkgb2YgYm90aCB2ZWN0b3JzXG5cbiAgICAgICAgZm9yICh2YXIgX2k3ID0gMDsgX2k3IDwgbnVtTm9kZXM7IF9pNysrKSB7XG4gICAgICAgICAgdmFyIGRlbHRhID0gcHJldmlvdXNbX2k3XSAtIGVpZ2VudmVjdG9yW19pN107XG4gICAgICAgICAgZGlmZiArPSBkZWx0YSAqIGRlbHRhO1xuICAgICAgICB9IC8vIElmIGRpZmZlcmVuY2UgaXMgbGVzcyB0aGFuIHRoZSBkZXNpcmVkIHRocmVzaG9sZCwgc3RvcCBpdGVyYXRpbmdcblxuXG4gICAgICAgIGlmIChkaWZmIDwgcHJlY2lzaW9uKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gQ29uc3RydWN0IHJlc3VsdFxuXG5cbiAgICAgIHZhciByZXMgPSB7XG4gICAgICAgIHJhbms6IGZ1bmN0aW9uIHJhbmsobm9kZSkge1xuICAgICAgICAgIG5vZGUgPSBjeS5jb2xsZWN0aW9uKG5vZGUpWzBdO1xuICAgICAgICAgIHJldHVybiBlaWdlbnZlY3Rvcltub2Rlcy5pbmRleE9mKG5vZGUpXTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIHJldHVybiByZXM7XG4gICAgfSAvLyBwYWdlUmFua1xuXG4gIH07IC8vIGVsZXNmblxuXG4gIHZhciBkZWZhdWx0cyRmID0gZGVmYXVsdHMkZyh7XG4gICAgcm9vdDogbnVsbCxcbiAgICB3ZWlnaHQ6IGZ1bmN0aW9uIHdlaWdodChlZGdlKSB7XG4gICAgICByZXR1cm4gMTtcbiAgICB9LFxuICAgIGRpcmVjdGVkOiBmYWxzZSxcbiAgICBhbHBoYTogMFxuICB9KTtcbiAgdmFyIGVsZXNmbiRuID0ge1xuICAgIGRlZ3JlZUNlbnRyYWxpdHlOb3JtYWxpemVkOiBmdW5jdGlvbiBkZWdyZWVDZW50cmFsaXR5Tm9ybWFsaXplZChvcHRpb25zKSB7XG4gICAgICBvcHRpb25zID0gZGVmYXVsdHMkZihvcHRpb25zKTtcbiAgICAgIHZhciBjeSA9IHRoaXMuY3koKTtcbiAgICAgIHZhciBub2RlcyA9IHRoaXMubm9kZXMoKTtcbiAgICAgIHZhciBudW1Ob2RlcyA9IG5vZGVzLmxlbmd0aDtcblxuICAgICAgaWYgKCFvcHRpb25zLmRpcmVjdGVkKSB7XG4gICAgICAgIHZhciBkZWdyZWVzID0ge307XG4gICAgICAgIHZhciBtYXhEZWdyZWUgPSAwO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbnVtTm9kZXM7IGkrKykge1xuICAgICAgICAgIHZhciBub2RlID0gbm9kZXNbaV07IC8vIGFkZCBjdXJyZW50IG5vZGUgdG8gdGhlIGN1cnJlbnQgb3B0aW9ucyBvYmplY3QgYW5kIGNhbGwgZGVncmVlQ2VudHJhbGl0eVxuXG4gICAgICAgICAgb3B0aW9ucy5yb290ID0gbm9kZTtcbiAgICAgICAgICB2YXIgY3VyckRlZ3JlZSA9IHRoaXMuZGVncmVlQ2VudHJhbGl0eShvcHRpb25zKTtcblxuICAgICAgICAgIGlmIChtYXhEZWdyZWUgPCBjdXJyRGVncmVlLmRlZ3JlZSkge1xuICAgICAgICAgICAgbWF4RGVncmVlID0gY3VyckRlZ3JlZS5kZWdyZWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZGVncmVlc1tub2RlLmlkKCldID0gY3VyckRlZ3JlZS5kZWdyZWU7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGRlZ3JlZTogZnVuY3Rpb24gZGVncmVlKG5vZGUpIHtcbiAgICAgICAgICAgIGlmIChtYXhEZWdyZWUgPT09IDApIHtcbiAgICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChzdHJpbmcobm9kZSkpIHtcbiAgICAgICAgICAgICAgLy8gZnJvbSBpcyBhIHNlbGVjdG9yIHN0cmluZ1xuICAgICAgICAgICAgICBub2RlID0gY3kuZmlsdGVyKG5vZGUpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gZGVncmVlc1tub2RlLmlkKCldIC8gbWF4RGVncmVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBpbmRlZ3JlZXMgPSB7fTtcbiAgICAgICAgdmFyIG91dGRlZ3JlZXMgPSB7fTtcbiAgICAgICAgdmFyIG1heEluZGVncmVlID0gMDtcbiAgICAgICAgdmFyIG1heE91dGRlZ3JlZSA9IDA7XG5cbiAgICAgICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IG51bU5vZGVzOyBfaSsrKSB7XG4gICAgICAgICAgdmFyIF9ub2RlID0gbm9kZXNbX2ldO1xuXG4gICAgICAgICAgdmFyIGlkID0gX25vZGUuaWQoKTsgLy8gYWRkIGN1cnJlbnQgbm9kZSB0byB0aGUgY3VycmVudCBvcHRpb25zIG9iamVjdCBhbmQgY2FsbCBkZWdyZWVDZW50cmFsaXR5XG5cblxuICAgICAgICAgIG9wdGlvbnMucm9vdCA9IF9ub2RlO1xuXG4gICAgICAgICAgdmFyIF9jdXJyRGVncmVlID0gdGhpcy5kZWdyZWVDZW50cmFsaXR5KG9wdGlvbnMpO1xuXG4gICAgICAgICAgaWYgKG1heEluZGVncmVlIDwgX2N1cnJEZWdyZWUuaW5kZWdyZWUpIG1heEluZGVncmVlID0gX2N1cnJEZWdyZWUuaW5kZWdyZWU7XG4gICAgICAgICAgaWYgKG1heE91dGRlZ3JlZSA8IF9jdXJyRGVncmVlLm91dGRlZ3JlZSkgbWF4T3V0ZGVncmVlID0gX2N1cnJEZWdyZWUub3V0ZGVncmVlO1xuICAgICAgICAgIGluZGVncmVlc1tpZF0gPSBfY3VyckRlZ3JlZS5pbmRlZ3JlZTtcbiAgICAgICAgICBvdXRkZWdyZWVzW2lkXSA9IF9jdXJyRGVncmVlLm91dGRlZ3JlZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgaW5kZWdyZWU6IGZ1bmN0aW9uIGluZGVncmVlKG5vZGUpIHtcbiAgICAgICAgICAgIGlmIChtYXhJbmRlZ3JlZSA9PSAwKSB7XG4gICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoc3RyaW5nKG5vZGUpKSB7XG4gICAgICAgICAgICAgIC8vIGZyb20gaXMgYSBzZWxlY3RvciBzdHJpbmdcbiAgICAgICAgICAgICAgbm9kZSA9IGN5LmZpbHRlcihub2RlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIGluZGVncmVlc1tub2RlLmlkKCldIC8gbWF4SW5kZWdyZWU7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvdXRkZWdyZWU6IGZ1bmN0aW9uIG91dGRlZ3JlZShub2RlKSB7XG4gICAgICAgICAgICBpZiAobWF4T3V0ZGVncmVlID09PSAwKSB7XG4gICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoc3RyaW5nKG5vZGUpKSB7XG4gICAgICAgICAgICAgIC8vIGZyb20gaXMgYSBzZWxlY3RvciBzdHJpbmdcbiAgICAgICAgICAgICAgbm9kZSA9IGN5LmZpbHRlcihub2RlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIG91dGRlZ3JlZXNbbm9kZS5pZCgpXSAvIG1heE91dGRlZ3JlZTtcbiAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfSxcbiAgICAvLyBkZWdyZWVDZW50cmFsaXR5Tm9ybWFsaXplZFxuICAgIC8vIEltcGxlbWVudGVkIGZyb20gdGhlIGFsZ29yaXRobSBpbiBPcHNhaGwncyBwYXBlclxuICAgIC8vIFwiTm9kZSBjZW50cmFsaXR5IGluIHdlaWdodGVkIG5ldHdvcmtzOiBHZW5lcmFsaXppbmcgZGVncmVlIGFuZCBzaG9ydGVzdCBwYXRoc1wiXG4gICAgLy8gY2hlY2sgdGhlIGhlYWRpbmcgMiBcIkRlZ3JlZVwiXG4gICAgZGVncmVlQ2VudHJhbGl0eTogZnVuY3Rpb24gZGVncmVlQ2VudHJhbGl0eShvcHRpb25zKSB7XG4gICAgICBvcHRpb25zID0gZGVmYXVsdHMkZihvcHRpb25zKTtcbiAgICAgIHZhciBjeSA9IHRoaXMuY3koKTtcbiAgICAgIHZhciBjYWxsaW5nRWxlcyA9IHRoaXM7XG4gICAgICB2YXIgX29wdGlvbnMgPSBvcHRpb25zLFxuICAgICAgICAgIHJvb3QgPSBfb3B0aW9ucy5yb290LFxuICAgICAgICAgIHdlaWdodCA9IF9vcHRpb25zLndlaWdodCxcbiAgICAgICAgICBkaXJlY3RlZCA9IF9vcHRpb25zLmRpcmVjdGVkLFxuICAgICAgICAgIGFscGhhID0gX29wdGlvbnMuYWxwaGE7XG4gICAgICByb290ID0gY3kuY29sbGVjdGlvbihyb290KVswXTtcblxuICAgICAgaWYgKCFkaXJlY3RlZCkge1xuICAgICAgICB2YXIgY29ubkVkZ2VzID0gcm9vdC5jb25uZWN0ZWRFZGdlcygpLmludGVyc2VjdGlvbihjYWxsaW5nRWxlcyk7XG4gICAgICAgIHZhciBrID0gY29ubkVkZ2VzLmxlbmd0aDtcbiAgICAgICAgdmFyIHMgPSAwOyAvLyBOb3csIHN1bSBlZGdlIHdlaWdodHNcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbm5FZGdlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHMgKz0gd2VpZ2h0KGNvbm5FZGdlc1tpXSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGRlZ3JlZTogTWF0aC5wb3coaywgMSAtIGFscGhhKSAqIE1hdGgucG93KHMsIGFscGhhKVxuICAgICAgICB9O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIGVkZ2VzID0gcm9vdC5jb25uZWN0ZWRFZGdlcygpO1xuICAgICAgICB2YXIgaW5jb21pbmcgPSBlZGdlcy5maWx0ZXIoZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICAgICAgICByZXR1cm4gZWRnZS50YXJnZXQoKS5zYW1lKHJvb3QpICYmIGNhbGxpbmdFbGVzLmhhcyhlZGdlKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBvdXRnb2luZyA9IGVkZ2VzLmZpbHRlcihmdW5jdGlvbiAoZWRnZSkge1xuICAgICAgICAgIHJldHVybiBlZGdlLnNvdXJjZSgpLnNhbWUocm9vdCkgJiYgY2FsbGluZ0VsZXMuaGFzKGVkZ2UpO1xuICAgICAgICB9KTtcbiAgICAgICAgdmFyIGtfaW4gPSBpbmNvbWluZy5sZW5ndGg7XG4gICAgICAgIHZhciBrX291dCA9IG91dGdvaW5nLmxlbmd0aDtcbiAgICAgICAgdmFyIHNfaW4gPSAwO1xuICAgICAgICB2YXIgc19vdXQgPSAwOyAvLyBOb3csIHN1bSBpbmNvbWluZyBlZGdlIHdlaWdodHNcblxuICAgICAgICBmb3IgKHZhciBfaTIgPSAwOyBfaTIgPCBpbmNvbWluZy5sZW5ndGg7IF9pMisrKSB7XG4gICAgICAgICAgc19pbiArPSB3ZWlnaHQoaW5jb21pbmdbX2kyXSk7XG4gICAgICAgIH0gLy8gTm93LCBzdW0gb3V0Z29pbmcgZWRnZSB3ZWlnaHRzXG5cblxuICAgICAgICBmb3IgKHZhciBfaTMgPSAwOyBfaTMgPCBvdXRnb2luZy5sZW5ndGg7IF9pMysrKSB7XG4gICAgICAgICAgc19vdXQgKz0gd2VpZ2h0KG91dGdvaW5nW19pM10pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBpbmRlZ3JlZTogTWF0aC5wb3coa19pbiwgMSAtIGFscGhhKSAqIE1hdGgucG93KHNfaW4sIGFscGhhKSxcbiAgICAgICAgICBvdXRkZWdyZWU6IE1hdGgucG93KGtfb3V0LCAxIC0gYWxwaGEpICogTWF0aC5wb3coc19vdXQsIGFscGhhKVxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH0gLy8gZGVncmVlQ2VudHJhbGl0eVxuXG4gIH07IC8vIGVsZXNmblxuICAvLyBuaWNlLCBzaG9ydCBtYXRoZW1hdGljYWwgYWxpYXNcblxuICBlbGVzZm4kbi5kYyA9IGVsZXNmbiRuLmRlZ3JlZUNlbnRyYWxpdHk7XG4gIGVsZXNmbiRuLmRjbiA9IGVsZXNmbiRuLmRlZ3JlZUNlbnRyYWxpdHlOb3JtYWxpc2VkID0gZWxlc2ZuJG4uZGVncmVlQ2VudHJhbGl0eU5vcm1hbGl6ZWQ7XG5cbiAgdmFyIGRlZmF1bHRzJGUgPSBkZWZhdWx0cyRnKHtcbiAgICBoYXJtb25pYzogdHJ1ZSxcbiAgICB3ZWlnaHQ6IGZ1bmN0aW9uIHdlaWdodCgpIHtcbiAgICAgIHJldHVybiAxO1xuICAgIH0sXG4gICAgZGlyZWN0ZWQ6IGZhbHNlLFxuICAgIHJvb3Q6IG51bGxcbiAgfSk7XG4gIHZhciBlbGVzZm4kbSA9IHtcbiAgICBjbG9zZW5lc3NDZW50cmFsaXR5Tm9ybWFsaXplZDogZnVuY3Rpb24gY2xvc2VuZXNzQ2VudHJhbGl0eU5vcm1hbGl6ZWQob3B0aW9ucykge1xuICAgICAgdmFyIF9kZWZhdWx0cyA9IGRlZmF1bHRzJGUob3B0aW9ucyksXG4gICAgICAgICAgaGFybW9uaWMgPSBfZGVmYXVsdHMuaGFybW9uaWMsXG4gICAgICAgICAgd2VpZ2h0ID0gX2RlZmF1bHRzLndlaWdodCxcbiAgICAgICAgICBkaXJlY3RlZCA9IF9kZWZhdWx0cy5kaXJlY3RlZDtcblxuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuICAgICAgdmFyIGNsb3NlbmVzc2VzID0ge307XG4gICAgICB2YXIgbWF4Q2xvc2VuZXNzID0gMDtcbiAgICAgIHZhciBub2RlcyA9IHRoaXMubm9kZXMoKTtcbiAgICAgIHZhciBmdyA9IHRoaXMuZmxveWRXYXJzaGFsbCh7XG4gICAgICAgIHdlaWdodDogd2VpZ2h0LFxuICAgICAgICBkaXJlY3RlZDogZGlyZWN0ZWRcbiAgICAgIH0pOyAvLyBDb21wdXRlIGNsb3NlbmVzcyBmb3IgZXZlcnkgbm9kZSBhbmQgZmluZCB0aGUgbWF4aW11bSBjbG9zZW5lc3NcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgY3VyckNsb3NlbmVzcyA9IDA7XG4gICAgICAgIHZhciBub2RlX2kgPSBub2Rlc1tpXTtcblxuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IG5vZGVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgaWYgKGkgIT09IGopIHtcbiAgICAgICAgICAgIHZhciBkID0gZncuZGlzdGFuY2Uobm9kZV9pLCBub2Rlc1tqXSk7XG5cbiAgICAgICAgICAgIGlmIChoYXJtb25pYykge1xuICAgICAgICAgICAgICBjdXJyQ2xvc2VuZXNzICs9IDEgLyBkO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgY3VyckNsb3NlbmVzcyArPSBkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghaGFybW9uaWMpIHtcbiAgICAgICAgICBjdXJyQ2xvc2VuZXNzID0gMSAvIGN1cnJDbG9zZW5lc3M7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWF4Q2xvc2VuZXNzIDwgY3VyckNsb3NlbmVzcykge1xuICAgICAgICAgIG1heENsb3NlbmVzcyA9IGN1cnJDbG9zZW5lc3M7XG4gICAgICAgIH1cblxuICAgICAgICBjbG9zZW5lc3Nlc1tub2RlX2kuaWQoKV0gPSBjdXJyQ2xvc2VuZXNzO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBjbG9zZW5lc3M6IGZ1bmN0aW9uIGNsb3NlbmVzcyhub2RlKSB7XG4gICAgICAgICAgaWYgKG1heENsb3NlbmVzcyA9PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoc3RyaW5nKG5vZGUpKSB7XG4gICAgICAgICAgICAvLyBmcm9tIGlzIGEgc2VsZWN0b3Igc3RyaW5nXG4gICAgICAgICAgICBub2RlID0gY3kuZmlsdGVyKG5vZGUpWzBdLmlkKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGZyb20gaXMgYSBub2RlXG4gICAgICAgICAgICBub2RlID0gbm9kZS5pZCgpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBjbG9zZW5lc3Nlc1tub2RlXSAvIG1heENsb3NlbmVzcztcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9LFxuICAgIC8vIEltcGxlbWVudGVkIGZyb20gcHNldWRvY29kZSBmcm9tIHdpa2lwZWRpYVxuICAgIGNsb3NlbmVzc0NlbnRyYWxpdHk6IGZ1bmN0aW9uIGNsb3NlbmVzc0NlbnRyYWxpdHkob3B0aW9ucykge1xuICAgICAgdmFyIF9kZWZhdWx0czIgPSBkZWZhdWx0cyRlKG9wdGlvbnMpLFxuICAgICAgICAgIHJvb3QgPSBfZGVmYXVsdHMyLnJvb3QsXG4gICAgICAgICAgd2VpZ2h0ID0gX2RlZmF1bHRzMi53ZWlnaHQsXG4gICAgICAgICAgZGlyZWN0ZWQgPSBfZGVmYXVsdHMyLmRpcmVjdGVkLFxuICAgICAgICAgIGhhcm1vbmljID0gX2RlZmF1bHRzMi5oYXJtb25pYztcblxuICAgICAgcm9vdCA9IHRoaXMuZmlsdGVyKHJvb3QpWzBdOyAvLyB3ZSBuZWVkIGRpc3RhbmNlIGZyb20gdGhpcyBub2RlIHRvIGV2ZXJ5IG90aGVyIG5vZGVcblxuICAgICAgdmFyIGRpamtzdHJhID0gdGhpcy5kaWprc3RyYSh7XG4gICAgICAgIHJvb3Q6IHJvb3QsXG4gICAgICAgIHdlaWdodDogd2VpZ2h0LFxuICAgICAgICBkaXJlY3RlZDogZGlyZWN0ZWRcbiAgICAgIH0pO1xuICAgICAgdmFyIHRvdGFsRGlzdGFuY2UgPSAwO1xuICAgICAgdmFyIG5vZGVzID0gdGhpcy5ub2RlcygpO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBuID0gbm9kZXNbaV07XG5cbiAgICAgICAgaWYgKCFuLnNhbWUocm9vdCkpIHtcbiAgICAgICAgICB2YXIgZCA9IGRpamtzdHJhLmRpc3RhbmNlVG8obik7XG5cbiAgICAgICAgICBpZiAoaGFybW9uaWMpIHtcbiAgICAgICAgICAgIHRvdGFsRGlzdGFuY2UgKz0gMSAvIGQ7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRvdGFsRGlzdGFuY2UgKz0gZDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGhhcm1vbmljID8gdG90YWxEaXN0YW5jZSA6IDEgLyB0b3RhbERpc3RhbmNlO1xuICAgIH0gLy8gY2xvc2VuZXNzQ2VudHJhbGl0eVxuXG4gIH07IC8vIGVsZXNmblxuICAvLyBuaWNlLCBzaG9ydCBtYXRoZW1hdGljYWwgYWxpYXNcblxuICBlbGVzZm4kbS5jYyA9IGVsZXNmbiRtLmNsb3NlbmVzc0NlbnRyYWxpdHk7XG4gIGVsZXNmbiRtLmNjbiA9IGVsZXNmbiRtLmNsb3NlbmVzc0NlbnRyYWxpdHlOb3JtYWxpc2VkID0gZWxlc2ZuJG0uY2xvc2VuZXNzQ2VudHJhbGl0eU5vcm1hbGl6ZWQ7XG5cbiAgdmFyIGRlZmF1bHRzJGQgPSBkZWZhdWx0cyRnKHtcbiAgICB3ZWlnaHQ6IG51bGwsXG4gICAgZGlyZWN0ZWQ6IGZhbHNlXG4gIH0pO1xuICB2YXIgZWxlc2ZuJGwgPSB7XG4gICAgLy8gSW1wbGVtZW50ZWQgZnJvbSB0aGUgYWxnb3JpdGhtIGluIHRoZSBwYXBlciBcIk9uIFZhcmlhbnRzIG9mIFNob3J0ZXN0LVBhdGggQmV0d2Vlbm5lc3MgQ2VudHJhbGl0eSBhbmQgdGhlaXIgR2VuZXJpYyBDb21wdXRhdGlvblwiIGJ5IFVscmlrIEJyYW5kZXNcbiAgICBiZXR3ZWVubmVzc0NlbnRyYWxpdHk6IGZ1bmN0aW9uIGJldHdlZW5uZXNzQ2VudHJhbGl0eShvcHRpb25zKSB7XG4gICAgICB2YXIgX2RlZmF1bHRzID0gZGVmYXVsdHMkZChvcHRpb25zKSxcbiAgICAgICAgICBkaXJlY3RlZCA9IF9kZWZhdWx0cy5kaXJlY3RlZCxcbiAgICAgICAgICB3ZWlnaHQgPSBfZGVmYXVsdHMud2VpZ2h0O1xuXG4gICAgICB2YXIgd2VpZ2h0ZWQgPSB3ZWlnaHQgIT0gbnVsbDtcbiAgICAgIHZhciBjeSA9IHRoaXMuY3koKTsgLy8gc3RhcnRpbmdcblxuICAgICAgdmFyIFYgPSB0aGlzLm5vZGVzKCk7XG4gICAgICB2YXIgQSA9IHt9O1xuICAgICAgdmFyIF9DID0ge307XG4gICAgICB2YXIgbWF4ID0gMDtcbiAgICAgIHZhciBDID0ge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIHNldChrZXksIHZhbCkge1xuICAgICAgICAgIF9DW2tleV0gPSB2YWw7XG5cbiAgICAgICAgICBpZiAodmFsID4gbWF4KSB7XG4gICAgICAgICAgICBtYXggPSB2YWw7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIGdldChrZXkpIHtcbiAgICAgICAgICByZXR1cm4gX0Nba2V5XTtcbiAgICAgICAgfVxuICAgICAgfTsgLy8gQSBjb250YWlucyB0aGUgbmVpZ2hib3Job29kcyBvZiBldmVyeSBub2RlXG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgVi5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgdiA9IFZbaV07XG4gICAgICAgIHZhciB2aWQgPSB2LmlkKCk7XG5cbiAgICAgICAgaWYgKGRpcmVjdGVkKSB7XG4gICAgICAgICAgQVt2aWRdID0gdi5vdXRnb2VycygpLm5vZGVzKCk7IC8vIGdldCBvdXRnb2VycyBvZiBldmVyeSBub2RlXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgQVt2aWRdID0gdi5vcGVuTmVpZ2hib3Job29kKCkubm9kZXMoKTsgLy8gZ2V0IG5laWdoYm9ycyBvZiBldmVyeSBub2RlXG4gICAgICAgIH1cblxuICAgICAgICBDLnNldCh2aWQsIDApO1xuICAgICAgfVxuXG4gICAgICB2YXIgX2xvb3AgPSBmdW5jdGlvbiBfbG9vcChzKSB7XG4gICAgICAgIHZhciBzaWQgPSBWW3NdLmlkKCk7XG4gICAgICAgIHZhciBTID0gW107IC8vIHN0YWNrXG5cbiAgICAgICAgdmFyIFAgPSB7fTtcbiAgICAgICAgdmFyIGcgPSB7fTtcbiAgICAgICAgdmFyIGQgPSB7fTtcbiAgICAgICAgdmFyIFEgPSBuZXcgaGVhcChmdW5jdGlvbiAoYSwgYikge1xuICAgICAgICAgIHJldHVybiBkW2FdIC0gZFtiXTtcbiAgICAgICAgfSk7IC8vIHF1ZXVlXG4gICAgICAgIC8vIGluaXQgZGljdGlvbmFyaWVzXG5cbiAgICAgICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IFYubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgdmFyIF92aWQgPSBWW19pXS5pZCgpO1xuXG4gICAgICAgICAgUFtfdmlkXSA9IFtdO1xuICAgICAgICAgIGdbX3ZpZF0gPSAwO1xuICAgICAgICAgIGRbX3ZpZF0gPSBJbmZpbml0eTtcbiAgICAgICAgfVxuXG4gICAgICAgIGdbc2lkXSA9IDE7IC8vIHNpZ21hXG5cbiAgICAgICAgZFtzaWRdID0gMDsgLy8gZGlzdGFuY2UgdG8gc1xuXG4gICAgICAgIFEucHVzaChzaWQpO1xuXG4gICAgICAgIHdoaWxlICghUS5lbXB0eSgpKSB7XG4gICAgICAgICAgdmFyIF92ID0gUS5wb3AoKTtcblxuICAgICAgICAgIFMucHVzaChfdik7XG5cbiAgICAgICAgICBpZiAod2VpZ2h0ZWQpIHtcbiAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgQVtfdl0ubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgdmFyIHcgPSBBW192XVtqXTtcbiAgICAgICAgICAgICAgdmFyIHZFbGUgPSBjeS5nZXRFbGVtZW50QnlJZChfdik7XG4gICAgICAgICAgICAgIHZhciBlZGdlID0gdm9pZCAwO1xuXG4gICAgICAgICAgICAgIGlmICh2RWxlLmVkZ2VzVG8odykubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGVkZ2UgPSB2RWxlLmVkZ2VzVG8odylbMF07XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZWRnZSA9IHcuZWRnZXNUbyh2RWxlKVswXTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHZhciBlZGdlV2VpZ2h0ID0gd2VpZ2h0KGVkZ2UpO1xuICAgICAgICAgICAgICB3ID0gdy5pZCgpO1xuXG4gICAgICAgICAgICAgIGlmIChkW3ddID4gZFtfdl0gKyBlZGdlV2VpZ2h0KSB7XG4gICAgICAgICAgICAgICAgZFt3XSA9IGRbX3ZdICsgZWRnZVdlaWdodDtcblxuICAgICAgICAgICAgICAgIGlmIChRLm5vZGVzLmluZGV4T2YodykgPCAwKSB7XG4gICAgICAgICAgICAgICAgICAvL2lmIHcgaXMgbm90IGluIFFcbiAgICAgICAgICAgICAgICAgIFEucHVzaCh3KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgLy8gdXBkYXRlIHBvc2l0aW9uIGlmIHcgaXMgaW4gUVxuICAgICAgICAgICAgICAgICAgUS51cGRhdGVJdGVtKHcpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGdbd10gPSAwO1xuICAgICAgICAgICAgICAgIFBbd10gPSBbXTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGlmIChkW3ddID09IGRbX3ZdICsgZWRnZVdlaWdodCkge1xuICAgICAgICAgICAgICAgIGdbd10gPSBnW3ddICsgZ1tfdl07XG4gICAgICAgICAgICAgICAgUFt3XS5wdXNoKF92KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmb3IgKHZhciBfaiA9IDA7IF9qIDwgQVtfdl0ubGVuZ3RoOyBfaisrKSB7XG4gICAgICAgICAgICAgIHZhciBfdyA9IEFbX3ZdW19qXS5pZCgpO1xuXG4gICAgICAgICAgICAgIGlmIChkW193XSA9PSBJbmZpbml0eSkge1xuICAgICAgICAgICAgICAgIFEucHVzaChfdyk7XG4gICAgICAgICAgICAgICAgZFtfd10gPSBkW192XSArIDE7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBpZiAoZFtfd10gPT0gZFtfdl0gKyAxKSB7XG4gICAgICAgICAgICAgICAgZ1tfd10gPSBnW193XSArIGdbX3ZdO1xuXG4gICAgICAgICAgICAgICAgUFtfd10ucHVzaChfdik7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZSA9IHt9O1xuXG4gICAgICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IFYubGVuZ3RoOyBfaTIrKykge1xuICAgICAgICAgIGVbVltfaTJdLmlkKCldID0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIHdoaWxlIChTLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICB2YXIgX3cyID0gUy5wb3AoKTtcblxuICAgICAgICAgIGZvciAodmFyIF9qMiA9IDA7IF9qMiA8IFBbX3cyXS5sZW5ndGg7IF9qMisrKSB7XG4gICAgICAgICAgICB2YXIgX3YyID0gUFtfdzJdW19qMl07XG4gICAgICAgICAgICBlW192Ml0gPSBlW192Ml0gKyBnW192Ml0gLyBnW193Ml0gKiAoMSArIGVbX3cyXSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKF93MiAhPSBWW3NdLmlkKCkpIHtcbiAgICAgICAgICAgIEMuc2V0KF93MiwgQy5nZXQoX3cyKSArIGVbX3cyXSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICBmb3IgKHZhciBzID0gMDsgcyA8IFYubGVuZ3RoOyBzKyspIHtcbiAgICAgICAgX2xvb3Aocyk7XG4gICAgICB9XG5cbiAgICAgIHZhciByZXQgPSB7XG4gICAgICAgIGJldHdlZW5uZXNzOiBmdW5jdGlvbiBiZXR3ZWVubmVzcyhub2RlKSB7XG4gICAgICAgICAgdmFyIGlkID0gY3kuY29sbGVjdGlvbihub2RlKS5pZCgpO1xuICAgICAgICAgIHJldHVybiBDLmdldChpZCk7XG4gICAgICAgIH0sXG4gICAgICAgIGJldHdlZW5uZXNzTm9ybWFsaXplZDogZnVuY3Rpb24gYmV0d2Vlbm5lc3NOb3JtYWxpemVkKG5vZGUpIHtcbiAgICAgICAgICBpZiAobWF4ID09IDApIHtcbiAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHZhciBpZCA9IGN5LmNvbGxlY3Rpb24obm9kZSkuaWQoKTtcbiAgICAgICAgICByZXR1cm4gQy5nZXQoaWQpIC8gbWF4O1xuICAgICAgICB9XG4gICAgICB9OyAvLyBhbGlhc1xuXG4gICAgICByZXQuYmV0d2Vlbm5lc3NOb3JtYWxpc2VkID0gcmV0LmJldHdlZW5uZXNzTm9ybWFsaXplZDtcbiAgICAgIHJldHVybiByZXQ7XG4gICAgfSAvLyBiZXR3ZWVubmVzc0NlbnRyYWxpdHlcblxuICB9OyAvLyBlbGVzZm5cbiAgLy8gbmljZSwgc2hvcnQgbWF0aGVtYXRpY2FsIGFsaWFzXG5cbiAgZWxlc2ZuJGwuYmMgPSBlbGVzZm4kbC5iZXR3ZWVubmVzc0NlbnRyYWxpdHk7XG5cbiAgLy8gSW1wbGVtZW50ZWQgYnkgWm9lIFhpIEB6b2V4aSBmb3IgR1NPQyAyMDE2XG4gIC8qIGVzbGludC1kaXNhYmxlIG5vLXVudXNlZC12YXJzICovXG5cbiAgdmFyIGRlZmF1bHRzJGMgPSBkZWZhdWx0cyRnKHtcbiAgICBleHBhbmRGYWN0b3I6IDIsXG4gICAgLy8gYWZmZWN0cyB0aW1lIG9mIGNvbXB1dGF0aW9uIGFuZCBjbHVzdGVyIGdyYW51bGFyaXR5IHRvIHNvbWUgZXh0ZW50OiBNICogTVxuICAgIGluZmxhdGVGYWN0b3I6IDIsXG4gICAgLy8gYWZmZWN0cyBjbHVzdGVyIGdyYW51bGFyaXR5ICh0aGUgZ3JlYXRlciB0aGUgdmFsdWUsIHRoZSBtb3JlIGNsdXN0ZXJzKTogTShpLGopIC8gRShqKVxuICAgIG11bHRGYWN0b3I6IDEsXG4gICAgLy8gb3B0aW9uYWwgc2VsZiBsb29wcyBmb3IgZWFjaCBub2RlLiBVc2UgYSBuZXV0cmFsIHZhbHVlIHRvIGltcHJvdmUgY2x1c3RlciBjb21wdXRhdGlvbnMuXG4gICAgbWF4SXRlcmF0aW9uczogMjAsXG4gICAgLy8gbWF4aW11bSBudW1iZXIgb2YgaXRlcmF0aW9ucyBvZiB0aGUgTUNMIGFsZ29yaXRobSBpbiBhIHNpbmdsZSBydW5cbiAgICBhdHRyaWJ1dGVzOiBbLy8gYXR0cmlidXRlcy9mZWF0dXJlcyB1c2VkIHRvIGdyb3VwIG5vZGVzLCBpZS4gc2ltaWxhcml0eSB2YWx1ZXMgYmV0d2VlbiBub2Rlc1xuICAgIGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgICByZXR1cm4gMTtcbiAgICB9XVxuICB9KTtcbiAgLyogZXNsaW50LWVuYWJsZSAqL1xuXG4gIHZhciBzZXRPcHRpb25zJDMgPSBmdW5jdGlvbiBzZXRPcHRpb25zKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGVmYXVsdHMkYyhvcHRpb25zKTtcbiAgfTtcbiAgLyogZXNsaW50LWVuYWJsZSAqL1xuXG5cbiAgdmFyIGdldFNpbWlsYXJpdHkkMSA9IGZ1bmN0aW9uIGdldFNpbWlsYXJpdHkoZWRnZSwgYXR0cmlidXRlcykge1xuICAgIHZhciB0b3RhbCA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGF0dHJpYnV0ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHRvdGFsICs9IGF0dHJpYnV0ZXNbaV0oZWRnZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRvdGFsO1xuICB9O1xuXG4gIHZhciBhZGRMb29wcyA9IGZ1bmN0aW9uIGFkZExvb3BzKE0sIG4sIHZhbCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgICBNW2kgKiBuICsgaV0gPSB2YWw7XG4gICAgfVxuICB9O1xuXG4gIHZhciBub3JtYWxpemUgPSBmdW5jdGlvbiBub3JtYWxpemUoTSwgbikge1xuICAgIHZhciBzdW07XG5cbiAgICBmb3IgKHZhciBjb2wgPSAwOyBjb2wgPCBuOyBjb2wrKykge1xuICAgICAgc3VtID0gMDtcblxuICAgICAgZm9yICh2YXIgcm93ID0gMDsgcm93IDwgbjsgcm93KyspIHtcbiAgICAgICAgc3VtICs9IE1bcm93ICogbiArIGNvbF07XG4gICAgICB9XG5cbiAgICAgIGZvciAodmFyIF9yb3cgPSAwOyBfcm93IDwgbjsgX3JvdysrKSB7XG4gICAgICAgIE1bX3JvdyAqIG4gKyBjb2xdID0gTVtfcm93ICogbiArIGNvbF0gLyBzdW07XG4gICAgICB9XG4gICAgfVxuICB9OyAvLyBUT0RPOiBibG9ja2VkIG1hdHJpeCBtdWx0aXBsaWNhdGlvbj9cblxuXG4gIHZhciBtbXVsdCA9IGZ1bmN0aW9uIG1tdWx0KEEsIEIsIG4pIHtcbiAgICB2YXIgQyA9IG5ldyBBcnJheShuICogbik7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG47IGkrKykge1xuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBuOyBqKyspIHtcbiAgICAgICAgQ1tpICogbiArIGpdID0gMDtcbiAgICAgIH1cblxuICAgICAgZm9yICh2YXIgayA9IDA7IGsgPCBuOyBrKyspIHtcbiAgICAgICAgZm9yICh2YXIgX2ogPSAwOyBfaiA8IG47IF9qKyspIHtcbiAgICAgICAgICBDW2kgKiBuICsgX2pdICs9IEFbaSAqIG4gKyBrXSAqIEJbayAqIG4gKyBfal07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gQztcbiAgfTtcblxuICB2YXIgZXhwYW5kID0gZnVuY3Rpb24gZXhwYW5kKE0sIG4sIGV4cGFuZEZhY3RvclxuICAvKiogcG93ZXIgKiovXG4gICkge1xuICAgIHZhciBfTSA9IE0uc2xpY2UoMCk7XG5cbiAgICBmb3IgKHZhciBwID0gMTsgcCA8IGV4cGFuZEZhY3RvcjsgcCsrKSB7XG4gICAgICBNID0gbW11bHQoTSwgX00sIG4pO1xuICAgIH1cblxuICAgIHJldHVybiBNO1xuICB9O1xuXG4gIHZhciBpbmZsYXRlID0gZnVuY3Rpb24gaW5mbGF0ZShNLCBuLCBpbmZsYXRlRmFjdG9yXG4gIC8qKiByICoqL1xuICApIHtcbiAgICB2YXIgX00gPSBuZXcgQXJyYXkobiAqIG4pOyAvLyBNKGksaikgXiBpbmZsYXRlUG93ZXJcblxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuICogbjsgaSsrKSB7XG4gICAgICBfTVtpXSA9IE1hdGgucG93KE1baV0sIGluZmxhdGVGYWN0b3IpO1xuICAgIH1cblxuICAgIG5vcm1hbGl6ZShfTSwgbik7XG4gICAgcmV0dXJuIF9NO1xuICB9O1xuXG4gIHZhciBoYXNDb252ZXJnZWQgPSBmdW5jdGlvbiBoYXNDb252ZXJnZWQoTSwgX00sIG4yLCByb3VuZEZhY3Rvcikge1xuICAgIC8vIENoZWNrIHRoYXQgYm90aCBtYXRyaWNlcyBoYXZlIHRoZSBzYW1lIGVsZW1lbnRzIChpLGopXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuMjsgaSsrKSB7XG4gICAgICB2YXIgdjEgPSBNYXRoLnJvdW5kKE1baV0gKiBNYXRoLnBvdygxMCwgcm91bmRGYWN0b3IpKSAvIE1hdGgucG93KDEwLCByb3VuZEZhY3Rvcik7IC8vIHRydW5jYXRlIHRvICdyb3VuZEZhY3RvcicgZGVjaW1hbCBwbGFjZXNcblxuICAgICAgdmFyIHYyID0gTWF0aC5yb3VuZChfTVtpXSAqIE1hdGgucG93KDEwLCByb3VuZEZhY3RvcikpIC8gTWF0aC5wb3coMTAsIHJvdW5kRmFjdG9yKTtcblxuICAgICAgaWYgKHYxICE9PSB2Mikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgdmFyIGFzc2lnbiQyID0gZnVuY3Rpb24gYXNzaWduKE0sIG4sIG5vZGVzLCBjeSkge1xuICAgIHZhciBjbHVzdGVycyA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuOyBpKyspIHtcbiAgICAgIHZhciBjbHVzdGVyID0gW107XG5cbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbjsgaisrKSB7XG4gICAgICAgIC8vIFJvdy13aXNlIGF0dHJhY3RvcnMgYW5kIGVsZW1lbnRzIHRoYXQgdGhleSBhdHRyYWN0IGJlbG9uZyBpbiBzYW1lIGNsdXN0ZXJcbiAgICAgICAgaWYgKE1hdGgucm91bmQoTVtpICogbiArIGpdICogMTAwMCkgLyAxMDAwID4gMCkge1xuICAgICAgICAgIGNsdXN0ZXIucHVzaChub2Rlc1tqXSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGNsdXN0ZXIubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgIGNsdXN0ZXJzLnB1c2goY3kuY29sbGVjdGlvbihjbHVzdGVyKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGNsdXN0ZXJzO1xuICB9O1xuXG4gIHZhciBpc0R1cGxpY2F0ZSA9IGZ1bmN0aW9uIGlzRHVwbGljYXRlKGMxLCBjMikge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYzEubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICghYzJbaV0gfHwgYzFbaV0uaWQoKSAhPT0gYzJbaV0uaWQoKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgdmFyIHJlbW92ZUR1cGxpY2F0ZXMgPSBmdW5jdGlvbiByZW1vdmVEdXBsaWNhdGVzKGNsdXN0ZXJzKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjbHVzdGVycy5sZW5ndGg7IGkrKykge1xuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBjbHVzdGVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoaSAhPSBqICYmIGlzRHVwbGljYXRlKGNsdXN0ZXJzW2ldLCBjbHVzdGVyc1tqXSkpIHtcbiAgICAgICAgICBjbHVzdGVycy5zcGxpY2UoaiwgMSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gY2x1c3RlcnM7XG4gIH07XG5cbiAgdmFyIG1hcmtvdkNsdXN0ZXJpbmcgPSBmdW5jdGlvbiBtYXJrb3ZDbHVzdGVyaW5nKG9wdGlvbnMpIHtcbiAgICB2YXIgbm9kZXMgPSB0aGlzLm5vZGVzKCk7XG4gICAgdmFyIGVkZ2VzID0gdGhpcy5lZGdlcygpO1xuICAgIHZhciBjeSA9IHRoaXMuY3koKTsgLy8gU2V0IHBhcmFtZXRlcnMgb2YgYWxnb3JpdGhtOlxuXG4gICAgdmFyIG9wdHMgPSBzZXRPcHRpb25zJDMob3B0aW9ucyk7IC8vIE1hcCBlYWNoIG5vZGUgdG8gaXRzIHBvc2l0aW9uIGluIG5vZGUgYXJyYXlcblxuICAgIHZhciBpZDJwb3NpdGlvbiA9IHt9O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWQycG9zaXRpb25bbm9kZXNbaV0uaWQoKV0gPSBpO1xuICAgIH0gLy8gR2VuZXJhdGUgc3RvY2hhc3RpYyBtYXRyaXggTSBmcm9tIGlucHV0IGdyYXBoIEcgKHNob3VsZCBiZSBzeW1tZXRyaWMvdW5kaXJlY3RlZClcblxuXG4gICAgdmFyIG4gPSBub2Rlcy5sZW5ndGgsXG4gICAgICAgIG4yID0gbiAqIG47XG5cbiAgICB2YXIgTSA9IG5ldyBBcnJheShuMiksXG4gICAgICAgIF9NO1xuXG4gICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IG4yOyBfaSsrKSB7XG4gICAgICBNW19pXSA9IDA7XG4gICAgfVxuXG4gICAgZm9yICh2YXIgZSA9IDA7IGUgPCBlZGdlcy5sZW5ndGg7IGUrKykge1xuICAgICAgdmFyIGVkZ2UgPSBlZGdlc1tlXTtcbiAgICAgIHZhciBfaTIgPSBpZDJwb3NpdGlvbltlZGdlLnNvdXJjZSgpLmlkKCldO1xuICAgICAgdmFyIGogPSBpZDJwb3NpdGlvbltlZGdlLnRhcmdldCgpLmlkKCldO1xuICAgICAgdmFyIHNpbSA9IGdldFNpbWlsYXJpdHkkMShlZGdlLCBvcHRzLmF0dHJpYnV0ZXMpO1xuICAgICAgTVtfaTIgKiBuICsgal0gKz0gc2ltOyAvLyBHIHNob3VsZCBiZSBzeW1tZXRyaWMgYW5kIHVuZGlyZWN0ZWRcblxuICAgICAgTVtqICogbiArIF9pMl0gKz0gc2ltO1xuICAgIH0gLy8gQmVnaW4gTWFya292IGNsdXN0ZXIgYWxnb3JpdGhtXG4gICAgLy8gU3RlcCAxOiBBZGQgc2VsZiBsb29wcyB0byBlYWNoIG5vZGUsIGllLiBhZGQgbXVsdEZhY3RvciB0byBtYXRyaXggZGlhZ29uYWxcblxuXG4gICAgYWRkTG9vcHMoTSwgbiwgb3B0cy5tdWx0RmFjdG9yKTsgLy8gU3RlcCAyOiBNID0gbm9ybWFsaXplKCBNICk7XG5cbiAgICBub3JtYWxpemUoTSwgbik7XG4gICAgdmFyIGlzU3RpbGxNb3ZpbmcgPSB0cnVlO1xuICAgIHZhciBpdGVyYXRpb25zID0gMDtcblxuICAgIHdoaWxlIChpc1N0aWxsTW92aW5nICYmIGl0ZXJhdGlvbnMgPCBvcHRzLm1heEl0ZXJhdGlvbnMpIHtcbiAgICAgIGlzU3RpbGxNb3ZpbmcgPSBmYWxzZTsgLy8gU3RlcCAzOlxuXG4gICAgICBfTSA9IGV4cGFuZChNLCBuLCBvcHRzLmV4cGFuZEZhY3Rvcik7IC8vIFN0ZXAgNDpcblxuICAgICAgTSA9IGluZmxhdGUoX00sIG4sIG9wdHMuaW5mbGF0ZUZhY3Rvcik7IC8vIFN0ZXAgNTogY2hlY2sgdG8gc2VlIGlmIH5zdGVhZHkgc3RhdGUgaGFzIGJlZW4gcmVhY2hlZFxuXG4gICAgICBpZiAoIWhhc0NvbnZlcmdlZChNLCBfTSwgbjIsIDQpKSB7XG4gICAgICAgIGlzU3RpbGxNb3ZpbmcgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICBpdGVyYXRpb25zKys7XG4gICAgfSAvLyBCdWlsZCBjbHVzdGVycyBmcm9tIG1hdHJpeFxuXG5cbiAgICB2YXIgY2x1c3RlcnMgPSBhc3NpZ24kMihNLCBuLCBub2RlcywgY3kpOyAvLyBSZW1vdmUgZHVwbGljYXRlIGNsdXN0ZXJzIGR1ZSB0byBzeW1tZXRyeSBvZiBncmFwaCBhbmQgTSBtYXRyaXhcblxuICAgIGNsdXN0ZXJzID0gcmVtb3ZlRHVwbGljYXRlcyhjbHVzdGVycyk7XG4gICAgcmV0dXJuIGNsdXN0ZXJzO1xuICB9O1xuXG4gIHZhciBtYXJrb3ZDbHVzdGVyaW5nJDEgPSB7XG4gICAgbWFya292Q2x1c3RlcmluZzogbWFya292Q2x1c3RlcmluZyxcbiAgICBtY2w6IG1hcmtvdkNsdXN0ZXJpbmdcbiAgfTtcblxuICAvLyBDb21tb24gZGlzdGFuY2UgbWV0cmljcyBmb3IgY2x1c3RlcmluZyBhbGdvcml0aG1zXG5cbiAgdmFyIGlkZW50aXR5ID0gZnVuY3Rpb24gaWRlbnRpdHkoeCkge1xuICAgIHJldHVybiB4O1xuICB9O1xuXG4gIHZhciBhYnNEaWZmID0gZnVuY3Rpb24gYWJzRGlmZihwLCBxKSB7XG4gICAgcmV0dXJuIE1hdGguYWJzKHEgLSBwKTtcbiAgfTtcblxuICB2YXIgYWRkQWJzRGlmZiA9IGZ1bmN0aW9uIGFkZEFic0RpZmYodG90YWwsIHAsIHEpIHtcbiAgICByZXR1cm4gdG90YWwgKyBhYnNEaWZmKHAsIHEpO1xuICB9O1xuXG4gIHZhciBhZGRTcXVhcmVkRGlmZiA9IGZ1bmN0aW9uIGFkZFNxdWFyZWREaWZmKHRvdGFsLCBwLCBxKSB7XG4gICAgcmV0dXJuIHRvdGFsICsgTWF0aC5wb3cocSAtIHAsIDIpO1xuICB9O1xuXG4gIHZhciBzcXJ0ID0gZnVuY3Rpb24gc3FydCh4KSB7XG4gICAgcmV0dXJuIE1hdGguc3FydCh4KTtcbiAgfTtcblxuICB2YXIgbWF4QWJzRGlmZiA9IGZ1bmN0aW9uIG1heEFic0RpZmYoY3VycmVudE1heCwgcCwgcSkge1xuICAgIHJldHVybiBNYXRoLm1heChjdXJyZW50TWF4LCBhYnNEaWZmKHAsIHEpKTtcbiAgfTtcblxuICB2YXIgZ2V0RGlzdGFuY2UgPSBmdW5jdGlvbiBnZXREaXN0YW5jZShsZW5ndGgsIGdldFAsIGdldFEsIGluaXQsIHZpc2l0KSB7XG4gICAgdmFyIHBvc3QgPSBhcmd1bWVudHMubGVuZ3RoID4gNSAmJiBhcmd1bWVudHNbNV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1s1XSA6IGlkZW50aXR5O1xuICAgIHZhciByZXQgPSBpbml0O1xuICAgIHZhciBwLCBxO1xuXG4gICAgZm9yICh2YXIgZGltID0gMDsgZGltIDwgbGVuZ3RoOyBkaW0rKykge1xuICAgICAgcCA9IGdldFAoZGltKTtcbiAgICAgIHEgPSBnZXRRKGRpbSk7XG4gICAgICByZXQgPSB2aXNpdChyZXQsIHAsIHEpO1xuICAgIH1cblxuICAgIHJldHVybiBwb3N0KHJldCk7XG4gIH07XG5cbiAgdmFyIGRpc3RhbmNlcyA9IHtcbiAgICBldWNsaWRlYW46IGZ1bmN0aW9uIGV1Y2xpZGVhbihsZW5ndGgsIGdldFAsIGdldFEpIHtcbiAgICAgIGlmIChsZW5ndGggPj0gMikge1xuICAgICAgICByZXR1cm4gZ2V0RGlzdGFuY2UobGVuZ3RoLCBnZXRQLCBnZXRRLCAwLCBhZGRTcXVhcmVkRGlmZiwgc3FydCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBmb3Igc2luZ2xlIGF0dHIgY2FzZSwgbW9yZSBlZmZpY2llbnQgdG8gYXZvaWQgc3FydFxuICAgICAgICByZXR1cm4gZ2V0RGlzdGFuY2UobGVuZ3RoLCBnZXRQLCBnZXRRLCAwLCBhZGRBYnNEaWZmKTtcbiAgICAgIH1cbiAgICB9LFxuICAgIHNxdWFyZWRFdWNsaWRlYW46IGZ1bmN0aW9uIHNxdWFyZWRFdWNsaWRlYW4obGVuZ3RoLCBnZXRQLCBnZXRRKSB7XG4gICAgICByZXR1cm4gZ2V0RGlzdGFuY2UobGVuZ3RoLCBnZXRQLCBnZXRRLCAwLCBhZGRTcXVhcmVkRGlmZik7XG4gICAgfSxcbiAgICBtYW5oYXR0YW46IGZ1bmN0aW9uIG1hbmhhdHRhbihsZW5ndGgsIGdldFAsIGdldFEpIHtcbiAgICAgIHJldHVybiBnZXREaXN0YW5jZShsZW5ndGgsIGdldFAsIGdldFEsIDAsIGFkZEFic0RpZmYpO1xuICAgIH0sXG4gICAgbWF4OiBmdW5jdGlvbiBtYXgobGVuZ3RoLCBnZXRQLCBnZXRRKSB7XG4gICAgICByZXR1cm4gZ2V0RGlzdGFuY2UobGVuZ3RoLCBnZXRQLCBnZXRRLCAtSW5maW5pdHksIG1heEFic0RpZmYpO1xuICAgIH1cbiAgfTsgLy8gaW4gY2FzZSB0aGUgdXNlciBhY2NpZGVudGFsbHkgZG9lc24ndCB1c2UgY2FtZWwgY2FzZVxuXG4gIGRpc3RhbmNlc1snc3F1YXJlZC1ldWNsaWRlYW4nXSA9IGRpc3RhbmNlc1snc3F1YXJlZEV1Y2xpZGVhbiddO1xuICBkaXN0YW5jZXNbJ3NxdWFyZWRldWNsaWRlYW4nXSA9IGRpc3RhbmNlc1snc3F1YXJlZEV1Y2xpZGVhbiddO1xuICBmdW5jdGlvbiBjbHVzdGVyaW5nRGlzdGFuY2UgKG1ldGhvZCwgbGVuZ3RoLCBnZXRQLCBnZXRRLCBub2RlUCwgbm9kZVEpIHtcbiAgICB2YXIgaW1wbDtcblxuICAgIGlmIChmbiQ2KG1ldGhvZCkpIHtcbiAgICAgIGltcGwgPSBtZXRob2Q7XG4gICAgfSBlbHNlIHtcbiAgICAgIGltcGwgPSBkaXN0YW5jZXNbbWV0aG9kXSB8fCBkaXN0YW5jZXMuZXVjbGlkZWFuO1xuICAgIH1cblxuICAgIGlmIChsZW5ndGggPT09IDAgJiYgZm4kNihtZXRob2QpKSB7XG4gICAgICByZXR1cm4gaW1wbChub2RlUCwgbm9kZVEpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gaW1wbChsZW5ndGgsIGdldFAsIGdldFEsIG5vZGVQLCBub2RlUSk7XG4gICAgfVxuICB9XG5cbiAgdmFyIGRlZmF1bHRzJGIgPSBkZWZhdWx0cyRnKHtcbiAgICBrOiAyLFxuICAgIG06IDIsXG4gICAgc2Vuc2l0aXZpdHlUaHJlc2hvbGQ6IDAuMDAwMSxcbiAgICBkaXN0YW5jZTogJ2V1Y2xpZGVhbicsXG4gICAgbWF4SXRlcmF0aW9uczogMTAsXG4gICAgYXR0cmlidXRlczogW10sXG4gICAgdGVzdE1vZGU6IGZhbHNlLFxuICAgIHRlc3RDZW50cm9pZHM6IG51bGxcbiAgfSk7XG5cbiAgdmFyIHNldE9wdGlvbnMkMiA9IGZ1bmN0aW9uIHNldE9wdGlvbnMob3B0aW9ucykge1xuICAgIHJldHVybiBkZWZhdWx0cyRiKG9wdGlvbnMpO1xuICB9O1xuICAvKiBlc2xpbnQtZW5hYmxlICovXG5cblxuICB2YXIgZ2V0RGlzdCA9IGZ1bmN0aW9uIGdldERpc3QodHlwZSwgbm9kZSwgY2VudHJvaWQsIGF0dHJpYnV0ZXMsIG1vZGUpIHtcbiAgICB2YXIgbm9Ob2RlUCA9IG1vZGUgIT09ICdrTWVkb2lkcyc7XG4gICAgdmFyIGdldFAgPSBub05vZGVQID8gZnVuY3Rpb24gKGkpIHtcbiAgICAgIHJldHVybiBjZW50cm9pZFtpXTtcbiAgICB9IDogZnVuY3Rpb24gKGkpIHtcbiAgICAgIHJldHVybiBhdHRyaWJ1dGVzW2ldKGNlbnRyb2lkKTtcbiAgICB9O1xuXG4gICAgdmFyIGdldFEgPSBmdW5jdGlvbiBnZXRRKGkpIHtcbiAgICAgIHJldHVybiBhdHRyaWJ1dGVzW2ldKG5vZGUpO1xuICAgIH07XG5cbiAgICB2YXIgbm9kZVAgPSBjZW50cm9pZDtcbiAgICB2YXIgbm9kZVEgPSBub2RlO1xuICAgIHJldHVybiBjbHVzdGVyaW5nRGlzdGFuY2UodHlwZSwgYXR0cmlidXRlcy5sZW5ndGgsIGdldFAsIGdldFEsIG5vZGVQLCBub2RlUSk7XG4gIH07XG5cbiAgdmFyIHJhbmRvbUNlbnRyb2lkcyA9IGZ1bmN0aW9uIHJhbmRvbUNlbnRyb2lkcyhub2RlcywgaywgYXR0cmlidXRlcykge1xuICAgIHZhciBuZGltID0gYXR0cmlidXRlcy5sZW5ndGg7XG4gICAgdmFyIG1pbiA9IG5ldyBBcnJheShuZGltKTtcbiAgICB2YXIgbWF4ID0gbmV3IEFycmF5KG5kaW0pO1xuICAgIHZhciBjZW50cm9pZHMgPSBuZXcgQXJyYXkoayk7XG4gICAgdmFyIGNlbnRyb2lkID0gbnVsbDsgLy8gRmluZCBtaW4sIG1heCB2YWx1ZXMgZm9yIGVhY2ggYXR0cmlidXRlIGRpbWVuc2lvblxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuZGltOyBpKyspIHtcbiAgICAgIG1pbltpXSA9IG5vZGVzLm1pbihhdHRyaWJ1dGVzW2ldKS52YWx1ZTtcbiAgICAgIG1heFtpXSA9IG5vZGVzLm1heChhdHRyaWJ1dGVzW2ldKS52YWx1ZTtcbiAgICB9IC8vIEJ1aWxkIGsgY2VudHJvaWRzLCBlYWNoIHJlcHJlc2VudGVkIGFzIGFuIG4tZGltIGZlYXR1cmUgdmVjdG9yXG5cblxuICAgIGZvciAodmFyIGMgPSAwOyBjIDwgazsgYysrKSB7XG4gICAgICBjZW50cm9pZCA9IFtdO1xuXG4gICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgbmRpbTsgX2krKykge1xuICAgICAgICBjZW50cm9pZFtfaV0gPSBNYXRoLnJhbmRvbSgpICogKG1heFtfaV0gLSBtaW5bX2ldKSArIG1pbltfaV07IC8vIHJhbmRvbSBpbml0aWFsIHZhbHVlXG4gICAgICB9XG5cbiAgICAgIGNlbnRyb2lkc1tjXSA9IGNlbnRyb2lkO1xuICAgIH1cblxuICAgIHJldHVybiBjZW50cm9pZHM7XG4gIH07XG5cbiAgdmFyIGNsYXNzaWZ5ID0gZnVuY3Rpb24gY2xhc3NpZnkobm9kZSwgY2VudHJvaWRzLCBkaXN0YW5jZSwgYXR0cmlidXRlcywgdHlwZSkge1xuICAgIHZhciBtaW4gPSBJbmZpbml0eTtcbiAgICB2YXIgaW5kZXggPSAwO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjZW50cm9pZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBkaXN0ID0gZ2V0RGlzdChkaXN0YW5jZSwgbm9kZSwgY2VudHJvaWRzW2ldLCBhdHRyaWJ1dGVzLCB0eXBlKTtcblxuICAgICAgaWYgKGRpc3QgPCBtaW4pIHtcbiAgICAgICAgbWluID0gZGlzdDtcbiAgICAgICAgaW5kZXggPSBpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBpbmRleDtcbiAgfTtcblxuICB2YXIgYnVpbGRDbHVzdGVyID0gZnVuY3Rpb24gYnVpbGRDbHVzdGVyKGNlbnRyb2lkLCBub2RlcywgYXNzaWdubWVudCkge1xuICAgIHZhciBjbHVzdGVyID0gW107XG4gICAgdmFyIG5vZGUgPSBudWxsO1xuXG4gICAgZm9yICh2YXIgbiA9IDA7IG4gPCBub2Rlcy5sZW5ndGg7IG4rKykge1xuICAgICAgbm9kZSA9IG5vZGVzW25dO1xuXG4gICAgICBpZiAoYXNzaWdubWVudFtub2RlLmlkKCldID09PSBjZW50cm9pZCkge1xuICAgICAgICAvL2NvbnNvbGUubG9nKFwiTm9kZSBcIiArIG5vZGUuaWQoKSArIFwiIGlzIGFzc29jaWF0ZWQgd2l0aCBtZWRvaWQgIzogXCIgKyBtKTtcbiAgICAgICAgY2x1c3Rlci5wdXNoKG5vZGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjbHVzdGVyO1xuICB9O1xuXG4gIHZhciBoYXZlVmFsdWVzQ29udmVyZ2VkID0gZnVuY3Rpb24gaGF2ZVZhbHVlc0NvbnZlcmdlZCh2MSwgdjIsIHNlbnNpdGl2aXR5VGhyZXNob2xkKSB7XG4gICAgcmV0dXJuIE1hdGguYWJzKHYyIC0gdjEpIDw9IHNlbnNpdGl2aXR5VGhyZXNob2xkO1xuICB9O1xuXG4gIHZhciBoYXZlTWF0cmljZXNDb252ZXJnZWQgPSBmdW5jdGlvbiBoYXZlTWF0cmljZXNDb252ZXJnZWQodjEsIHYyLCBzZW5zaXRpdml0eVRocmVzaG9sZCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdjEubGVuZ3RoOyBpKyspIHtcbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgdjFbaV0ubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdmFyIGRpZmYgPSBNYXRoLmFicyh2MVtpXVtqXSAtIHYyW2ldW2pdKTtcblxuICAgICAgICBpZiAoZGlmZiA+IHNlbnNpdGl2aXR5VGhyZXNob2xkKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgdmFyIHNlZW5CZWZvcmUgPSBmdW5jdGlvbiBzZWVuQmVmb3JlKG5vZGUsIG1lZG9pZHMsIG4pIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG47IGkrKykge1xuICAgICAgaWYgKG5vZGUgPT09IG1lZG9pZHNbaV0pIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfTtcblxuICB2YXIgcmFuZG9tTWVkb2lkcyA9IGZ1bmN0aW9uIHJhbmRvbU1lZG9pZHMobm9kZXMsIGspIHtcbiAgICB2YXIgbWVkb2lkcyA9IG5ldyBBcnJheShrKTsgLy8gRm9yIHNtYWxsIGRhdGEgc2V0cywgdGhlIHByb2JhYmlsaXR5IG9mIG1lZG9pZCBjb25mbGljdCBpcyBncmVhdGVyLFxuICAgIC8vIHNvIHdlIG5lZWQgdG8gY2hlY2sgdG8gc2VlIGlmIHdlJ3ZlIGFscmVhZHkgc2VlbiBvciBjaG9zZSB0aGlzIG5vZGUgYmVmb3JlLlxuXG4gICAgaWYgKG5vZGVzLmxlbmd0aCA8IDUwKSB7XG4gICAgICAvLyBSYW5kb21seSBzZWxlY3QgayBtZWRvaWRzIGZyb20gdGhlIG4gbm9kZXNcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgazsgaSsrKSB7XG4gICAgICAgIHZhciBub2RlID0gbm9kZXNbTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogbm9kZXMubGVuZ3RoKV07IC8vIElmIHdlJ3ZlIGFscmVhZHkgY2hvc2VuIHRoaXMgbm9kZSB0byBiZSBhIG1lZG9pZCwgZG9uJ3QgY2hvb3NlIGl0IGFnYWluIChmb3Igc21hbGwgZGF0YSBzZXRzKS5cbiAgICAgICAgLy8gSW5zdGVhZCBjaG9vc2UgYSBkaWZmZXJlbnQgcmFuZG9tIG5vZGUuXG5cbiAgICAgICAgd2hpbGUgKHNlZW5CZWZvcmUobm9kZSwgbWVkb2lkcywgaSkpIHtcbiAgICAgICAgICBub2RlID0gbm9kZXNbTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogbm9kZXMubGVuZ3RoKV07XG4gICAgICAgIH1cblxuICAgICAgICBtZWRvaWRzW2ldID0gbm9kZTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUmVsYXRpdmVseSBsYXJnZSBkYXRhIHNldCwgc28gcHJldHR5IHNhZmUgdG8gbm90IGNoZWNrIGFuZCBqdXN0IHNlbGVjdCByYW5kb20gbm9kZXNcbiAgICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IGs7IF9pMisrKSB7XG4gICAgICAgIG1lZG9pZHNbX2kyXSA9IG5vZGVzW01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIG5vZGVzLmxlbmd0aCldO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBtZWRvaWRzO1xuICB9O1xuXG4gIHZhciBmaW5kQ29zdCA9IGZ1bmN0aW9uIGZpbmRDb3N0KHBvdGVudGlhbE5ld01lZG9pZCwgY2x1c3RlciwgYXR0cmlidXRlcykge1xuICAgIHZhciBjb3N0ID0gMDtcblxuICAgIGZvciAodmFyIG4gPSAwOyBuIDwgY2x1c3Rlci5sZW5ndGg7IG4rKykge1xuICAgICAgY29zdCArPSBnZXREaXN0KCdtYW5oYXR0YW4nLCBjbHVzdGVyW25dLCBwb3RlbnRpYWxOZXdNZWRvaWQsIGF0dHJpYnV0ZXMsICdrTWVkb2lkcycpO1xuICAgIH1cblxuICAgIHJldHVybiBjb3N0O1xuICB9O1xuXG4gIHZhciBrTWVhbnMgPSBmdW5jdGlvbiBrTWVhbnMob3B0aW9ucykge1xuICAgIHZhciBjeSA9IHRoaXMuY3koKTtcbiAgICB2YXIgbm9kZXMgPSB0aGlzLm5vZGVzKCk7XG4gICAgdmFyIG5vZGUgPSBudWxsOyAvLyBTZXQgcGFyYW1ldGVycyBvZiBhbGdvcml0aG06ICMgb2YgY2x1c3RlcnMsIGRpc3RhbmNlIG1ldHJpYywgZXRjLlxuXG4gICAgdmFyIG9wdHMgPSBzZXRPcHRpb25zJDIob3B0aW9ucyk7IC8vIEJlZ2luIGstbWVhbnMgYWxnb3JpdGhtXG5cbiAgICB2YXIgY2x1c3RlcnMgPSBuZXcgQXJyYXkob3B0cy5rKTtcbiAgICB2YXIgYXNzaWdubWVudCA9IHt9O1xuICAgIHZhciBjZW50cm9pZHM7IC8vIFN0ZXAgMTogSW5pdGlhbGl6ZSBjZW50cm9pZCBwb3NpdGlvbnNcblxuICAgIGlmIChvcHRzLnRlc3RNb2RlKSB7XG4gICAgICBpZiAodHlwZW9mIG9wdHMudGVzdENlbnRyb2lkcyA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgLy8gVE9ETzogaW1wbGVtZW50IGEgc2VlZGVkIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yLlxuICAgICAgICBvcHRzLnRlc3RDZW50cm9pZHM7XG4gICAgICAgIGNlbnRyb2lkcyA9IHJhbmRvbUNlbnRyb2lkcyhub2Rlcywgb3B0cy5rLCBvcHRzLmF0dHJpYnV0ZXMpO1xuICAgICAgfSBlbHNlIGlmIChfdHlwZW9mKG9wdHMudGVzdENlbnRyb2lkcykgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIGNlbnRyb2lkcyA9IG9wdHMudGVzdENlbnRyb2lkcztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNlbnRyb2lkcyA9IHJhbmRvbUNlbnRyb2lkcyhub2Rlcywgb3B0cy5rLCBvcHRzLmF0dHJpYnV0ZXMpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBjZW50cm9pZHMgPSByYW5kb21DZW50cm9pZHMobm9kZXMsIG9wdHMuaywgb3B0cy5hdHRyaWJ1dGVzKTtcbiAgICB9XG5cbiAgICB2YXIgaXNTdGlsbE1vdmluZyA9IHRydWU7XG4gICAgdmFyIGl0ZXJhdGlvbnMgPSAwO1xuXG4gICAgd2hpbGUgKGlzU3RpbGxNb3ZpbmcgJiYgaXRlcmF0aW9ucyA8IG9wdHMubWF4SXRlcmF0aW9ucykge1xuICAgICAgLy8gU3RlcCAyOiBBc3NpZ24gbm9kZXMgdG8gdGhlIG5lYXJlc3QgY2VudHJvaWRcbiAgICAgIGZvciAodmFyIG4gPSAwOyBuIDwgbm9kZXMubGVuZ3RoOyBuKyspIHtcbiAgICAgICAgbm9kZSA9IG5vZGVzW25dOyAvLyBEZXRlcm1pbmUgd2hpY2ggY2x1c3RlciB0aGlzIG5vZGUgYmVsb25ncyB0bzogbm9kZSBpZCA9PiBjbHVzdGVyICNcblxuICAgICAgICBhc3NpZ25tZW50W25vZGUuaWQoKV0gPSBjbGFzc2lmeShub2RlLCBjZW50cm9pZHMsIG9wdHMuZGlzdGFuY2UsIG9wdHMuYXR0cmlidXRlcywgJ2tNZWFucycpO1xuICAgICAgfSAvLyBTdGVwIDM6IEZvciBlYWNoIG9mIHRoZSBrIGNsdXN0ZXJzLCB1cGRhdGUgaXRzIGNlbnRyb2lkXG5cblxuICAgICAgaXNTdGlsbE1vdmluZyA9IGZhbHNlO1xuXG4gICAgICBmb3IgKHZhciBjID0gMDsgYyA8IG9wdHMuazsgYysrKSB7XG4gICAgICAgIC8vIEdldCBhbGwgbm9kZXMgdGhhdCBiZWxvbmcgdG8gdGhpcyBjbHVzdGVyXG4gICAgICAgIHZhciBjbHVzdGVyID0gYnVpbGRDbHVzdGVyKGMsIG5vZGVzLCBhc3NpZ25tZW50KTtcblxuICAgICAgICBpZiAoY2x1c3Rlci5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAvLyBJZiBjbHVzdGVyIGlzIGVtcHR5LCBicmVhayBvdXQgZWFybHkgJiBtb3ZlIHRvIG5leHQgY2x1c3RlclxuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9IC8vIFVwZGF0ZSBjZW50cm9pZHMgYnkgY2FsY3VsYXRpbmcgYXZnIG9mIGFsbCBub2RlcyB3aXRoaW4gdGhlIGNsdXN0ZXIuXG5cblxuICAgICAgICB2YXIgbmRpbSA9IG9wdHMuYXR0cmlidXRlcy5sZW5ndGg7XG4gICAgICAgIHZhciBjZW50cm9pZCA9IGNlbnRyb2lkc1tjXTsgLy8gWyBkaW1fMSwgZGltXzIsIGRpbV8zLCAuLi4gLCBkaW1fbiBdXG5cbiAgICAgICAgdmFyIG5ld0NlbnRyb2lkID0gbmV3IEFycmF5KG5kaW0pO1xuICAgICAgICB2YXIgc3VtID0gbmV3IEFycmF5KG5kaW0pO1xuXG4gICAgICAgIGZvciAodmFyIGQgPSAwOyBkIDwgbmRpbTsgZCsrKSB7XG4gICAgICAgICAgc3VtW2RdID0gMC4wO1xuXG4gICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjbHVzdGVyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBub2RlID0gY2x1c3RlcltpXTtcbiAgICAgICAgICAgIHN1bVtkXSArPSBvcHRzLmF0dHJpYnV0ZXNbZF0obm9kZSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgbmV3Q2VudHJvaWRbZF0gPSBzdW1bZF0gLyBjbHVzdGVyLmxlbmd0aDsgLy8gQ2hlY2sgdG8gc2VlIGlmIGFsZ29yaXRobSBoYXMgY29udmVyZ2VkLCBpLmUuIHdoZW4gY2VudHJvaWRzIG5vIGxvbmdlciBjaGFuZ2VcblxuICAgICAgICAgIGlmICghaGF2ZVZhbHVlc0NvbnZlcmdlZChuZXdDZW50cm9pZFtkXSwgY2VudHJvaWRbZF0sIG9wdHMuc2Vuc2l0aXZpdHlUaHJlc2hvbGQpKSB7XG4gICAgICAgICAgICBpc1N0aWxsTW92aW5nID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjZW50cm9pZHNbY10gPSBuZXdDZW50cm9pZDtcbiAgICAgICAgY2x1c3RlcnNbY10gPSBjeS5jb2xsZWN0aW9uKGNsdXN0ZXIpO1xuICAgICAgfVxuXG4gICAgICBpdGVyYXRpb25zKys7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNsdXN0ZXJzO1xuICB9O1xuXG4gIHZhciBrTWVkb2lkcyA9IGZ1bmN0aW9uIGtNZWRvaWRzKG9wdGlvbnMpIHtcbiAgICB2YXIgY3kgPSB0aGlzLmN5KCk7XG4gICAgdmFyIG5vZGVzID0gdGhpcy5ub2RlcygpO1xuICAgIHZhciBub2RlID0gbnVsbDtcbiAgICB2YXIgb3B0cyA9IHNldE9wdGlvbnMkMihvcHRpb25zKTsgLy8gQmVnaW4gay1tZWRvaWRzIGFsZ29yaXRobVxuXG4gICAgdmFyIGNsdXN0ZXJzID0gbmV3IEFycmF5KG9wdHMuayk7XG4gICAgdmFyIG1lZG9pZHM7XG4gICAgdmFyIGFzc2lnbm1lbnQgPSB7fTtcbiAgICB2YXIgY3VyQ29zdDtcbiAgICB2YXIgbWluQ29zdHMgPSBuZXcgQXJyYXkob3B0cy5rKTsgLy8gbWluaW11bSBjb3N0IGNvbmZpZ3VyYXRpb24gZm9yIGVhY2ggY2x1c3RlclxuICAgIC8vIFN0ZXAgMTogSW5pdGlhbGl6ZSBrIG1lZG9pZHNcblxuICAgIGlmIChvcHRzLnRlc3RNb2RlKSB7XG4gICAgICBpZiAodHlwZW9mIG9wdHMudGVzdENlbnRyb2lkcyA9PT0gJ251bWJlcicpIDsgZWxzZSBpZiAoX3R5cGVvZihvcHRzLnRlc3RDZW50cm9pZHMpID09PSAnb2JqZWN0Jykge1xuICAgICAgICBtZWRvaWRzID0gb3B0cy50ZXN0Q2VudHJvaWRzO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbWVkb2lkcyA9IHJhbmRvbU1lZG9pZHMobm9kZXMsIG9wdHMuayk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIG1lZG9pZHMgPSByYW5kb21NZWRvaWRzKG5vZGVzLCBvcHRzLmspO1xuICAgIH1cblxuICAgIHZhciBpc1N0aWxsTW92aW5nID0gdHJ1ZTtcbiAgICB2YXIgaXRlcmF0aW9ucyA9IDA7XG5cbiAgICB3aGlsZSAoaXNTdGlsbE1vdmluZyAmJiBpdGVyYXRpb25zIDwgb3B0cy5tYXhJdGVyYXRpb25zKSB7XG4gICAgICAvLyBTdGVwIDI6IEFzc2lnbiBub2RlcyB0byB0aGUgbmVhcmVzdCBtZWRvaWRcbiAgICAgIGZvciAodmFyIG4gPSAwOyBuIDwgbm9kZXMubGVuZ3RoOyBuKyspIHtcbiAgICAgICAgbm9kZSA9IG5vZGVzW25dOyAvLyBEZXRlcm1pbmUgd2hpY2ggY2x1c3RlciB0aGlzIG5vZGUgYmVsb25ncyB0bzogbm9kZSBpZCA9PiBjbHVzdGVyICNcblxuICAgICAgICBhc3NpZ25tZW50W25vZGUuaWQoKV0gPSBjbGFzc2lmeShub2RlLCBtZWRvaWRzLCBvcHRzLmRpc3RhbmNlLCBvcHRzLmF0dHJpYnV0ZXMsICdrTWVkb2lkcycpO1xuICAgICAgfVxuXG4gICAgICBpc1N0aWxsTW92aW5nID0gZmFsc2U7IC8vIFN0ZXAgMzogRm9yIGVhY2ggbWVkb2lkIG0sIGFuZCBmb3IgZWFjaCBub2RlIGFzc29jaWF0ZWQgd2l0aCBtZWRpb2QgbSxcbiAgICAgIC8vIHNlbGVjdCB0aGUgbm9kZSB3aXRoIHRoZSBsb3dlc3QgY29uZmlndXJhdGlvbiBjb3N0IGFzIG5ldyBtZWRvaWQuXG5cbiAgICAgIGZvciAodmFyIG0gPSAwOyBtIDwgbWVkb2lkcy5sZW5ndGg7IG0rKykge1xuICAgICAgICAvLyBHZXQgYWxsIG5vZGVzIHRoYXQgYmVsb25nIHRvIHRoaXMgbWVkb2lkXG4gICAgICAgIHZhciBjbHVzdGVyID0gYnVpbGRDbHVzdGVyKG0sIG5vZGVzLCBhc3NpZ25tZW50KTtcblxuICAgICAgICBpZiAoY2x1c3Rlci5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAvLyBJZiBjbHVzdGVyIGlzIGVtcHR5LCBicmVhayBvdXQgZWFybHkgJiBtb3ZlIHRvIG5leHQgY2x1c3RlclxuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgbWluQ29zdHNbbV0gPSBmaW5kQ29zdChtZWRvaWRzW21dLCBjbHVzdGVyLCBvcHRzLmF0dHJpYnV0ZXMpOyAvLyBvcmlnaW5hbCBjb3N0XG4gICAgICAgIC8vIFNlbGVjdCBkaWZmZXJlbnQgbWVkb2lkIGlmIGl0cyBjb25maWd1cmF0aW9uIGhhcyB0aGUgbG93ZXN0IGNvc3RcblxuICAgICAgICBmb3IgKHZhciBfbiA9IDA7IF9uIDwgY2x1c3Rlci5sZW5ndGg7IF9uKyspIHtcbiAgICAgICAgICBjdXJDb3N0ID0gZmluZENvc3QoY2x1c3Rlcltfbl0sIGNsdXN0ZXIsIG9wdHMuYXR0cmlidXRlcyk7XG5cbiAgICAgICAgICBpZiAoY3VyQ29zdCA8IG1pbkNvc3RzW21dKSB7XG4gICAgICAgICAgICBtaW5Db3N0c1ttXSA9IGN1ckNvc3Q7XG4gICAgICAgICAgICBtZWRvaWRzW21dID0gY2x1c3Rlcltfbl07XG4gICAgICAgICAgICBpc1N0aWxsTW92aW5nID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjbHVzdGVyc1ttXSA9IGN5LmNvbGxlY3Rpb24oY2x1c3Rlcik7XG4gICAgICB9XG5cbiAgICAgIGl0ZXJhdGlvbnMrKztcbiAgICB9XG5cbiAgICByZXR1cm4gY2x1c3RlcnM7XG4gIH07XG5cbiAgdmFyIHVwZGF0ZUNlbnRyb2lkcyA9IGZ1bmN0aW9uIHVwZGF0ZUNlbnRyb2lkcyhjZW50cm9pZHMsIG5vZGVzLCBVLCB3ZWlnaHQsIG9wdHMpIHtcbiAgICB2YXIgbnVtZXJhdG9yLCBkZW5vbWluYXRvcjtcblxuICAgIGZvciAodmFyIG4gPSAwOyBuIDwgbm9kZXMubGVuZ3RoOyBuKyspIHtcbiAgICAgIGZvciAodmFyIGMgPSAwOyBjIDwgY2VudHJvaWRzLmxlbmd0aDsgYysrKSB7XG4gICAgICAgIHdlaWdodFtuXVtjXSA9IE1hdGgucG93KFVbbl1bY10sIG9wdHMubSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yICh2YXIgX2MgPSAwOyBfYyA8IGNlbnRyb2lkcy5sZW5ndGg7IF9jKyspIHtcbiAgICAgIGZvciAodmFyIGRpbSA9IDA7IGRpbSA8IG9wdHMuYXR0cmlidXRlcy5sZW5ndGg7IGRpbSsrKSB7XG4gICAgICAgIG51bWVyYXRvciA9IDA7XG4gICAgICAgIGRlbm9taW5hdG9yID0gMDtcblxuICAgICAgICBmb3IgKHZhciBfbjIgPSAwOyBfbjIgPCBub2Rlcy5sZW5ndGg7IF9uMisrKSB7XG4gICAgICAgICAgbnVtZXJhdG9yICs9IHdlaWdodFtfbjJdW19jXSAqIG9wdHMuYXR0cmlidXRlc1tkaW1dKG5vZGVzW19uMl0pO1xuICAgICAgICAgIGRlbm9taW5hdG9yICs9IHdlaWdodFtfbjJdW19jXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNlbnRyb2lkc1tfY11bZGltXSA9IG51bWVyYXRvciAvIGRlbm9taW5hdG9yO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICB2YXIgdXBkYXRlTWVtYmVyc2hpcCA9IGZ1bmN0aW9uIHVwZGF0ZU1lbWJlcnNoaXAoVSwgX1UsIGNlbnRyb2lkcywgbm9kZXMsIG9wdHMpIHtcbiAgICAvLyBTYXZlIHByZXZpb3VzIHN0ZXBcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IFUubGVuZ3RoOyBpKyspIHtcbiAgICAgIF9VW2ldID0gVVtpXS5zbGljZSgpO1xuICAgIH1cblxuICAgIHZhciBzdW0sIG51bWVyYXRvciwgZGVub21pbmF0b3I7XG4gICAgdmFyIHBvdyA9IDIgLyAob3B0cy5tIC0gMSk7XG5cbiAgICBmb3IgKHZhciBjID0gMDsgYyA8IGNlbnRyb2lkcy5sZW5ndGg7IGMrKykge1xuICAgICAgZm9yICh2YXIgbiA9IDA7IG4gPCBub2Rlcy5sZW5ndGg7IG4rKykge1xuICAgICAgICBzdW0gPSAwO1xuXG4gICAgICAgIGZvciAodmFyIGsgPSAwOyBrIDwgY2VudHJvaWRzLmxlbmd0aDsgaysrKSB7XG4gICAgICAgICAgLy8gYWdhaW5zdCBhbGwgb3RoZXIgY2VudHJvaWRzXG4gICAgICAgICAgbnVtZXJhdG9yID0gZ2V0RGlzdChvcHRzLmRpc3RhbmNlLCBub2Rlc1tuXSwgY2VudHJvaWRzW2NdLCBvcHRzLmF0dHJpYnV0ZXMsICdjbWVhbnMnKTtcbiAgICAgICAgICBkZW5vbWluYXRvciA9IGdldERpc3Qob3B0cy5kaXN0YW5jZSwgbm9kZXNbbl0sIGNlbnRyb2lkc1trXSwgb3B0cy5hdHRyaWJ1dGVzLCAnY21lYW5zJyk7XG4gICAgICAgICAgc3VtICs9IE1hdGgucG93KG51bWVyYXRvciAvIGRlbm9taW5hdG9yLCBwb3cpO1xuICAgICAgICB9XG5cbiAgICAgICAgVVtuXVtjXSA9IDEgLyBzdW07XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIHZhciBhc3NpZ24kMSA9IGZ1bmN0aW9uIGFzc2lnbihub2RlcywgVSwgb3B0cywgY3kpIHtcbiAgICB2YXIgY2x1c3RlcnMgPSBuZXcgQXJyYXkob3B0cy5rKTtcblxuICAgIGZvciAodmFyIGMgPSAwOyBjIDwgY2x1c3RlcnMubGVuZ3RoOyBjKyspIHtcbiAgICAgIGNsdXN0ZXJzW2NdID0gW107XG4gICAgfVxuXG4gICAgdmFyIG1heDtcbiAgICB2YXIgaW5kZXg7XG5cbiAgICBmb3IgKHZhciBuID0gMDsgbiA8IFUubGVuZ3RoOyBuKyspIHtcbiAgICAgIC8vIGZvciBlYWNoIG5vZGUgKFUgaXMgTiB4IEMgbWF0cml4KVxuICAgICAgbWF4ID0gLUluZmluaXR5O1xuICAgICAgaW5kZXggPSAtMTsgLy8gRGV0ZXJtaW5lIHdoaWNoIGNsdXN0ZXIgdGhlIG5vZGUgaXMgbW9zdCBsaWtlbHkgdG8gYmVsb25nIGluXG5cbiAgICAgIGZvciAodmFyIF9jMiA9IDA7IF9jMiA8IFVbMF0ubGVuZ3RoOyBfYzIrKykge1xuICAgICAgICBpZiAoVVtuXVtfYzJdID4gbWF4KSB7XG4gICAgICAgICAgbWF4ID0gVVtuXVtfYzJdO1xuICAgICAgICAgIGluZGV4ID0gX2MyO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNsdXN0ZXJzW2luZGV4XS5wdXNoKG5vZGVzW25dKTtcbiAgICB9IC8vIFR1cm4gZXZlcnkgYXJyYXkgaW50byBhIGNvbGxlY3Rpb24gb2Ygbm9kZXNcblxuXG4gICAgZm9yICh2YXIgX2MzID0gMDsgX2MzIDwgY2x1c3RlcnMubGVuZ3RoOyBfYzMrKykge1xuICAgICAgY2x1c3RlcnNbX2MzXSA9IGN5LmNvbGxlY3Rpb24oY2x1c3RlcnNbX2MzXSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNsdXN0ZXJzO1xuICB9O1xuXG4gIHZhciBmdXp6eUNNZWFucyA9IGZ1bmN0aW9uIGZ1enp5Q01lYW5zKG9wdGlvbnMpIHtcbiAgICB2YXIgY3kgPSB0aGlzLmN5KCk7XG4gICAgdmFyIG5vZGVzID0gdGhpcy5ub2RlcygpO1xuICAgIHZhciBvcHRzID0gc2V0T3B0aW9ucyQyKG9wdGlvbnMpOyAvLyBCZWdpbiBmdXp6eSBjLW1lYW5zIGFsZ29yaXRobVxuXG4gICAgdmFyIGNsdXN0ZXJzO1xuICAgIHZhciBjZW50cm9pZHM7XG4gICAgdmFyIFU7XG5cbiAgICB2YXIgX1U7XG5cbiAgICB2YXIgd2VpZ2h0OyAvLyBTdGVwIDE6IEluaXRpYWxpemUgbGV0aWFibGVzLlxuXG4gICAgX1UgPSBuZXcgQXJyYXkobm9kZXMubGVuZ3RoKTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIC8vIE4geCBDIG1hdHJpeFxuICAgICAgX1VbaV0gPSBuZXcgQXJyYXkob3B0cy5rKTtcbiAgICB9XG5cbiAgICBVID0gbmV3IEFycmF5KG5vZGVzLmxlbmd0aCk7XG5cbiAgICBmb3IgKHZhciBfaTMgPSAwOyBfaTMgPCBub2Rlcy5sZW5ndGg7IF9pMysrKSB7XG4gICAgICAvLyBOIHggQyBtYXRyaXhcbiAgICAgIFVbX2kzXSA9IG5ldyBBcnJheShvcHRzLmspO1xuICAgIH1cblxuICAgIGZvciAodmFyIF9pNCA9IDA7IF9pNCA8IG5vZGVzLmxlbmd0aDsgX2k0KyspIHtcbiAgICAgIHZhciB0b3RhbCA9IDA7XG5cbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgb3B0cy5rOyBqKyspIHtcbiAgICAgICAgVVtfaTRdW2pdID0gTWF0aC5yYW5kb20oKTtcbiAgICAgICAgdG90YWwgKz0gVVtfaTRdW2pdO1xuICAgICAgfVxuXG4gICAgICBmb3IgKHZhciBfaiA9IDA7IF9qIDwgb3B0cy5rOyBfaisrKSB7XG4gICAgICAgIFVbX2k0XVtfal0gPSBVW19pNF1bX2pdIC8gdG90YWw7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY2VudHJvaWRzID0gbmV3IEFycmF5KG9wdHMuayk7XG5cbiAgICBmb3IgKHZhciBfaTUgPSAwOyBfaTUgPCBvcHRzLms7IF9pNSsrKSB7XG4gICAgICBjZW50cm9pZHNbX2k1XSA9IG5ldyBBcnJheShvcHRzLmF0dHJpYnV0ZXMubGVuZ3RoKTtcbiAgICB9XG5cbiAgICB3ZWlnaHQgPSBuZXcgQXJyYXkobm9kZXMubGVuZ3RoKTtcblxuICAgIGZvciAodmFyIF9pNiA9IDA7IF9pNiA8IG5vZGVzLmxlbmd0aDsgX2k2KyspIHtcbiAgICAgIC8vIE4geCBDIG1hdHJpeFxuICAgICAgd2VpZ2h0W19pNl0gPSBuZXcgQXJyYXkob3B0cy5rKTtcbiAgICB9IC8vIGVuZCBpbml0IEZDTVxuXG5cbiAgICB2YXIgaXNTdGlsbE1vdmluZyA9IHRydWU7XG4gICAgdmFyIGl0ZXJhdGlvbnMgPSAwO1xuXG4gICAgd2hpbGUgKGlzU3RpbGxNb3ZpbmcgJiYgaXRlcmF0aW9ucyA8IG9wdHMubWF4SXRlcmF0aW9ucykge1xuICAgICAgaXNTdGlsbE1vdmluZyA9IGZhbHNlOyAvLyBTdGVwIDI6IENhbGN1bGF0ZSB0aGUgY2VudHJvaWRzIGZvciBlYWNoIHN0ZXAuXG5cbiAgICAgIHVwZGF0ZUNlbnRyb2lkcyhjZW50cm9pZHMsIG5vZGVzLCBVLCB3ZWlnaHQsIG9wdHMpOyAvLyBTdGVwIDM6IFVwZGF0ZSB0aGUgcGFydGl0aW9uIG1hdHJpeCBVLlxuXG4gICAgICB1cGRhdGVNZW1iZXJzaGlwKFUsIF9VLCBjZW50cm9pZHMsIG5vZGVzLCBvcHRzKTsgLy8gU3RlcCA0OiBDaGVjayBmb3IgY29udmVyZ2VuY2UuXG5cbiAgICAgIGlmICghaGF2ZU1hdHJpY2VzQ29udmVyZ2VkKFUsIF9VLCBvcHRzLnNlbnNpdGl2aXR5VGhyZXNob2xkKSkge1xuICAgICAgICBpc1N0aWxsTW92aW5nID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgaXRlcmF0aW9ucysrO1xuICAgIH0gLy8gQXNzaWduIG5vZGVzIHRvIGNsdXN0ZXJzIHdpdGggaGlnaGVzdCBwcm9iYWJpbGl0eS5cblxuXG4gICAgY2x1c3RlcnMgPSBhc3NpZ24kMShub2RlcywgVSwgb3B0cywgY3kpO1xuICAgIHJldHVybiB7XG4gICAgICBjbHVzdGVyczogY2x1c3RlcnMsXG4gICAgICBkZWdyZWVPZk1lbWJlcnNoaXA6IFVcbiAgICB9O1xuICB9O1xuXG4gIHZhciBrQ2x1c3RlcmluZyA9IHtcbiAgICBrTWVhbnM6IGtNZWFucyxcbiAgICBrTWVkb2lkczoga01lZG9pZHMsXG4gICAgZnV6enlDTWVhbnM6IGZ1enp5Q01lYW5zLFxuICAgIGZjbTogZnV6enlDTWVhbnNcbiAgfTtcblxuICAvLyBJbXBsZW1lbnRlZCBieSBab2UgWGkgQHpvZXhpIGZvciBHU09DIDIwMTZcbiAgdmFyIGRlZmF1bHRzJGEgPSBkZWZhdWx0cyRnKHtcbiAgICBkaXN0YW5jZTogJ2V1Y2xpZGVhbicsXG4gICAgLy8gZGlzdGFuY2UgbWV0cmljIHRvIGNvbXBhcmUgbm9kZXNcbiAgICBsaW5rYWdlOiAnbWluJyxcbiAgICAvLyBsaW5rYWdlIGNyaXRlcmlvbiA6IGhvdyB0byBkZXRlcm1pbmUgdGhlIGRpc3RhbmNlIGJldHdlZW4gY2x1c3RlcnMgb2Ygbm9kZXNcbiAgICBtb2RlOiAndGhyZXNob2xkJyxcbiAgICAvLyBtb2RlOid0aHJlc2hvbGQnID0+IGNsdXN0ZXJzIG11c3QgYmUgdGhyZXNob2xkIGRpc3RhbmNlIGFwYXJ0XG4gICAgdGhyZXNob2xkOiBJbmZpbml0eSxcbiAgICAvLyB0aGUgZGlzdGFuY2UgdGhyZXNob2xkXG4gICAgLy8gbW9kZTonZGVuZHJvZ3JhbScgPT4gdGhlIG5vZGVzIGFyZSBvcmdhbmlzZWQgYXMgbGVhdmVzIGluIGEgdHJlZSAoc2libGluZ3MgYXJlIGNsb3NlKSwgbWVyZ2luZyBtYWtlcyBjbHVzdGVyc1xuICAgIGFkZERlbmRyb2dyYW06IGZhbHNlLFxuICAgIC8vIHdoZXRoZXIgdG8gYWRkIHRoZSBkZW5kcm9ncmFtIHRvIHRoZSBncmFwaCBmb3Igdml6XG4gICAgZGVuZHJvZ3JhbURlcHRoOiAwLFxuICAgIC8vIGRlcHRoIGF0IHdoaWNoIGRlbmRyb2dyYW0gYnJhbmNoZXMgYXJlIG1lcmdlZCBpbnRvIHRoZSByZXR1cm5lZCBjbHVzdGVyc1xuICAgIGF0dHJpYnV0ZXM6IFtdIC8vIGFycmF5IG9mIGF0dHIgZnVuY3Rpb25zXG5cbiAgfSk7XG4gIHZhciBsaW5rYWdlQWxpYXNlcyA9IHtcbiAgICAnc2luZ2xlJzogJ21pbicsXG4gICAgJ2NvbXBsZXRlJzogJ21heCdcbiAgfTtcblxuICB2YXIgc2V0T3B0aW9ucyQxID0gZnVuY3Rpb24gc2V0T3B0aW9ucyhvcHRpb25zKSB7XG4gICAgdmFyIG9wdHMgPSBkZWZhdWx0cyRhKG9wdGlvbnMpO1xuICAgIHZhciBwcmVmZXJyZWRBbGlhcyA9IGxpbmthZ2VBbGlhc2VzW29wdHMubGlua2FnZV07XG5cbiAgICBpZiAocHJlZmVycmVkQWxpYXMgIT0gbnVsbCkge1xuICAgICAgb3B0cy5saW5rYWdlID0gcHJlZmVycmVkQWxpYXM7XG4gICAgfVxuXG4gICAgcmV0dXJuIG9wdHM7XG4gIH07XG5cbiAgdmFyIG1lcmdlQ2xvc2VzdCA9IGZ1bmN0aW9uIG1lcmdlQ2xvc2VzdChjbHVzdGVycywgaW5kZXgsIGRpc3RzLCBtaW5zLCBvcHRzKSB7XG4gICAgLy8gRmluZCB0d28gY2xvc2VzdCBjbHVzdGVycyBmcm9tIGNhY2hlZCBtaW5zXG4gICAgdmFyIG1pbktleSA9IDA7XG4gICAgdmFyIG1pbiA9IEluZmluaXR5O1xuICAgIHZhciBkaXN0O1xuICAgIHZhciBhdHRycyA9IG9wdHMuYXR0cmlidXRlcztcblxuICAgIHZhciBnZXREaXN0ID0gZnVuY3Rpb24gZ2V0RGlzdChuMSwgbjIpIHtcbiAgICAgIHJldHVybiBjbHVzdGVyaW5nRGlzdGFuY2Uob3B0cy5kaXN0YW5jZSwgYXR0cnMubGVuZ3RoLCBmdW5jdGlvbiAoaSkge1xuICAgICAgICByZXR1cm4gYXR0cnNbaV0objEpO1xuICAgICAgfSwgZnVuY3Rpb24gKGkpIHtcbiAgICAgICAgcmV0dXJuIGF0dHJzW2ldKG4yKTtcbiAgICAgIH0sIG4xLCBuMik7XG4gICAgfTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2x1c3RlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBrZXkgPSBjbHVzdGVyc1tpXS5rZXk7XG4gICAgICB2YXIgX2Rpc3QgPSBkaXN0c1trZXldW21pbnNba2V5XV07XG5cbiAgICAgIGlmIChfZGlzdCA8IG1pbikge1xuICAgICAgICBtaW5LZXkgPSBrZXk7XG4gICAgICAgIG1pbiA9IF9kaXN0O1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChvcHRzLm1vZGUgPT09ICd0aHJlc2hvbGQnICYmIG1pbiA+PSBvcHRzLnRocmVzaG9sZCB8fCBvcHRzLm1vZGUgPT09ICdkZW5kcm9ncmFtJyAmJiBjbHVzdGVycy5sZW5ndGggPT09IDEpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB2YXIgYzEgPSBpbmRleFttaW5LZXldO1xuICAgIHZhciBjMiA9IGluZGV4W21pbnNbbWluS2V5XV07XG4gICAgdmFyIG1lcmdlZDsgLy8gTWVyZ2UgdHdvIGNsb3Nlc3QgY2x1c3RlcnNcblxuICAgIGlmIChvcHRzLm1vZGUgPT09ICdkZW5kcm9ncmFtJykge1xuICAgICAgbWVyZ2VkID0ge1xuICAgICAgICBsZWZ0OiBjMSxcbiAgICAgICAgcmlnaHQ6IGMyLFxuICAgICAgICBrZXk6IGMxLmtleVxuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgbWVyZ2VkID0ge1xuICAgICAgICB2YWx1ZTogYzEudmFsdWUuY29uY2F0KGMyLnZhbHVlKSxcbiAgICAgICAga2V5OiBjMS5rZXlcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY2x1c3RlcnNbYzEuaW5kZXhdID0gbWVyZ2VkO1xuICAgIGNsdXN0ZXJzLnNwbGljZShjMi5pbmRleCwgMSk7XG4gICAgaW5kZXhbYzEua2V5XSA9IG1lcmdlZDsgLy8gVXBkYXRlIGRpc3RhbmNlcyB3aXRoIG5ldyBtZXJnZWQgY2x1c3RlclxuXG4gICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IGNsdXN0ZXJzLmxlbmd0aDsgX2krKykge1xuICAgICAgdmFyIGN1ciA9IGNsdXN0ZXJzW19pXTtcblxuICAgICAgaWYgKGMxLmtleSA9PT0gY3VyLmtleSkge1xuICAgICAgICBkaXN0ID0gSW5maW5pdHk7XG4gICAgICB9IGVsc2UgaWYgKG9wdHMubGlua2FnZSA9PT0gJ21pbicpIHtcbiAgICAgICAgZGlzdCA9IGRpc3RzW2MxLmtleV1bY3VyLmtleV07XG5cbiAgICAgICAgaWYgKGRpc3RzW2MxLmtleV1bY3VyLmtleV0gPiBkaXN0c1tjMi5rZXldW2N1ci5rZXldKSB7XG4gICAgICAgICAgZGlzdCA9IGRpc3RzW2MyLmtleV1bY3VyLmtleV07XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAob3B0cy5saW5rYWdlID09PSAnbWF4Jykge1xuICAgICAgICBkaXN0ID0gZGlzdHNbYzEua2V5XVtjdXIua2V5XTtcblxuICAgICAgICBpZiAoZGlzdHNbYzEua2V5XVtjdXIua2V5XSA8IGRpc3RzW2MyLmtleV1bY3VyLmtleV0pIHtcbiAgICAgICAgICBkaXN0ID0gZGlzdHNbYzIua2V5XVtjdXIua2V5XTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChvcHRzLmxpbmthZ2UgPT09ICdtZWFuJykge1xuICAgICAgICBkaXN0ID0gKGRpc3RzW2MxLmtleV1bY3VyLmtleV0gKiBjMS5zaXplICsgZGlzdHNbYzIua2V5XVtjdXIua2V5XSAqIGMyLnNpemUpIC8gKGMxLnNpemUgKyBjMi5zaXplKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChvcHRzLm1vZGUgPT09ICdkZW5kcm9ncmFtJykgZGlzdCA9IGdldERpc3QoY3VyLnZhbHVlLCBjMS52YWx1ZSk7ZWxzZSBkaXN0ID0gZ2V0RGlzdChjdXIudmFsdWVbMF0sIGMxLnZhbHVlWzBdKTtcbiAgICAgIH1cblxuICAgICAgZGlzdHNbYzEua2V5XVtjdXIua2V5XSA9IGRpc3RzW2N1ci5rZXldW2MxLmtleV0gPSBkaXN0OyAvLyBkaXN0YW5jZSBtYXRyaXggaXMgc3ltbWV0cmljXG4gICAgfSAvLyBVcGRhdGUgY2FjaGVkIG1pbnNcblxuXG4gICAgZm9yICh2YXIgX2kyID0gMDsgX2kyIDwgY2x1c3RlcnMubGVuZ3RoOyBfaTIrKykge1xuICAgICAgdmFyIGtleTEgPSBjbHVzdGVyc1tfaTJdLmtleTtcblxuICAgICAgaWYgKG1pbnNba2V5MV0gPT09IGMxLmtleSB8fCBtaW5zW2tleTFdID09PSBjMi5rZXkpIHtcbiAgICAgICAgdmFyIF9taW4gPSBrZXkxO1xuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgY2x1c3RlcnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICB2YXIga2V5MiA9IGNsdXN0ZXJzW2pdLmtleTtcblxuICAgICAgICAgIGlmIChkaXN0c1trZXkxXVtrZXkyXSA8IGRpc3RzW2tleTFdW19taW5dKSB7XG4gICAgICAgICAgICBfbWluID0ga2V5MjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBtaW5zW2tleTFdID0gX21pbjtcbiAgICAgIH1cblxuICAgICAgY2x1c3RlcnNbX2kyXS5pbmRleCA9IF9pMjtcbiAgICB9IC8vIENsZWFuIHVwIG1ldGEgZGF0YSB1c2VkIGZvciBjbHVzdGVyaW5nXG5cblxuICAgIGMxLmtleSA9IGMyLmtleSA9IGMxLmluZGV4ID0gYzIuaW5kZXggPSBudWxsO1xuICAgIHJldHVybiB0cnVlO1xuICB9O1xuXG4gIHZhciBnZXRBbGxDaGlsZHJlbiA9IGZ1bmN0aW9uIGdldEFsbENoaWxkcmVuKHJvb3QsIGFyciwgY3kpIHtcbiAgICBpZiAoIXJvb3QpIHJldHVybjtcblxuICAgIGlmIChyb290LnZhbHVlKSB7XG4gICAgICBhcnIucHVzaChyb290LnZhbHVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHJvb3QubGVmdCkgZ2V0QWxsQ2hpbGRyZW4ocm9vdC5sZWZ0LCBhcnIpO1xuICAgICAgaWYgKHJvb3QucmlnaHQpIGdldEFsbENoaWxkcmVuKHJvb3QucmlnaHQsIGFycik7XG4gICAgfVxuICB9O1xuXG4gIHZhciBidWlsZERlbmRyb2dyYW0gPSBmdW5jdGlvbiBidWlsZERlbmRyb2dyYW0ocm9vdCwgY3kpIHtcbiAgICBpZiAoIXJvb3QpIHJldHVybiAnJztcblxuICAgIGlmIChyb290LmxlZnQgJiYgcm9vdC5yaWdodCkge1xuICAgICAgdmFyIGxlZnRTdHIgPSBidWlsZERlbmRyb2dyYW0ocm9vdC5sZWZ0LCBjeSk7XG4gICAgICB2YXIgcmlnaHRTdHIgPSBidWlsZERlbmRyb2dyYW0ocm9vdC5yaWdodCwgY3kpO1xuICAgICAgdmFyIG5vZGUgPSBjeS5hZGQoe1xuICAgICAgICBncm91cDogJ25vZGVzJyxcbiAgICAgICAgZGF0YToge1xuICAgICAgICAgIGlkOiBsZWZ0U3RyICsgJywnICsgcmlnaHRTdHJcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICBjeS5hZGQoe1xuICAgICAgICBncm91cDogJ2VkZ2VzJyxcbiAgICAgICAgZGF0YToge1xuICAgICAgICAgIHNvdXJjZTogbGVmdFN0cixcbiAgICAgICAgICB0YXJnZXQ6IG5vZGUuaWQoKVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGN5LmFkZCh7XG4gICAgICAgIGdyb3VwOiAnZWRnZXMnLFxuICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgc291cmNlOiByaWdodFN0cixcbiAgICAgICAgICB0YXJnZXQ6IG5vZGUuaWQoKVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHJldHVybiBub2RlLmlkKCk7XG4gICAgfSBlbHNlIGlmIChyb290LnZhbHVlKSB7XG4gICAgICByZXR1cm4gcm9vdC52YWx1ZS5pZCgpO1xuICAgIH1cbiAgfTtcblxuICB2YXIgYnVpbGRDbHVzdGVyc0Zyb21UcmVlID0gZnVuY3Rpb24gYnVpbGRDbHVzdGVyc0Zyb21UcmVlKHJvb3QsIGssIGN5KSB7XG4gICAgaWYgKCFyb290KSByZXR1cm4gW107XG4gICAgdmFyIGxlZnQgPSBbXSxcbiAgICAgICAgcmlnaHQgPSBbXSxcbiAgICAgICAgbGVhdmVzID0gW107XG5cbiAgICBpZiAoayA9PT0gMCkge1xuICAgICAgLy8gZG9uJ3QgY3V0IHRyZWUsIHNpbXBseSByZXR1cm4gYWxsIG5vZGVzIGFzIDEgc2luZ2xlIGNsdXN0ZXJcbiAgICAgIGlmIChyb290LmxlZnQpIGdldEFsbENoaWxkcmVuKHJvb3QubGVmdCwgbGVmdCk7XG4gICAgICBpZiAocm9vdC5yaWdodCkgZ2V0QWxsQ2hpbGRyZW4ocm9vdC5yaWdodCwgcmlnaHQpO1xuICAgICAgbGVhdmVzID0gbGVmdC5jb25jYXQocmlnaHQpO1xuICAgICAgcmV0dXJuIFtjeS5jb2xsZWN0aW9uKGxlYXZlcyldO1xuICAgIH0gZWxzZSBpZiAoayA9PT0gMSkge1xuICAgICAgLy8gY3V0IGF0IHJvb3RcbiAgICAgIGlmIChyb290LnZhbHVlKSB7XG4gICAgICAgIC8vIGxlYWYgbm9kZVxuICAgICAgICByZXR1cm4gW2N5LmNvbGxlY3Rpb24ocm9vdC52YWx1ZSldO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHJvb3QubGVmdCkgZ2V0QWxsQ2hpbGRyZW4ocm9vdC5sZWZ0LCBsZWZ0KTtcbiAgICAgICAgaWYgKHJvb3QucmlnaHQpIGdldEFsbENoaWxkcmVuKHJvb3QucmlnaHQsIHJpZ2h0KTtcbiAgICAgICAgcmV0dXJuIFtjeS5jb2xsZWN0aW9uKGxlZnQpLCBjeS5jb2xsZWN0aW9uKHJpZ2h0KV07XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmIChyb290LnZhbHVlKSB7XG4gICAgICAgIHJldHVybiBbY3kuY29sbGVjdGlvbihyb290LnZhbHVlKV07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAocm9vdC5sZWZ0KSBsZWZ0ID0gYnVpbGRDbHVzdGVyc0Zyb21UcmVlKHJvb3QubGVmdCwgayAtIDEsIGN5KTtcbiAgICAgICAgaWYgKHJvb3QucmlnaHQpIHJpZ2h0ID0gYnVpbGRDbHVzdGVyc0Zyb21UcmVlKHJvb3QucmlnaHQsIGsgLSAxLCBjeSk7XG4gICAgICAgIHJldHVybiBsZWZ0LmNvbmNhdChyaWdodCk7XG4gICAgICB9XG4gICAgfVxuICB9O1xuICAvKiBlc2xpbnQtZW5hYmxlICovXG5cblxuICB2YXIgaGllcmFyY2hpY2FsQ2x1c3RlcmluZyA9IGZ1bmN0aW9uIGhpZXJhcmNoaWNhbENsdXN0ZXJpbmcob3B0aW9ucykge1xuICAgIHZhciBjeSA9IHRoaXMuY3koKTtcbiAgICB2YXIgbm9kZXMgPSB0aGlzLm5vZGVzKCk7IC8vIFNldCBwYXJhbWV0ZXJzIG9mIGFsZ29yaXRobTogbGlua2FnZSB0eXBlLCBkaXN0YW5jZSBtZXRyaWMsIGV0Yy5cblxuICAgIHZhciBvcHRzID0gc2V0T3B0aW9ucyQxKG9wdGlvbnMpO1xuICAgIHZhciBhdHRycyA9IG9wdHMuYXR0cmlidXRlcztcblxuICAgIHZhciBnZXREaXN0ID0gZnVuY3Rpb24gZ2V0RGlzdChuMSwgbjIpIHtcbiAgICAgIHJldHVybiBjbHVzdGVyaW5nRGlzdGFuY2Uob3B0cy5kaXN0YW5jZSwgYXR0cnMubGVuZ3RoLCBmdW5jdGlvbiAoaSkge1xuICAgICAgICByZXR1cm4gYXR0cnNbaV0objEpO1xuICAgICAgfSwgZnVuY3Rpb24gKGkpIHtcbiAgICAgICAgcmV0dXJuIGF0dHJzW2ldKG4yKTtcbiAgICAgIH0sIG4xLCBuMik7XG4gICAgfTsgLy8gQmVnaW4gaGllcmFyY2hpY2FsIGFsZ29yaXRobVxuXG5cbiAgICB2YXIgY2x1c3RlcnMgPSBbXTtcbiAgICB2YXIgZGlzdHMgPSBbXTsgLy8gZGlzdGFuY2VzIGJldHdlZW4gZWFjaCBwYWlyIG9mIGNsdXN0ZXJzXG5cbiAgICB2YXIgbWlucyA9IFtdOyAvLyBjbG9zZXN0IGNsdXN0ZXIgZm9yIGVhY2ggY2x1c3RlclxuXG4gICAgdmFyIGluZGV4ID0gW107IC8vIGhhc2ggb2YgYWxsIGNsdXN0ZXJzIGJ5IGtleVxuICAgIC8vIEluIGFnZ2xvbWVyYXRpdmUgKGJvdHRvbS11cCkgY2x1c3RlcmluZywgZWFjaCBub2RlIHN0YXJ0cyBhcyBpdHMgb3duIGNsdXN0ZXJcblxuICAgIGZvciAodmFyIG4gPSAwOyBuIDwgbm9kZXMubGVuZ3RoOyBuKyspIHtcbiAgICAgIHZhciBjbHVzdGVyID0ge1xuICAgICAgICB2YWx1ZTogb3B0cy5tb2RlID09PSAnZGVuZHJvZ3JhbScgPyBub2Rlc1tuXSA6IFtub2Rlc1tuXV0sXG4gICAgICAgIGtleTogbixcbiAgICAgICAgaW5kZXg6IG5cbiAgICAgIH07XG4gICAgICBjbHVzdGVyc1tuXSA9IGNsdXN0ZXI7XG4gICAgICBpbmRleFtuXSA9IGNsdXN0ZXI7XG4gICAgICBkaXN0c1tuXSA9IFtdO1xuICAgICAgbWluc1tuXSA9IDA7XG4gICAgfSAvLyBDYWxjdWxhdGUgdGhlIGRpc3RhbmNlIGJldHdlZW4gZWFjaCBwYWlyIG9mIGNsdXN0ZXJzXG5cblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2x1c3RlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDw9IGk7IGorKykge1xuICAgICAgICB2YXIgZGlzdCA9IHZvaWQgMDtcblxuICAgICAgICBpZiAob3B0cy5tb2RlID09PSAnZGVuZHJvZ3JhbScpIHtcbiAgICAgICAgICAvLyBtb2RlcyBzdG9yZSBjbHVzdGVyIHZhbHVlcyBkaWZmZXJlbnRseVxuICAgICAgICAgIGRpc3QgPSBpID09PSBqID8gSW5maW5pdHkgOiBnZXREaXN0KGNsdXN0ZXJzW2ldLnZhbHVlLCBjbHVzdGVyc1tqXS52YWx1ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZGlzdCA9IGkgPT09IGogPyBJbmZpbml0eSA6IGdldERpc3QoY2x1c3RlcnNbaV0udmFsdWVbMF0sIGNsdXN0ZXJzW2pdLnZhbHVlWzBdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGRpc3RzW2ldW2pdID0gZGlzdDtcbiAgICAgICAgZGlzdHNbal1baV0gPSBkaXN0O1xuXG4gICAgICAgIGlmIChkaXN0IDwgZGlzdHNbaV1bbWluc1tpXV0pIHtcbiAgICAgICAgICBtaW5zW2ldID0gajsgLy8gQ2FjaGUgbWluczogY2xvc2VzdCBjbHVzdGVyIHRvIGNsdXN0ZXIgaSBpcyBjbHVzdGVyIGpcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gLy8gRmluZCB0aGUgY2xvc2VzdCBwYWlyIG9mIGNsdXN0ZXJzIGFuZCBtZXJnZSB0aGVtIGludG8gYSBzaW5nbGUgY2x1c3Rlci5cbiAgICAvLyBVcGRhdGUgZGlzdGFuY2VzIGJldHdlZW4gbmV3IGNsdXN0ZXIgYW5kIGVhY2ggb2YgdGhlIG9sZCBjbHVzdGVycywgYW5kIGxvb3AgdW50aWwgdGhyZXNob2xkIHJlYWNoZWQuXG5cblxuICAgIHZhciBtZXJnZWQgPSBtZXJnZUNsb3Nlc3QoY2x1c3RlcnMsIGluZGV4LCBkaXN0cywgbWlucywgb3B0cyk7XG5cbiAgICB3aGlsZSAobWVyZ2VkKSB7XG4gICAgICBtZXJnZWQgPSBtZXJnZUNsb3Nlc3QoY2x1c3RlcnMsIGluZGV4LCBkaXN0cywgbWlucywgb3B0cyk7XG4gICAgfVxuXG4gICAgdmFyIHJldENsdXN0ZXJzOyAvLyBEZW5kcm9ncmFtIG1vZGUgYnVpbGRzIHRoZSBoaWVyYXJjaHkgYW5kIGFkZHMgaW50ZXJtZWRpYXJ5IG5vZGVzICsgZWRnZXNcbiAgICAvLyBpbiBhZGRpdGlvbiB0byByZXR1cm5pbmcgdGhlIGNsdXN0ZXJzLlxuXG4gICAgaWYgKG9wdHMubW9kZSA9PT0gJ2RlbmRyb2dyYW0nKSB7XG4gICAgICByZXRDbHVzdGVycyA9IGJ1aWxkQ2x1c3RlcnNGcm9tVHJlZShjbHVzdGVyc1swXSwgb3B0cy5kZW5kcm9ncmFtRGVwdGgsIGN5KTtcbiAgICAgIGlmIChvcHRzLmFkZERlbmRyb2dyYW0pIGJ1aWxkRGVuZHJvZ3JhbShjbHVzdGVyc1swXSwgY3kpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBSZWd1bGFyIG1vZGUgc2ltcGx5IHJldHVybnMgdGhlIGNsdXN0ZXJzXG4gICAgICByZXRDbHVzdGVycyA9IG5ldyBBcnJheShjbHVzdGVycy5sZW5ndGgpO1xuICAgICAgY2x1c3RlcnMuZm9yRWFjaChmdW5jdGlvbiAoY2x1c3RlciwgaSkge1xuICAgICAgICAvLyBDbGVhbiB1cCBtZXRhIGRhdGEgdXNlZCBmb3IgY2x1c3RlcmluZ1xuICAgICAgICBjbHVzdGVyLmtleSA9IGNsdXN0ZXIuaW5kZXggPSBudWxsO1xuICAgICAgICByZXRDbHVzdGVyc1tpXSA9IGN5LmNvbGxlY3Rpb24oY2x1c3Rlci52YWx1ZSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmV0Q2x1c3RlcnM7XG4gIH07XG5cbiAgdmFyIGhpZXJhcmNoaWNhbENsdXN0ZXJpbmckMSA9IHtcbiAgICBoaWVyYXJjaGljYWxDbHVzdGVyaW5nOiBoaWVyYXJjaGljYWxDbHVzdGVyaW5nLFxuICAgIGhjYTogaGllcmFyY2hpY2FsQ2x1c3RlcmluZ1xuICB9O1xuXG4gIC8vIEltcGxlbWVudGVkIGJ5IFpvZSBYaSBAem9leGkgZm9yIEdTT0MgMjAxNlxuICB2YXIgZGVmYXVsdHMkOSA9IGRlZmF1bHRzJGcoe1xuICAgIGRpc3RhbmNlOiAnZXVjbGlkZWFuJyxcbiAgICAvLyBkaXN0YW5jZSBtZXRyaWMgdG8gY29tcGFyZSBhdHRyaWJ1dGVzIGJldHdlZW4gdHdvIG5vZGVzXG4gICAgcHJlZmVyZW5jZTogJ21lZGlhbicsXG4gICAgLy8gc3VpdGFiaWxpdHkgb2YgYSBkYXRhIHBvaW50IHRvIHNlcnZlIGFzIGFuIGV4ZW1wbGFyXG4gICAgZGFtcGluZzogMC44LFxuICAgIC8vIGRhbXBpbmcgZmFjdG9yIGJldHdlZW4gWzAuNSwgMSlcbiAgICBtYXhJdGVyYXRpb25zOiAxMDAwLFxuICAgIC8vIG1heCBudW1iZXIgb2YgaXRlcmF0aW9ucyB0byBydW5cbiAgICBtaW5JdGVyYXRpb25zOiAxMDAsXG4gICAgLy8gbWluIG51bWJlciBvZiBpdGVyYXRpb25zIHRvIHJ1biBpbiBvcmRlciBmb3IgY2x1c3RlcmluZyB0byBzdG9wXG4gICAgYXR0cmlidXRlczogWy8vIGZ1bmN0aW9ucyB0byBxdWFudGlmeSB0aGUgc2ltaWxhcml0eSBiZXR3ZWVuIGFueSB0d28gcG9pbnRzXG4gICAgICAvLyBlLmcuIG5vZGUgPT4gbm9kZS5kYXRhKCd3ZWlnaHQnKVxuICAgIF1cbiAgfSk7XG5cbiAgdmFyIHNldE9wdGlvbnMgPSBmdW5jdGlvbiBzZXRPcHRpb25zKG9wdGlvbnMpIHtcbiAgICB2YXIgZG1wID0gb3B0aW9ucy5kYW1waW5nO1xuICAgIHZhciBwcmVmID0gb3B0aW9ucy5wcmVmZXJlbmNlO1xuXG4gICAgaWYgKCEoMC41IDw9IGRtcCAmJiBkbXAgPCAxKSkge1xuICAgICAgZXJyb3IoXCJEYW1waW5nIG11c3QgcmFuZ2Ugb24gWzAuNSwgMSkuICBHb3Q6IFwiLmNvbmNhdChkbXApKTtcbiAgICB9XG5cbiAgICB2YXIgdmFsaWRQcmVmcyA9IFsnbWVkaWFuJywgJ21lYW4nLCAnbWluJywgJ21heCddO1xuXG4gICAgaWYgKCEodmFsaWRQcmVmcy5zb21lKGZ1bmN0aW9uICh2KSB7XG4gICAgICByZXR1cm4gdiA9PT0gcHJlZjtcbiAgICB9KSB8fCBudW1iZXIkMShwcmVmKSkpIHtcbiAgICAgIGVycm9yKFwiUHJlZmVyZW5jZSBtdXN0IGJlIG9uZSBvZiBbXCIuY29uY2F0KHZhbGlkUHJlZnMubWFwKGZ1bmN0aW9uIChwKSB7XG4gICAgICAgIHJldHVybiBcIidcIi5jb25jYXQocCwgXCInXCIpO1xuICAgICAgfSkuam9pbignLCAnKSwgXCJdIG9yIGEgbnVtYmVyLiAgR290OiBcIikuY29uY2F0KHByZWYpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZGVmYXVsdHMkOShvcHRpb25zKTtcbiAgfTtcbiAgLyogZXNsaW50LWVuYWJsZSAqL1xuXG5cbiAgdmFyIGdldFNpbWlsYXJpdHkgPSBmdW5jdGlvbiBnZXRTaW1pbGFyaXR5KHR5cGUsIG4xLCBuMiwgYXR0cmlidXRlcykge1xuICAgIHZhciBhdHRyID0gZnVuY3Rpb24gYXR0cihuLCBpKSB7XG4gICAgICByZXR1cm4gYXR0cmlidXRlc1tpXShuKTtcbiAgICB9OyAvLyBuYiBuZWdhdGl2ZSBiZWNhdXNlIHNpbWlsYXJpdHkgc2hvdWxkIGhhdmUgYW4gaW52ZXJzZSByZWxhdGlvbnNoaXAgdG8gZGlzdGFuY2VcblxuXG4gICAgcmV0dXJuIC1jbHVzdGVyaW5nRGlzdGFuY2UodHlwZSwgYXR0cmlidXRlcy5sZW5ndGgsIGZ1bmN0aW9uIChpKSB7XG4gICAgICByZXR1cm4gYXR0cihuMSwgaSk7XG4gICAgfSwgZnVuY3Rpb24gKGkpIHtcbiAgICAgIHJldHVybiBhdHRyKG4yLCBpKTtcbiAgICB9LCBuMSwgbjIpO1xuICB9O1xuXG4gIHZhciBnZXRQcmVmZXJlbmNlID0gZnVuY3Rpb24gZ2V0UHJlZmVyZW5jZShTLCBwcmVmZXJlbmNlKSB7XG4gICAgLy8gbGFyZ2VyIHByZWZlcmVuY2UgPSBncmVhdGVyICMgb2YgY2x1c3RlcnNcbiAgICB2YXIgcCA9IG51bGw7XG5cbiAgICBpZiAocHJlZmVyZW5jZSA9PT0gJ21lZGlhbicpIHtcbiAgICAgIHAgPSBtZWRpYW4oUyk7XG4gICAgfSBlbHNlIGlmIChwcmVmZXJlbmNlID09PSAnbWVhbicpIHtcbiAgICAgIHAgPSBtZWFuKFMpO1xuICAgIH0gZWxzZSBpZiAocHJlZmVyZW5jZSA9PT0gJ21pbicpIHtcbiAgICAgIHAgPSBtaW4oUyk7XG4gICAgfSBlbHNlIGlmIChwcmVmZXJlbmNlID09PSAnbWF4Jykge1xuICAgICAgcCA9IG1heChTKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQ3VzdG9tIHByZWZlcmVuY2UgbnVtYmVyLCBhcyBzZXQgYnkgdXNlclxuICAgICAgcCA9IHByZWZlcmVuY2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIHA7XG4gIH07XG5cbiAgdmFyIGZpbmRFeGVtcGxhcnMgPSBmdW5jdGlvbiBmaW5kRXhlbXBsYXJzKG4sIFIsIEEpIHtcbiAgICB2YXIgaW5kaWNlcyA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuOyBpKyspIHtcbiAgICAgIGlmIChSW2kgKiBuICsgaV0gKyBBW2kgKiBuICsgaV0gPiAwKSB7XG4gICAgICAgIGluZGljZXMucHVzaChpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gaW5kaWNlcztcbiAgfTtcblxuICB2YXIgYXNzaWduQ2x1c3RlcnMgPSBmdW5jdGlvbiBhc3NpZ25DbHVzdGVycyhuLCBTLCBleGVtcGxhcnMpIHtcbiAgICB2YXIgY2x1c3RlcnMgPSBbXTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgICB2YXIgaW5kZXggPSAtMTtcbiAgICAgIHZhciBtYXggPSAtSW5maW5pdHk7XG5cbiAgICAgIGZvciAodmFyIGVpID0gMDsgZWkgPCBleGVtcGxhcnMubGVuZ3RoOyBlaSsrKSB7XG4gICAgICAgIHZhciBlID0gZXhlbXBsYXJzW2VpXTtcblxuICAgICAgICBpZiAoU1tpICogbiArIGVdID4gbWF4KSB7XG4gICAgICAgICAgaW5kZXggPSBlO1xuICAgICAgICAgIG1heCA9IFNbaSAqIG4gKyBlXTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoaW5kZXggPiAwKSB7XG4gICAgICAgIGNsdXN0ZXJzLnB1c2goaW5kZXgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAodmFyIF9laSA9IDA7IF9laSA8IGV4ZW1wbGFycy5sZW5ndGg7IF9laSsrKSB7XG4gICAgICBjbHVzdGVyc1tleGVtcGxhcnNbX2VpXV0gPSBleGVtcGxhcnNbX2VpXTtcbiAgICB9XG5cbiAgICByZXR1cm4gY2x1c3RlcnM7XG4gIH07XG5cbiAgdmFyIGFzc2lnbiA9IGZ1bmN0aW9uIGFzc2lnbihuLCBTLCBleGVtcGxhcnMpIHtcbiAgICB2YXIgY2x1c3RlcnMgPSBhc3NpZ25DbHVzdGVycyhuLCBTLCBleGVtcGxhcnMpO1xuXG4gICAgZm9yICh2YXIgZWkgPSAwOyBlaSA8IGV4ZW1wbGFycy5sZW5ndGg7IGVpKyspIHtcbiAgICAgIHZhciBpaSA9IFtdO1xuXG4gICAgICBmb3IgKHZhciBjID0gMDsgYyA8IGNsdXN0ZXJzLmxlbmd0aDsgYysrKSB7XG4gICAgICAgIGlmIChjbHVzdGVyc1tjXSA9PT0gZXhlbXBsYXJzW2VpXSkge1xuICAgICAgICAgIGlpLnB1c2goYyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdmFyIG1heEkgPSAtMTtcbiAgICAgIHZhciBtYXhTdW0gPSAtSW5maW5pdHk7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaWkubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHN1bSA9IDA7XG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBpaS5sZW5ndGg7IGorKykge1xuICAgICAgICAgIHN1bSArPSBTW2lpW2pdICogbiArIGlpW2ldXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChzdW0gPiBtYXhTdW0pIHtcbiAgICAgICAgICBtYXhJID0gaTtcbiAgICAgICAgICBtYXhTdW0gPSBzdW07XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZXhlbXBsYXJzW2VpXSA9IGlpW21heEldO1xuICAgIH1cblxuICAgIGNsdXN0ZXJzID0gYXNzaWduQ2x1c3RlcnMobiwgUywgZXhlbXBsYXJzKTtcbiAgICByZXR1cm4gY2x1c3RlcnM7XG4gIH07XG5cbiAgdmFyIGFmZmluaXR5UHJvcGFnYXRpb24gPSBmdW5jdGlvbiBhZmZpbml0eVByb3BhZ2F0aW9uKG9wdGlvbnMpIHtcbiAgICB2YXIgY3kgPSB0aGlzLmN5KCk7XG4gICAgdmFyIG5vZGVzID0gdGhpcy5ub2RlcygpO1xuICAgIHZhciBvcHRzID0gc2V0T3B0aW9ucyhvcHRpb25zKTsgLy8gTWFwIGVhY2ggbm9kZSB0byBpdHMgcG9zaXRpb24gaW4gbm9kZSBhcnJheVxuXG4gICAgdmFyIGlkMnBvc2l0aW9uID0ge307XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZDJwb3NpdGlvbltub2Rlc1tpXS5pZCgpXSA9IGk7XG4gICAgfSAvLyBCZWdpbiBhZmZpbml0eSBwcm9wYWdhdGlvbiBhbGdvcml0aG1cblxuXG4gICAgdmFyIG47IC8vIG51bWJlciBvZiBkYXRhIHBvaW50c1xuXG4gICAgdmFyIG4yOyAvLyBzaXplIG9mIG1hdHJpY2VzXG5cbiAgICB2YXIgUzsgLy8gc2ltaWxhcml0eSBtYXRyaXggKDFEIGFycmF5KVxuXG4gICAgdmFyIHA7IC8vIHByZWZlcmVuY2Uvc3VpdGFiaWxpdHkgb2YgYSBkYXRhIHBvaW50IHRvIHNlcnZlIGFzIGFuIGV4ZW1wbGFyXG5cbiAgICB2YXIgUjsgLy8gcmVzcG9uc2liaWxpdHkgbWF0cml4ICgxRCBhcnJheSlcblxuICAgIHZhciBBOyAvLyBhdmFpbGFiaWxpdHkgbWF0cml4ICgxRCBhcnJheSlcblxuICAgIG4gPSBub2Rlcy5sZW5ndGg7XG4gICAgbjIgPSBuICogbjsgLy8gSW5pdGlhbGl6ZSBhbmQgYnVpbGQgUyBzaW1pbGFyaXR5IG1hdHJpeFxuXG4gICAgUyA9IG5ldyBBcnJheShuMik7XG5cbiAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgbjI7IF9pKyspIHtcbiAgICAgIFNbX2ldID0gLUluZmluaXR5OyAvLyBmb3IgY2FzZXMgd2hlcmUgdHdvIGRhdGEgcG9pbnRzIHNob3VsZG4ndCBiZSBsaW5rZWQgdG9nZXRoZXJcbiAgICB9XG5cbiAgICBmb3IgKHZhciBfaTIgPSAwOyBfaTIgPCBuOyBfaTIrKykge1xuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBuOyBqKyspIHtcbiAgICAgICAgaWYgKF9pMiAhPT0gaikge1xuICAgICAgICAgIFNbX2kyICogbiArIGpdID0gZ2V0U2ltaWxhcml0eShvcHRzLmRpc3RhbmNlLCBub2Rlc1tfaTJdLCBub2Rlc1tqXSwgb3B0cy5hdHRyaWJ1dGVzKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gLy8gUGxhY2UgcHJlZmVyZW5jZXMgb24gdGhlIGRpYWdvbmFsIG9mIFNcblxuXG4gICAgcCA9IGdldFByZWZlcmVuY2UoUywgb3B0cy5wcmVmZXJlbmNlKTtcblxuICAgIGZvciAodmFyIF9pMyA9IDA7IF9pMyA8IG47IF9pMysrKSB7XG4gICAgICBTW19pMyAqIG4gKyBfaTNdID0gcDtcbiAgICB9IC8vIEluaXRpYWxpemUgUiByZXNwb25zaWJpbGl0eSBtYXRyaXhcblxuXG4gICAgUiA9IG5ldyBBcnJheShuMik7XG5cbiAgICBmb3IgKHZhciBfaTQgPSAwOyBfaTQgPCBuMjsgX2k0KyspIHtcbiAgICAgIFJbX2k0XSA9IDAuMDtcbiAgICB9IC8vIEluaXRpYWxpemUgQSBhdmFpbGFiaWxpdHkgbWF0cml4XG5cblxuICAgIEEgPSBuZXcgQXJyYXkobjIpO1xuXG4gICAgZm9yICh2YXIgX2k1ID0gMDsgX2k1IDwgbjI7IF9pNSsrKSB7XG4gICAgICBBW19pNV0gPSAwLjA7XG4gICAgfVxuXG4gICAgdmFyIG9sZCA9IG5ldyBBcnJheShuKTtcbiAgICB2YXIgUnAgPSBuZXcgQXJyYXkobik7XG4gICAgdmFyIHNlID0gbmV3IEFycmF5KG4pO1xuXG4gICAgZm9yICh2YXIgX2k2ID0gMDsgX2k2IDwgbjsgX2k2KyspIHtcbiAgICAgIG9sZFtfaTZdID0gMC4wO1xuICAgICAgUnBbX2k2XSA9IDAuMDtcbiAgICAgIHNlW19pNl0gPSAwO1xuICAgIH1cblxuICAgIHZhciBlID0gbmV3IEFycmF5KG4gKiBvcHRzLm1pbkl0ZXJhdGlvbnMpO1xuXG4gICAgZm9yICh2YXIgX2k3ID0gMDsgX2k3IDwgZS5sZW5ndGg7IF9pNysrKSB7XG4gICAgICBlW19pN10gPSAwO1xuICAgIH1cblxuICAgIHZhciBpdGVyO1xuXG4gICAgZm9yIChpdGVyID0gMDsgaXRlciA8IG9wdHMubWF4SXRlcmF0aW9uczsgaXRlcisrKSB7XG4gICAgICAvLyBtYWluIGFsZ29yaXRobWljIGxvb3BcbiAgICAgIC8vIFVwZGF0ZSBSIHJlc3BvbnNpYmlsaXR5IG1hdHJpeFxuICAgICAgZm9yICh2YXIgX2k4ID0gMDsgX2k4IDwgbjsgX2k4KyspIHtcbiAgICAgICAgdmFyIG1heCA9IC1JbmZpbml0eSxcbiAgICAgICAgICAgIG1heDIgPSAtSW5maW5pdHksXG4gICAgICAgICAgICBtYXhJID0gLTEsXG4gICAgICAgICAgICBBUyA9IDAuMDtcblxuICAgICAgICBmb3IgKHZhciBfaiA9IDA7IF9qIDwgbjsgX2orKykge1xuICAgICAgICAgIG9sZFtfal0gPSBSW19pOCAqIG4gKyBfal07XG4gICAgICAgICAgQVMgPSBBW19pOCAqIG4gKyBfal0gKyBTW19pOCAqIG4gKyBfal07XG5cbiAgICAgICAgICBpZiAoQVMgPj0gbWF4KSB7XG4gICAgICAgICAgICBtYXgyID0gbWF4O1xuICAgICAgICAgICAgbWF4ID0gQVM7XG4gICAgICAgICAgICBtYXhJID0gX2o7XG4gICAgICAgICAgfSBlbHNlIGlmIChBUyA+IG1heDIpIHtcbiAgICAgICAgICAgIG1heDIgPSBBUztcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKHZhciBfajIgPSAwOyBfajIgPCBuOyBfajIrKykge1xuICAgICAgICAgIFJbX2k4ICogbiArIF9qMl0gPSAoMSAtIG9wdHMuZGFtcGluZykgKiAoU1tfaTggKiBuICsgX2oyXSAtIG1heCkgKyBvcHRzLmRhbXBpbmcgKiBvbGRbX2oyXTtcbiAgICAgICAgfVxuXG4gICAgICAgIFJbX2k4ICogbiArIG1heEldID0gKDEgLSBvcHRzLmRhbXBpbmcpICogKFNbX2k4ICogbiArIG1heEldIC0gbWF4MikgKyBvcHRzLmRhbXBpbmcgKiBvbGRbbWF4SV07XG4gICAgICB9IC8vIFVwZGF0ZSBBIGF2YWlsYWJpbGl0eSBtYXRyaXhcblxuXG4gICAgICBmb3IgKHZhciBfaTkgPSAwOyBfaTkgPCBuOyBfaTkrKykge1xuICAgICAgICB2YXIgc3VtID0gMDtcblxuICAgICAgICBmb3IgKHZhciBfajMgPSAwOyBfajMgPCBuOyBfajMrKykge1xuICAgICAgICAgIG9sZFtfajNdID0gQVtfajMgKiBuICsgX2k5XTtcbiAgICAgICAgICBScFtfajNdID0gTWF0aC5tYXgoMCwgUltfajMgKiBuICsgX2k5XSk7XG4gICAgICAgICAgc3VtICs9IFJwW19qM107XG4gICAgICAgIH1cblxuICAgICAgICBzdW0gLT0gUnBbX2k5XTtcbiAgICAgICAgUnBbX2k5XSA9IFJbX2k5ICogbiArIF9pOV07XG4gICAgICAgIHN1bSArPSBScFtfaTldO1xuXG4gICAgICAgIGZvciAodmFyIF9qNCA9IDA7IF9qNCA8IG47IF9qNCsrKSB7XG4gICAgICAgICAgQVtfajQgKiBuICsgX2k5XSA9ICgxIC0gb3B0cy5kYW1waW5nKSAqIE1hdGgubWluKDAsIHN1bSAtIFJwW19qNF0pICsgb3B0cy5kYW1waW5nICogb2xkW19qNF07XG4gICAgICAgIH1cblxuICAgICAgICBBW19pOSAqIG4gKyBfaTldID0gKDEgLSBvcHRzLmRhbXBpbmcpICogKHN1bSAtIFJwW19pOV0pICsgb3B0cy5kYW1waW5nICogb2xkW19pOV07XG4gICAgICB9IC8vIENoZWNrIGZvciBjb252ZXJnZW5jZVxuXG5cbiAgICAgIHZhciBLID0gMDtcblxuICAgICAgZm9yICh2YXIgX2kxMCA9IDA7IF9pMTAgPCBuOyBfaTEwKyspIHtcbiAgICAgICAgdmFyIEUgPSBBW19pMTAgKiBuICsgX2kxMF0gKyBSW19pMTAgKiBuICsgX2kxMF0gPiAwID8gMSA6IDA7XG4gICAgICAgIGVbaXRlciAlIG9wdHMubWluSXRlcmF0aW9ucyAqIG4gKyBfaTEwXSA9IEU7XG4gICAgICAgIEsgKz0gRTtcbiAgICAgIH1cblxuICAgICAgaWYgKEsgPiAwICYmIChpdGVyID49IG9wdHMubWluSXRlcmF0aW9ucyAtIDEgfHwgaXRlciA9PSBvcHRzLm1heEl0ZXJhdGlvbnMgLSAxKSkge1xuICAgICAgICB2YXIgX3N1bSA9IDA7XG5cbiAgICAgICAgZm9yICh2YXIgX2kxMSA9IDA7IF9pMTEgPCBuOyBfaTExKyspIHtcbiAgICAgICAgICBzZVtfaTExXSA9IDA7XG5cbiAgICAgICAgICBmb3IgKHZhciBfajUgPSAwOyBfajUgPCBvcHRzLm1pbkl0ZXJhdGlvbnM7IF9qNSsrKSB7XG4gICAgICAgICAgICBzZVtfaTExXSArPSBlW19qNSAqIG4gKyBfaTExXTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoc2VbX2kxMV0gPT09IDAgfHwgc2VbX2kxMV0gPT09IG9wdHMubWluSXRlcmF0aW9ucykge1xuICAgICAgICAgICAgX3N1bSsrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChfc3VtID09PSBuKSB7XG4gICAgICAgICAgLy8gdGhlbiB3ZSBoYXZlIGNvbnZlcmdlbmNlXG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IC8vIElkZW50aWZ5IGV4ZW1wbGFycyAoY2x1c3RlciBjZW50ZXJzKVxuXG5cbiAgICB2YXIgZXhlbXBsYXJzSW5kaWNlcyA9IGZpbmRFeGVtcGxhcnMobiwgUiwgQSk7IC8vIEFzc2lnbiBub2RlcyB0byBjbHVzdGVyc1xuXG4gICAgdmFyIGNsdXN0ZXJJbmRpY2VzID0gYXNzaWduKG4sIFMsIGV4ZW1wbGFyc0luZGljZXMpO1xuICAgIHZhciBjbHVzdGVycyA9IHt9O1xuXG4gICAgZm9yICh2YXIgYyA9IDA7IGMgPCBleGVtcGxhcnNJbmRpY2VzLmxlbmd0aDsgYysrKSB7XG4gICAgICBjbHVzdGVyc1tleGVtcGxhcnNJbmRpY2VzW2NdXSA9IFtdO1xuICAgIH1cblxuICAgIGZvciAodmFyIF9pMTIgPSAwOyBfaTEyIDwgbm9kZXMubGVuZ3RoOyBfaTEyKyspIHtcbiAgICAgIHZhciBwb3MgPSBpZDJwb3NpdGlvbltub2Rlc1tfaTEyXS5pZCgpXTtcblxuICAgICAgdmFyIGNsdXN0ZXJJbmRleCA9IGNsdXN0ZXJJbmRpY2VzW3Bvc107XG5cbiAgICAgIGlmIChjbHVzdGVySW5kZXggIT0gbnVsbCkge1xuICAgICAgICAvLyB0aGUgbm9kZSBtYXkgaGF2ZSBub3QgYmVlbiBhc3NpZ25lZCBhIGNsdXN0ZXIgaWYgbm8gdmFsaWQgYXR0cmlidXRlcyB3ZXJlIHNwZWNpZmllZFxuICAgICAgICBjbHVzdGVyc1tjbHVzdGVySW5kZXhdLnB1c2gobm9kZXNbX2kxMl0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciByZXRDbHVzdGVycyA9IG5ldyBBcnJheShleGVtcGxhcnNJbmRpY2VzLmxlbmd0aCk7XG5cbiAgICBmb3IgKHZhciBfYyA9IDA7IF9jIDwgZXhlbXBsYXJzSW5kaWNlcy5sZW5ndGg7IF9jKyspIHtcbiAgICAgIHJldENsdXN0ZXJzW19jXSA9IGN5LmNvbGxlY3Rpb24oY2x1c3RlcnNbZXhlbXBsYXJzSW5kaWNlc1tfY11dKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmV0Q2x1c3RlcnM7XG4gIH07XG5cbiAgdmFyIGFmZmluaXR5UHJvcGFnYXRpb24kMSA9IHtcbiAgICBhZmZpbml0eVByb3BhZ2F0aW9uOiBhZmZpbml0eVByb3BhZ2F0aW9uLFxuICAgIGFwOiBhZmZpbml0eVByb3BhZ2F0aW9uXG4gIH07XG5cbiAgdmFyIGhpZXJob2x6ZXJEZWZhdWx0cyA9IGRlZmF1bHRzJGcoe1xuICAgIHJvb3Q6IHVuZGVmaW5lZCxcbiAgICBkaXJlY3RlZDogZmFsc2VcbiAgfSk7XG4gIHZhciBlbGVzZm4kayA9IHtcbiAgICBoaWVyaG9semVyOiBmdW5jdGlvbiBoaWVyaG9semVyKG9wdGlvbnMpIHtcbiAgICAgIGlmICghcGxhaW5PYmplY3Qob3B0aW9ucykpIHtcbiAgICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICAgIG9wdGlvbnMgPSB7XG4gICAgICAgICAgcm9vdDogYXJnc1swXSxcbiAgICAgICAgICBkaXJlY3RlZDogYXJnc1sxXVxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICB2YXIgX2hpZXJob2x6ZXJEZWZhdWx0cyA9IGhpZXJob2x6ZXJEZWZhdWx0cyhvcHRpb25zKSxcbiAgICAgICAgICByb290ID0gX2hpZXJob2x6ZXJEZWZhdWx0cy5yb290LFxuICAgICAgICAgIGRpcmVjdGVkID0gX2hpZXJob2x6ZXJEZWZhdWx0cy5kaXJlY3RlZDtcblxuICAgICAgdmFyIGVsZXMgPSB0aGlzO1xuICAgICAgdmFyIGRmbGFnID0gZmFsc2U7XG4gICAgICB2YXIgb2RkSW47XG4gICAgICB2YXIgb2RkT3V0O1xuICAgICAgdmFyIHN0YXJ0VmVydGV4O1xuICAgICAgaWYgKHJvb3QpIHN0YXJ0VmVydGV4ID0gc3RyaW5nKHJvb3QpID8gdGhpcy5maWx0ZXIocm9vdClbMF0uaWQoKSA6IHJvb3RbMF0uaWQoKTtcbiAgICAgIHZhciBub2RlcyA9IHt9O1xuICAgICAgdmFyIGVkZ2VzID0ge307XG5cbiAgICAgIGlmIChkaXJlY3RlZCkge1xuICAgICAgICBlbGVzLmZvckVhY2goZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICAgIHZhciBpZCA9IGVsZS5pZCgpO1xuXG4gICAgICAgICAgaWYgKGVsZS5pc05vZGUoKSkge1xuICAgICAgICAgICAgdmFyIGluZCA9IGVsZS5pbmRlZ3JlZSh0cnVlKTtcbiAgICAgICAgICAgIHZhciBvdXRkID0gZWxlLm91dGRlZ3JlZSh0cnVlKTtcbiAgICAgICAgICAgIHZhciBkMSA9IGluZCAtIG91dGQ7XG4gICAgICAgICAgICB2YXIgZDIgPSBvdXRkIC0gaW5kO1xuXG4gICAgICAgICAgICBpZiAoZDEgPT0gMSkge1xuICAgICAgICAgICAgICBpZiAob2RkSW4pIGRmbGFnID0gdHJ1ZTtlbHNlIG9kZEluID0gaWQ7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGQyID09IDEpIHtcbiAgICAgICAgICAgICAgaWYgKG9kZE91dCkgZGZsYWcgPSB0cnVlO2Vsc2Ugb2RkT3V0ID0gaWQ7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGQyID4gMSB8fCBkMSA+IDEpIHtcbiAgICAgICAgICAgICAgZGZsYWcgPSB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBub2Rlc1tpZF0gPSBbXTtcbiAgICAgICAgICAgIGVsZS5vdXRnb2VycygpLmZvckVhY2goZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgaWYgKGUuaXNFZGdlKCkpIG5vZGVzW2lkXS5wdXNoKGUuaWQoKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZWRnZXNbaWRdID0gW3VuZGVmaW5lZCwgZWxlLnRhcmdldCgpLmlkKCldO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlbGVzLmZvckVhY2goZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICAgIHZhciBpZCA9IGVsZS5pZCgpO1xuXG4gICAgICAgICAgaWYgKGVsZS5pc05vZGUoKSkge1xuICAgICAgICAgICAgdmFyIGQgPSBlbGUuZGVncmVlKHRydWUpO1xuXG4gICAgICAgICAgICBpZiAoZCAlIDIpIHtcbiAgICAgICAgICAgICAgaWYgKCFvZGRJbikgb2RkSW4gPSBpZDtlbHNlIGlmICghb2RkT3V0KSBvZGRPdXQgPSBpZDtlbHNlIGRmbGFnID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbm9kZXNbaWRdID0gW107XG4gICAgICAgICAgICBlbGUuY29ubmVjdGVkRWRnZXMoKS5mb3JFYWNoKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgIHJldHVybiBub2Rlc1tpZF0ucHVzaChlLmlkKCkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGVkZ2VzW2lkXSA9IFtlbGUuc291cmNlKCkuaWQoKSwgZWxlLnRhcmdldCgpLmlkKCldO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHZhciByZXN1bHQgPSB7XG4gICAgICAgIGZvdW5kOiBmYWxzZSxcbiAgICAgICAgdHJhaWw6IHVuZGVmaW5lZFxuICAgICAgfTtcbiAgICAgIGlmIChkZmxhZykgcmV0dXJuIHJlc3VsdDtlbHNlIGlmIChvZGRPdXQgJiYgb2RkSW4pIHtcbiAgICAgICAgaWYgKGRpcmVjdGVkKSB7XG4gICAgICAgICAgaWYgKHN0YXJ0VmVydGV4ICYmIG9kZE91dCAhPSBzdGFydFZlcnRleCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzdGFydFZlcnRleCA9IG9kZE91dDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAoc3RhcnRWZXJ0ZXggJiYgb2RkT3V0ICE9IHN0YXJ0VmVydGV4ICYmIG9kZEluICE9IHN0YXJ0VmVydGV4KSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgIH0gZWxzZSBpZiAoIXN0YXJ0VmVydGV4KSB7XG4gICAgICAgICAgICBzdGFydFZlcnRleCA9IG9kZE91dDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICghc3RhcnRWZXJ0ZXgpIHN0YXJ0VmVydGV4ID0gZWxlc1swXS5pZCgpO1xuICAgICAgfVxuXG4gICAgICB2YXIgd2FsayA9IGZ1bmN0aW9uIHdhbGsodikge1xuICAgICAgICB2YXIgY3VycmVudE5vZGUgPSB2O1xuICAgICAgICB2YXIgc3VidG91ciA9IFt2XTtcbiAgICAgICAgdmFyIGFkaiwgYWRqVGFpbCwgYWRqSGVhZDtcblxuICAgICAgICB3aGlsZSAobm9kZXNbY3VycmVudE5vZGVdLmxlbmd0aCkge1xuICAgICAgICAgIGFkaiA9IG5vZGVzW2N1cnJlbnROb2RlXS5zaGlmdCgpO1xuICAgICAgICAgIGFkalRhaWwgPSBlZGdlc1thZGpdWzBdO1xuICAgICAgICAgIGFkakhlYWQgPSBlZGdlc1thZGpdWzFdO1xuXG4gICAgICAgICAgaWYgKGN1cnJlbnROb2RlICE9IGFkakhlYWQpIHtcbiAgICAgICAgICAgIG5vZGVzW2FkakhlYWRdID0gbm9kZXNbYWRqSGVhZF0uZmlsdGVyKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgIHJldHVybiBlICE9IGFkajtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY3VycmVudE5vZGUgPSBhZGpIZWFkO1xuICAgICAgICAgIH0gZWxzZSBpZiAoIWRpcmVjdGVkICYmIGN1cnJlbnROb2RlICE9IGFkalRhaWwpIHtcbiAgICAgICAgICAgIG5vZGVzW2FkalRhaWxdID0gbm9kZXNbYWRqVGFpbF0uZmlsdGVyKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgIHJldHVybiBlICE9IGFkajtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY3VycmVudE5vZGUgPSBhZGpUYWlsO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHN1YnRvdXIudW5zaGlmdChhZGopO1xuICAgICAgICAgIHN1YnRvdXIudW5zaGlmdChjdXJyZW50Tm9kZSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gc3VidG91cjtcbiAgICAgIH07XG5cbiAgICAgIHZhciB0cmFpbCA9IFtdO1xuICAgICAgdmFyIHN1YnRvdXIgPSBbXTtcbiAgICAgIHN1YnRvdXIgPSB3YWxrKHN0YXJ0VmVydGV4KTtcblxuICAgICAgd2hpbGUgKHN1YnRvdXIubGVuZ3RoICE9IDEpIHtcbiAgICAgICAgaWYgKG5vZGVzW3N1YnRvdXJbMF1dLmxlbmd0aCA9PSAwKSB7XG4gICAgICAgICAgdHJhaWwudW5zaGlmdChlbGVzLmdldEVsZW1lbnRCeUlkKHN1YnRvdXIuc2hpZnQoKSkpO1xuICAgICAgICAgIHRyYWlsLnVuc2hpZnQoZWxlcy5nZXRFbGVtZW50QnlJZChzdWJ0b3VyLnNoaWZ0KCkpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzdWJ0b3VyID0gd2FsayhzdWJ0b3VyLnNoaWZ0KCkpLmNvbmNhdChzdWJ0b3VyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0cmFpbC51bnNoaWZ0KGVsZXMuZ2V0RWxlbWVudEJ5SWQoc3VidG91ci5zaGlmdCgpKSk7IC8vIGZpbmFsIG5vZGVcblxuICAgICAgZm9yICh2YXIgZCBpbiBub2Rlcykge1xuICAgICAgICBpZiAobm9kZXNbZF0ubGVuZ3RoKSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXN1bHQuZm91bmQgPSB0cnVlO1xuICAgICAgcmVzdWx0LnRyYWlsID0gdGhpcy5zcGF3bih0cmFpbCwgdHJ1ZSk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbiAgfTtcblxuICB2YXIgaG9wY3JvZnRUYXJqYW5CaWNvbm5lY3RlZCA9IGZ1bmN0aW9uIGhvcGNyb2Z0VGFyamFuQmljb25uZWN0ZWQoKSB7XG4gICAgdmFyIGVsZXMgPSB0aGlzO1xuICAgIHZhciBub2RlcyA9IHt9O1xuICAgIHZhciBpZCA9IDA7XG4gICAgdmFyIGVkZ2VDb3VudCA9IDA7XG4gICAgdmFyIGNvbXBvbmVudHMgPSBbXTtcbiAgICB2YXIgc3RhY2sgPSBbXTtcbiAgICB2YXIgdmlzaXRlZEVkZ2VzID0ge307XG5cbiAgICB2YXIgYnVpbGRDb21wb25lbnQgPSBmdW5jdGlvbiBidWlsZENvbXBvbmVudCh4LCB5KSB7XG4gICAgICB2YXIgaSA9IHN0YWNrLmxlbmd0aCAtIDE7XG4gICAgICB2YXIgY3V0c2V0ID0gW107XG4gICAgICB2YXIgY29tcG9uZW50ID0gZWxlcy5zcGF3bigpO1xuXG4gICAgICB3aGlsZSAoc3RhY2tbaV0ueCAhPSB4IHx8IHN0YWNrW2ldLnkgIT0geSkge1xuICAgICAgICBjdXRzZXQucHVzaChzdGFjay5wb3AoKS5lZGdlKTtcbiAgICAgICAgaS0tO1xuICAgICAgfVxuXG4gICAgICBjdXRzZXQucHVzaChzdGFjay5wb3AoKS5lZGdlKTtcbiAgICAgIGN1dHNldC5mb3JFYWNoKGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgICAgIHZhciBjb25uZWN0ZWROb2RlcyA9IGVkZ2UuY29ubmVjdGVkTm9kZXMoKS5pbnRlcnNlY3Rpb24oZWxlcyk7XG4gICAgICAgIGNvbXBvbmVudC5tZXJnZShlZGdlKTtcbiAgICAgICAgY29ubmVjdGVkTm9kZXMuZm9yRWFjaChmdW5jdGlvbiAobm9kZSkge1xuICAgICAgICAgIHZhciBub2RlSWQgPSBub2RlLmlkKCk7XG4gICAgICAgICAgdmFyIGNvbm5lY3RlZEVkZ2VzID0gbm9kZS5jb25uZWN0ZWRFZGdlcygpLmludGVyc2VjdGlvbihlbGVzKTtcbiAgICAgICAgICBjb21wb25lbnQubWVyZ2Uobm9kZSk7XG5cbiAgICAgICAgICBpZiAoIW5vZGVzW25vZGVJZF0uY3V0VmVydGV4KSB7XG4gICAgICAgICAgICBjb21wb25lbnQubWVyZ2UoY29ubmVjdGVkRWRnZXMpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb21wb25lbnQubWVyZ2UoY29ubmVjdGVkRWRnZXMuZmlsdGVyKGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgICAgICAgICAgIHJldHVybiBlZGdlLmlzTG9vcCgpO1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICAgIGNvbXBvbmVudHMucHVzaChjb21wb25lbnQpO1xuICAgIH07XG5cbiAgICB2YXIgYmljb25uZWN0ZWRTZWFyY2ggPSBmdW5jdGlvbiBiaWNvbm5lY3RlZFNlYXJjaChyb290LCBjdXJyZW50Tm9kZSwgcGFyZW50KSB7XG4gICAgICBpZiAocm9vdCA9PT0gcGFyZW50KSBlZGdlQ291bnQgKz0gMTtcbiAgICAgIG5vZGVzW2N1cnJlbnROb2RlXSA9IHtcbiAgICAgICAgaWQ6IGlkLFxuICAgICAgICBsb3c6IGlkKyssXG4gICAgICAgIGN1dFZlcnRleDogZmFsc2VcbiAgICAgIH07XG4gICAgICB2YXIgZWRnZXMgPSBlbGVzLmdldEVsZW1lbnRCeUlkKGN1cnJlbnROb2RlKS5jb25uZWN0ZWRFZGdlcygpLmludGVyc2VjdGlvbihlbGVzKTtcblxuICAgICAgaWYgKGVkZ2VzLnNpemUoKSA9PT0gMCkge1xuICAgICAgICBjb21wb25lbnRzLnB1c2goZWxlcy5zcGF3bihlbGVzLmdldEVsZW1lbnRCeUlkKGN1cnJlbnROb2RlKSkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIHNvdXJjZUlkLCB0YXJnZXRJZCwgb3RoZXJOb2RlSWQsIGVkZ2VJZDtcbiAgICAgICAgZWRnZXMuZm9yRWFjaChmdW5jdGlvbiAoZWRnZSkge1xuICAgICAgICAgIHNvdXJjZUlkID0gZWRnZS5zb3VyY2UoKS5pZCgpO1xuICAgICAgICAgIHRhcmdldElkID0gZWRnZS50YXJnZXQoKS5pZCgpO1xuICAgICAgICAgIG90aGVyTm9kZUlkID0gc291cmNlSWQgPT09IGN1cnJlbnROb2RlID8gdGFyZ2V0SWQgOiBzb3VyY2VJZDtcblxuICAgICAgICAgIGlmIChvdGhlck5vZGVJZCAhPT0gcGFyZW50KSB7XG4gICAgICAgICAgICBlZGdlSWQgPSBlZGdlLmlkKCk7XG5cbiAgICAgICAgICAgIGlmICghdmlzaXRlZEVkZ2VzW2VkZ2VJZF0pIHtcbiAgICAgICAgICAgICAgdmlzaXRlZEVkZ2VzW2VkZ2VJZF0gPSB0cnVlO1xuICAgICAgICAgICAgICBzdGFjay5wdXNoKHtcbiAgICAgICAgICAgICAgICB4OiBjdXJyZW50Tm9kZSxcbiAgICAgICAgICAgICAgICB5OiBvdGhlck5vZGVJZCxcbiAgICAgICAgICAgICAgICBlZGdlOiBlZGdlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIShvdGhlck5vZGVJZCBpbiBub2RlcykpIHtcbiAgICAgICAgICAgICAgYmljb25uZWN0ZWRTZWFyY2gocm9vdCwgb3RoZXJOb2RlSWQsIGN1cnJlbnROb2RlKTtcbiAgICAgICAgICAgICAgbm9kZXNbY3VycmVudE5vZGVdLmxvdyA9IE1hdGgubWluKG5vZGVzW2N1cnJlbnROb2RlXS5sb3csIG5vZGVzW290aGVyTm9kZUlkXS5sb3cpO1xuXG4gICAgICAgICAgICAgIGlmIChub2Rlc1tjdXJyZW50Tm9kZV0uaWQgPD0gbm9kZXNbb3RoZXJOb2RlSWRdLmxvdykge1xuICAgICAgICAgICAgICAgIG5vZGVzW2N1cnJlbnROb2RlXS5jdXRWZXJ0ZXggPSB0cnVlO1xuICAgICAgICAgICAgICAgIGJ1aWxkQ29tcG9uZW50KGN1cnJlbnROb2RlLCBvdGhlck5vZGVJZCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIG5vZGVzW2N1cnJlbnROb2RlXS5sb3cgPSBNYXRoLm1pbihub2Rlc1tjdXJyZW50Tm9kZV0ubG93LCBub2Rlc1tvdGhlck5vZGVJZF0uaWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIGVsZXMuZm9yRWFjaChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICBpZiAoZWxlLmlzTm9kZSgpKSB7XG4gICAgICAgIHZhciBub2RlSWQgPSBlbGUuaWQoKTtcblxuICAgICAgICBpZiAoIShub2RlSWQgaW4gbm9kZXMpKSB7XG4gICAgICAgICAgZWRnZUNvdW50ID0gMDtcbiAgICAgICAgICBiaWNvbm5lY3RlZFNlYXJjaChub2RlSWQsIG5vZGVJZCk7XG4gICAgICAgICAgbm9kZXNbbm9kZUlkXS5jdXRWZXJ0ZXggPSBlZGdlQ291bnQgPiAxO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGN1dFZlcnRpY2VzID0gT2JqZWN0LmtleXMobm9kZXMpLmZpbHRlcihmdW5jdGlvbiAoaWQpIHtcbiAgICAgIHJldHVybiBub2Rlc1tpZF0uY3V0VmVydGV4O1xuICAgIH0pLm1hcChmdW5jdGlvbiAoaWQpIHtcbiAgICAgIHJldHVybiBlbGVzLmdldEVsZW1lbnRCeUlkKGlkKTtcbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgY3V0OiBlbGVzLnNwYXduKGN1dFZlcnRpY2VzKSxcbiAgICAgIGNvbXBvbmVudHM6IGNvbXBvbmVudHNcbiAgICB9O1xuICB9O1xuXG4gIHZhciBob3Bjcm9mdFRhcmphbkJpY29ubmVjdGVkJDEgPSB7XG4gICAgaG9wY3JvZnRUYXJqYW5CaWNvbm5lY3RlZDogaG9wY3JvZnRUYXJqYW5CaWNvbm5lY3RlZCxcbiAgICBodGJjOiBob3Bjcm9mdFRhcmphbkJpY29ubmVjdGVkLFxuICAgIGh0YjogaG9wY3JvZnRUYXJqYW5CaWNvbm5lY3RlZCxcbiAgICBob3Bjcm9mdFRhcmphbkJpY29ubmVjdGVkQ29tcG9uZW50czogaG9wY3JvZnRUYXJqYW5CaWNvbm5lY3RlZFxuICB9O1xuXG4gIHZhciB0YXJqYW5TdHJvbmdseUNvbm5lY3RlZCA9IGZ1bmN0aW9uIHRhcmphblN0cm9uZ2x5Q29ubmVjdGVkKCkge1xuICAgIHZhciBlbGVzID0gdGhpcztcbiAgICB2YXIgbm9kZXMgPSB7fTtcbiAgICB2YXIgaW5kZXggPSAwO1xuICAgIHZhciBjb21wb25lbnRzID0gW107XG4gICAgdmFyIHN0YWNrID0gW107XG4gICAgdmFyIGN1dCA9IGVsZXMuc3Bhd24oZWxlcyk7XG5cbiAgICB2YXIgc3Ryb25nbHlDb25uZWN0ZWRTZWFyY2ggPSBmdW5jdGlvbiBzdHJvbmdseUNvbm5lY3RlZFNlYXJjaChzb3VyY2VOb2RlSWQpIHtcbiAgICAgIHN0YWNrLnB1c2goc291cmNlTm9kZUlkKTtcbiAgICAgIG5vZGVzW3NvdXJjZU5vZGVJZF0gPSB7XG4gICAgICAgIGluZGV4OiBpbmRleCxcbiAgICAgICAgbG93OiBpbmRleCsrLFxuICAgICAgICBleHBsb3JlZDogZmFsc2VcbiAgICAgIH07XG4gICAgICB2YXIgY29ubmVjdGVkRWRnZXMgPSBlbGVzLmdldEVsZW1lbnRCeUlkKHNvdXJjZU5vZGVJZCkuY29ubmVjdGVkRWRnZXMoKS5pbnRlcnNlY3Rpb24oZWxlcyk7XG4gICAgICBjb25uZWN0ZWRFZGdlcy5mb3JFYWNoKGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgICAgIHZhciB0YXJnZXROb2RlSWQgPSBlZGdlLnRhcmdldCgpLmlkKCk7XG5cbiAgICAgICAgaWYgKHRhcmdldE5vZGVJZCAhPT0gc291cmNlTm9kZUlkKSB7XG4gICAgICAgICAgaWYgKCEodGFyZ2V0Tm9kZUlkIGluIG5vZGVzKSkge1xuICAgICAgICAgICAgc3Ryb25nbHlDb25uZWN0ZWRTZWFyY2godGFyZ2V0Tm9kZUlkKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIW5vZGVzW3RhcmdldE5vZGVJZF0uZXhwbG9yZWQpIHtcbiAgICAgICAgICAgIG5vZGVzW3NvdXJjZU5vZGVJZF0ubG93ID0gTWF0aC5taW4obm9kZXNbc291cmNlTm9kZUlkXS5sb3csIG5vZGVzW3RhcmdldE5vZGVJZF0ubG93KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBpZiAobm9kZXNbc291cmNlTm9kZUlkXS5pbmRleCA9PT0gbm9kZXNbc291cmNlTm9kZUlkXS5sb3cpIHtcbiAgICAgICAgdmFyIGNvbXBvbmVudE5vZGVzID0gZWxlcy5zcGF3bigpO1xuXG4gICAgICAgIGZvciAoOzspIHtcbiAgICAgICAgICB2YXIgbm9kZUlkID0gc3RhY2sucG9wKCk7XG4gICAgICAgICAgY29tcG9uZW50Tm9kZXMubWVyZ2UoZWxlcy5nZXRFbGVtZW50QnlJZChub2RlSWQpKTtcbiAgICAgICAgICBub2Rlc1tub2RlSWRdLmxvdyA9IG5vZGVzW3NvdXJjZU5vZGVJZF0uaW5kZXg7XG4gICAgICAgICAgbm9kZXNbbm9kZUlkXS5leHBsb3JlZCA9IHRydWU7XG5cbiAgICAgICAgICBpZiAobm9kZUlkID09PSBzb3VyY2VOb2RlSWQpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBjb21wb25lbnRFZGdlcyA9IGNvbXBvbmVudE5vZGVzLmVkZ2VzV2l0aChjb21wb25lbnROb2Rlcyk7XG4gICAgICAgIHZhciBjb21wb25lbnQgPSBjb21wb25lbnROb2Rlcy5tZXJnZShjb21wb25lbnRFZGdlcyk7XG4gICAgICAgIGNvbXBvbmVudHMucHVzaChjb21wb25lbnQpO1xuICAgICAgICBjdXQgPSBjdXQuZGlmZmVyZW5jZShjb21wb25lbnQpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBlbGVzLmZvckVhY2goZnVuY3Rpb24gKGVsZSkge1xuICAgICAgaWYgKGVsZS5pc05vZGUoKSkge1xuICAgICAgICB2YXIgbm9kZUlkID0gZWxlLmlkKCk7XG5cbiAgICAgICAgaWYgKCEobm9kZUlkIGluIG5vZGVzKSkge1xuICAgICAgICAgIHN0cm9uZ2x5Q29ubmVjdGVkU2VhcmNoKG5vZGVJZCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgY3V0OiBjdXQsXG4gICAgICBjb21wb25lbnRzOiBjb21wb25lbnRzXG4gICAgfTtcbiAgfTtcblxuICB2YXIgdGFyamFuU3Ryb25nbHlDb25uZWN0ZWQkMSA9IHtcbiAgICB0YXJqYW5TdHJvbmdseUNvbm5lY3RlZDogdGFyamFuU3Ryb25nbHlDb25uZWN0ZWQsXG4gICAgdHNjOiB0YXJqYW5TdHJvbmdseUNvbm5lY3RlZCxcbiAgICB0c2NjOiB0YXJqYW5TdHJvbmdseUNvbm5lY3RlZCxcbiAgICB0YXJqYW5TdHJvbmdseUNvbm5lY3RlZENvbXBvbmVudHM6IHRhcmphblN0cm9uZ2x5Q29ubmVjdGVkXG4gIH07XG5cbiAgdmFyIGVsZXNmbiRqID0ge307XG4gIFtlbGVzZm4kdiwgZWxlc2ZuJHUsIGVsZXNmbiR0LCBlbGVzZm4kcywgZWxlc2ZuJHIsIGVsZXNmbiRxLCBlbGVzZm4kcCwgZWxlc2ZuJG8sIGVsZXNmbiRuLCBlbGVzZm4kbSwgZWxlc2ZuJGwsIG1hcmtvdkNsdXN0ZXJpbmckMSwga0NsdXN0ZXJpbmcsIGhpZXJhcmNoaWNhbENsdXN0ZXJpbmckMSwgYWZmaW5pdHlQcm9wYWdhdGlvbiQxLCBlbGVzZm4kaywgaG9wY3JvZnRUYXJqYW5CaWNvbm5lY3RlZCQxLCB0YXJqYW5TdHJvbmdseUNvbm5lY3RlZCQxXS5mb3JFYWNoKGZ1bmN0aW9uIChwcm9wcykge1xuICAgIGV4dGVuZChlbGVzZm4kaiwgcHJvcHMpO1xuICB9KTtcblxuICAvKiFcbiAgRW1iZWRkYWJsZSBNaW5pbXVtIFN0cmljdGx5LUNvbXBsaWFudCBQcm9taXNlcy9BKyAxLjEuMSBUaGVuYWJsZVxuICBDb3B5cmlnaHQgKGMpIDIwMTMtMjAxNCBSYWxmIFMuIEVuZ2Vsc2NoYWxsIChodHRwOi8vZW5nZWxzY2hhbGwuY29tKVxuICBMaWNlbnNlZCB1bmRlciBUaGUgTUlUIExpY2Vuc2UgKGh0dHA6Ly9vcGVuc291cmNlLm9yZy9saWNlbnNlcy9NSVQpXG4gICovXG5cbiAgLyogIHByb21pc2Ugc3RhdGVzIFtQcm9taXNlcy9BKyAyLjFdICAqL1xuICB2YXIgU1RBVEVfUEVORElORyA9IDA7XG4gIC8qICBbUHJvbWlzZXMvQSsgMi4xLjFdICAqL1xuXG4gIHZhciBTVEFURV9GVUxGSUxMRUQgPSAxO1xuICAvKiAgW1Byb21pc2VzL0ErIDIuMS4yXSAgKi9cblxuICB2YXIgU1RBVEVfUkVKRUNURUQgPSAyO1xuICAvKiAgW1Byb21pc2VzL0ErIDIuMS4zXSAgKi9cblxuICAvKiAgcHJvbWlzZSBvYmplY3QgY29uc3RydWN0b3IgICovXG5cbiAgdmFyIGFwaSA9IGZ1bmN0aW9uIGFwaShleGVjdXRvcikge1xuICAgIC8qICBvcHRpb25hbGx5IHN1cHBvcnQgbm9uLWNvbnN0cnVjdG9yL3BsYWluLWZ1bmN0aW9uIGNhbGwgICovXG4gICAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIGFwaSkpIHJldHVybiBuZXcgYXBpKGV4ZWN1dG9yKTtcbiAgICAvKiAgaW5pdGlhbGl6ZSBvYmplY3QgICovXG5cbiAgICB0aGlzLmlkID0gJ1RoZW5hYmxlLzEuMC43JztcbiAgICB0aGlzLnN0YXRlID0gU1RBVEVfUEVORElORztcbiAgICAvKiAgaW5pdGlhbCBzdGF0ZSAgKi9cblxuICAgIHRoaXMuZnVsZmlsbFZhbHVlID0gdW5kZWZpbmVkO1xuICAgIC8qICBpbml0aWFsIHZhbHVlICAqL1xuXG4gICAgLyogIFtQcm9taXNlcy9BKyAxLjMsIDIuMS4yLjJdICAqL1xuXG4gICAgdGhpcy5yZWplY3RSZWFzb24gPSB1bmRlZmluZWQ7XG4gICAgLyogIGluaXRpYWwgcmVhc29uICovXG5cbiAgICAvKiAgW1Byb21pc2VzL0ErIDEuNSwgMi4xLjMuMl0gICovXG5cbiAgICB0aGlzLm9uRnVsZmlsbGVkID0gW107XG4gICAgLyogIGluaXRpYWwgaGFuZGxlcnMgICovXG5cbiAgICB0aGlzLm9uUmVqZWN0ZWQgPSBbXTtcbiAgICAvKiAgaW5pdGlhbCBoYW5kbGVycyAgKi9cblxuICAgIC8qICBwcm92aWRlIG9wdGlvbmFsIGluZm9ybWF0aW9uLWhpZGluZyBwcm94eSAgKi9cblxuICAgIHRoaXMucHJveHkgPSB7XG4gICAgICB0aGVuOiB0aGlzLnRoZW4uYmluZCh0aGlzKVxuICAgIH07XG4gICAgLyogIHN1cHBvcnQgb3B0aW9uYWwgZXhlY3V0b3IgZnVuY3Rpb24gICovXG5cbiAgICBpZiAodHlwZW9mIGV4ZWN1dG9yID09PSAnZnVuY3Rpb24nKSBleGVjdXRvci5jYWxsKHRoaXMsIHRoaXMuZnVsZmlsbC5iaW5kKHRoaXMpLCB0aGlzLnJlamVjdC5iaW5kKHRoaXMpKTtcbiAgfTtcbiAgLyogIHByb21pc2UgQVBJIG1ldGhvZHMgICovXG5cblxuICBhcGkucHJvdG90eXBlID0ge1xuICAgIC8qICBwcm9taXNlIHJlc29sdmluZyBtZXRob2RzICAqL1xuICAgIGZ1bGZpbGw6IGZ1bmN0aW9uIGZ1bGZpbGwodmFsdWUpIHtcbiAgICAgIHJldHVybiBkZWxpdmVyKHRoaXMsIFNUQVRFX0ZVTEZJTExFRCwgJ2Z1bGZpbGxWYWx1ZScsIHZhbHVlKTtcbiAgICB9LFxuICAgIHJlamVjdDogZnVuY3Rpb24gcmVqZWN0KHZhbHVlKSB7XG4gICAgICByZXR1cm4gZGVsaXZlcih0aGlzLCBTVEFURV9SRUpFQ1RFRCwgJ3JlamVjdFJlYXNvbicsIHZhbHVlKTtcbiAgICB9LFxuXG4gICAgLyogIFwiVGhlIHRoZW4gTWV0aG9kXCIgW1Byb21pc2VzL0ErIDEuMSwgMS4yLCAyLjJdICAqL1xuICAgIHRoZW46IGZ1bmN0aW9uIHRoZW4ob25GdWxmaWxsZWQsIG9uUmVqZWN0ZWQpIHtcbiAgICAgIHZhciBjdXJyID0gdGhpcztcbiAgICAgIHZhciBuZXh0ID0gbmV3IGFwaSgpO1xuICAgICAgLyogIFtQcm9taXNlcy9BKyAyLjIuN10gICovXG5cbiAgICAgIGN1cnIub25GdWxmaWxsZWQucHVzaChyZXNvbHZlcihvbkZ1bGZpbGxlZCwgbmV4dCwgJ2Z1bGZpbGwnKSk7XG4gICAgICAvKiAgW1Byb21pc2VzL0ErIDIuMi4yLzIuMi42XSAgKi9cblxuICAgICAgY3Vyci5vblJlamVjdGVkLnB1c2gocmVzb2x2ZXIob25SZWplY3RlZCwgbmV4dCwgJ3JlamVjdCcpKTtcbiAgICAgIC8qICBbUHJvbWlzZXMvQSsgMi4yLjMvMi4yLjZdICAqL1xuXG4gICAgICBleGVjdXRlKGN1cnIpO1xuICAgICAgcmV0dXJuIG5leHQucHJveHk7XG4gICAgICAvKiAgW1Byb21pc2VzL0ErIDIuMi43LCAzLjNdICAqL1xuICAgIH1cbiAgfTtcbiAgLyogIGRlbGl2ZXIgYW4gYWN0aW9uICAqL1xuXG4gIHZhciBkZWxpdmVyID0gZnVuY3Rpb24gZGVsaXZlcihjdXJyLCBzdGF0ZSwgbmFtZSwgdmFsdWUpIHtcbiAgICBpZiAoY3Vyci5zdGF0ZSA9PT0gU1RBVEVfUEVORElORykge1xuICAgICAgY3Vyci5zdGF0ZSA9IHN0YXRlO1xuICAgICAgLyogIFtQcm9taXNlcy9BKyAyLjEuMi4xLCAyLjEuMy4xXSAgKi9cblxuICAgICAgY3VycltuYW1lXSA9IHZhbHVlO1xuICAgICAgLyogIFtQcm9taXNlcy9BKyAyLjEuMi4yLCAyLjEuMy4yXSAgKi9cblxuICAgICAgZXhlY3V0ZShjdXJyKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY3VycjtcbiAgfTtcbiAgLyogIGV4ZWN1dGUgYWxsIGhhbmRsZXJzICAqL1xuXG5cbiAgdmFyIGV4ZWN1dGUgPSBmdW5jdGlvbiBleGVjdXRlKGN1cnIpIHtcbiAgICBpZiAoY3Vyci5zdGF0ZSA9PT0gU1RBVEVfRlVMRklMTEVEKSBleGVjdXRlX2hhbmRsZXJzKGN1cnIsICdvbkZ1bGZpbGxlZCcsIGN1cnIuZnVsZmlsbFZhbHVlKTtlbHNlIGlmIChjdXJyLnN0YXRlID09PSBTVEFURV9SRUpFQ1RFRCkgZXhlY3V0ZV9oYW5kbGVycyhjdXJyLCAnb25SZWplY3RlZCcsIGN1cnIucmVqZWN0UmVhc29uKTtcbiAgfTtcbiAgLyogIGV4ZWN1dGUgcGFydGljdWxhciBzZXQgb2YgaGFuZGxlcnMgICovXG5cblxuICB2YXIgZXhlY3V0ZV9oYW5kbGVycyA9IGZ1bmN0aW9uIGV4ZWN1dGVfaGFuZGxlcnMoY3VyciwgbmFtZSwgdmFsdWUpIHtcbiAgICAvKiBnbG9iYWwgc2V0SW1tZWRpYXRlOiB0cnVlICovXG5cbiAgICAvKiBnbG9iYWwgc2V0VGltZW91dDogdHJ1ZSAqL1xuXG4gICAgLyogIHNob3J0LWNpcmN1aXQgcHJvY2Vzc2luZyAgKi9cbiAgICBpZiAoY3VycltuYW1lXS5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICAvKiAgaXRlcmF0ZSBvdmVyIGFsbCBoYW5kbGVycywgZXhhY3RseSBvbmNlICAqL1xuXG4gICAgdmFyIGhhbmRsZXJzID0gY3VycltuYW1lXTtcbiAgICBjdXJyW25hbWVdID0gW107XG4gICAgLyogIFtQcm9taXNlcy9BKyAyLjIuMi4zLCAyLjIuMy4zXSAgKi9cblxuICAgIHZhciBmdW5jID0gZnVuY3Rpb24gZnVuYygpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaGFuZGxlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaGFuZGxlcnNbaV0odmFsdWUpO1xuICAgICAgfVxuICAgICAgLyogIFtQcm9taXNlcy9BKyAyLjIuNV0gICovXG5cbiAgICB9O1xuICAgIC8qICBleGVjdXRlIHByb2NlZHVyZSBhc3luY2hyb25vdXNseSAgKi9cblxuICAgIC8qICBbUHJvbWlzZXMvQSsgMi4yLjQsIDMuMV0gICovXG5cblxuICAgIGlmICh0eXBlb2Ygc2V0SW1tZWRpYXRlID09PSAnZnVuY3Rpb24nKSBzZXRJbW1lZGlhdGUoZnVuYyk7ZWxzZSBzZXRUaW1lb3V0KGZ1bmMsIDApO1xuICB9O1xuICAvKiAgZ2VuZXJhdGUgYSByZXNvbHZlciBmdW5jdGlvbiAgKi9cblxuXG4gIHZhciByZXNvbHZlciA9IGZ1bmN0aW9uIHJlc29sdmVyKGNiLCBuZXh0LCBtZXRob2QpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICBpZiAodHlwZW9mIGNiICE9PSAnZnVuY3Rpb24nKVxuICAgICAgICAvKiAgW1Byb21pc2VzL0ErIDIuMi4xLCAyLjIuNy4zLCAyLjIuNy40XSAgKi9cbiAgICAgICAgbmV4dFttZXRob2RdLmNhbGwobmV4dCwgdmFsdWUpO1xuICAgICAgICAvKiAgW1Byb21pc2VzL0ErIDIuMi43LjMsIDIuMi43LjRdICAqL1xuICAgICAgZWxzZSB7XG4gICAgICAgIHZhciByZXN1bHQ7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICByZXN1bHQgPSBjYih2YWx1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgLyogIFtQcm9taXNlcy9BKyAyLjIuMi4xLCAyLjIuMy4xLCAyLjIuNSwgMy4yXSAgKi9cbiAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICBuZXh0LnJlamVjdChlKTtcbiAgICAgICAgICAvKiAgW1Byb21pc2VzL0ErIDIuMi43LjJdICAqL1xuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgcmVzb2x2ZShuZXh0LCByZXN1bHQpO1xuICAgICAgICAvKiAgW1Byb21pc2VzL0ErIDIuMi43LjFdICAqL1xuICAgICAgfVxuICAgIH07XG4gIH07XG4gIC8qICBcIlByb21pc2UgUmVzb2x1dGlvbiBQcm9jZWR1cmVcIiAgKi9cblxuICAvKiAgW1Byb21pc2VzL0ErIDIuM10gICovXG5cblxuICB2YXIgcmVzb2x2ZSA9IGZ1bmN0aW9uIHJlc29sdmUocHJvbWlzZSwgeCkge1xuICAgIC8qICBzYW5pdHkgY2hlY2sgYXJndW1lbnRzICAqL1xuXG4gICAgLyogIFtQcm9taXNlcy9BKyAyLjMuMV0gICovXG4gICAgaWYgKHByb21pc2UgPT09IHggfHwgcHJvbWlzZS5wcm94eSA9PT0geCkge1xuICAgICAgcHJvbWlzZS5yZWplY3QobmV3IFR5cGVFcnJvcignY2Fubm90IHJlc29sdmUgcHJvbWlzZSB3aXRoIGl0c2VsZicpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLyogIHN1cmdpY2FsbHkgY2hlY2sgZm9yIGEgXCJ0aGVuXCIgbWV0aG9kXG4gICAgICAobWFpbmx5IHRvIGp1c3QgY2FsbCB0aGUgXCJnZXR0ZXJcIiBvZiBcInRoZW5cIiBvbmx5IG9uY2UpICAqL1xuXG5cbiAgICB2YXIgdGhlbjtcblxuICAgIGlmIChfdHlwZW9mKHgpID09PSAnb2JqZWN0JyAmJiB4ICE9PSBudWxsIHx8IHR5cGVvZiB4ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0cnkge1xuICAgICAgICB0aGVuID0geC50aGVuO1xuICAgICAgfVxuICAgICAgLyogIFtQcm9taXNlcy9BKyAyLjMuMy4xLCAzLjVdICAqL1xuICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgcHJvbWlzZS5yZWplY3QoZSk7XG4gICAgICAgIC8qICBbUHJvbWlzZXMvQSsgMi4zLjMuMl0gICovXG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICAvKiAgaGFuZGxlIG93biBUaGVuYWJsZXMgICAgW1Byb21pc2VzL0ErIDIuMy4yXVxuICAgICAgYW5kIHNpbWlsYXIgXCJ0aGVuYWJsZXNcIiBbUHJvbWlzZXMvQSsgMi4zLjNdICAqL1xuXG5cbiAgICBpZiAodHlwZW9mIHRoZW4gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHZhciByZXNvbHZlZCA9IGZhbHNlO1xuXG4gICAgICB0cnkge1xuICAgICAgICAvKiAgY2FsbCByZXRyaWV2ZWQgXCJ0aGVuXCIgbWV0aG9kICovXG5cbiAgICAgICAgLyogIFtQcm9taXNlcy9BKyAyLjMuMy4zXSAgKi9cbiAgICAgICAgdGhlbi5jYWxsKHgsXG4gICAgICAgIC8qICByZXNvbHZlUHJvbWlzZSAgKi9cblxuICAgICAgICAvKiAgW1Byb21pc2VzL0ErIDIuMy4zLjMuMV0gICovXG4gICAgICAgIGZ1bmN0aW9uICh5KSB7XG4gICAgICAgICAgaWYgKHJlc29sdmVkKSByZXR1cm47XG4gICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgIC8qICBbUHJvbWlzZXMvQSsgMi4zLjMuMy4zXSAgKi9cblxuICAgICAgICAgIGlmICh5ID09PSB4KVxuICAgICAgICAgICAgLyogIFtQcm9taXNlcy9BKyAzLjZdICAqL1xuICAgICAgICAgICAgcHJvbWlzZS5yZWplY3QobmV3IFR5cGVFcnJvcignY2lyY3VsYXIgdGhlbmFibGUgY2hhaW4nKSk7ZWxzZSByZXNvbHZlKHByb21pc2UsIHkpO1xuICAgICAgICB9LFxuICAgICAgICAvKiAgcmVqZWN0UHJvbWlzZSAgKi9cblxuICAgICAgICAvKiAgW1Byb21pc2VzL0ErIDIuMy4zLjMuMl0gICovXG4gICAgICAgIGZ1bmN0aW9uIChyKSB7XG4gICAgICAgICAgaWYgKHJlc29sdmVkKSByZXR1cm47XG4gICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgIC8qICBbUHJvbWlzZXMvQSsgMi4zLjMuMy4zXSAgKi9cblxuICAgICAgICAgIHByb21pc2UucmVqZWN0KHIpO1xuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKCFyZXNvbHZlZClcbiAgICAgICAgICAvKiAgW1Byb21pc2VzL0ErIDIuMy4zLjMuM10gICovXG4gICAgICAgICAgcHJvbWlzZS5yZWplY3QoZSk7XG4gICAgICAgIC8qICBbUHJvbWlzZXMvQSsgMi4zLjMuMy40XSAgKi9cbiAgICAgIH1cblxuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvKiAgaGFuZGxlIG90aGVyIHZhbHVlcyAgKi9cblxuXG4gICAgcHJvbWlzZS5mdWxmaWxsKHgpO1xuICAgIC8qICBbUHJvbWlzZXMvQSsgMi4zLjQsIDIuMy4zLjRdICAqL1xuICB9OyAvLyBzbyB3ZSBhbHdheXMgaGF2ZSBQcm9taXNlLmFsbCgpXG5cblxuICBhcGkuYWxsID0gZnVuY3Rpb24gKHBzKSB7XG4gICAgcmV0dXJuIG5ldyBhcGkoZnVuY3Rpb24gKHJlc29sdmVBbGwsIHJlamVjdEFsbCkge1xuICAgICAgdmFyIHZhbHMgPSBuZXcgQXJyYXkocHMubGVuZ3RoKTtcbiAgICAgIHZhciBkb25lQ291bnQgPSAwO1xuXG4gICAgICB2YXIgZnVsZmlsbCA9IGZ1bmN0aW9uIGZ1bGZpbGwoaSwgdmFsKSB7XG4gICAgICAgIHZhbHNbaV0gPSB2YWw7XG4gICAgICAgIGRvbmVDb3VudCsrO1xuXG4gICAgICAgIGlmIChkb25lQ291bnQgPT09IHBzLmxlbmd0aCkge1xuICAgICAgICAgIHJlc29sdmVBbGwodmFscyk7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKGZ1bmN0aW9uIChpKSB7XG4gICAgICAgICAgdmFyIHAgPSBwc1tpXTtcbiAgICAgICAgICB2YXIgaXNQcm9taXNlID0gcCAhPSBudWxsICYmIHAudGhlbiAhPSBudWxsO1xuXG4gICAgICAgICAgaWYgKGlzUHJvbWlzZSkge1xuICAgICAgICAgICAgcC50aGVuKGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgICAgICAgZnVsZmlsbChpLCB2YWwpO1xuICAgICAgICAgICAgfSwgZnVuY3Rpb24gKGVycikge1xuICAgICAgICAgICAgICByZWplY3RBbGwoZXJyKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgdmFsID0gcDtcbiAgICAgICAgICAgIGZ1bGZpbGwoaSwgdmFsKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pKGkpO1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIGFwaS5yZXNvbHZlID0gZnVuY3Rpb24gKHZhbCkge1xuICAgIHJldHVybiBuZXcgYXBpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgIHJlc29sdmUodmFsKTtcbiAgICB9KTtcbiAgfTtcblxuICBhcGkucmVqZWN0ID0gZnVuY3Rpb24gKHZhbCkge1xuICAgIHJldHVybiBuZXcgYXBpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgIHJlamVjdCh2YWwpO1xuICAgIH0pO1xuICB9O1xuXG4gIHZhciBQcm9taXNlJDEgPSB0eXBlb2YgUHJvbWlzZSAhPT0gJ3VuZGVmaW5lZCcgPyBQcm9taXNlIDogYXBpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cbiAgdmFyIEFuaW1hdGlvbiA9IGZ1bmN0aW9uIEFuaW1hdGlvbih0YXJnZXQsIG9wdHMsIG9wdHMyKSB7XG4gICAgdmFyIGlzQ29yZSA9IGNvcmUodGFyZ2V0KTtcbiAgICB2YXIgaXNFbGUgPSAhaXNDb3JlO1xuXG4gICAgdmFyIF9wID0gdGhpcy5fcHJpdmF0ZSA9IGV4dGVuZCh7XG4gICAgICBkdXJhdGlvbjogMTAwMFxuICAgIH0sIG9wdHMsIG9wdHMyKTtcblxuICAgIF9wLnRhcmdldCA9IHRhcmdldDtcbiAgICBfcC5zdHlsZSA9IF9wLnN0eWxlIHx8IF9wLmNzcztcbiAgICBfcC5zdGFydGVkID0gZmFsc2U7XG4gICAgX3AucGxheWluZyA9IGZhbHNlO1xuICAgIF9wLmhvb2tlZCA9IGZhbHNlO1xuICAgIF9wLmFwcGx5aW5nID0gZmFsc2U7XG4gICAgX3AucHJvZ3Jlc3MgPSAwO1xuICAgIF9wLmNvbXBsZXRlcyA9IFtdO1xuICAgIF9wLmZyYW1lcyA9IFtdO1xuXG4gICAgaWYgKF9wLmNvbXBsZXRlICYmIGZuJDYoX3AuY29tcGxldGUpKSB7XG4gICAgICBfcC5jb21wbGV0ZXMucHVzaChfcC5jb21wbGV0ZSk7XG4gICAgfVxuXG4gICAgaWYgKGlzRWxlKSB7XG4gICAgICB2YXIgcG9zID0gdGFyZ2V0LnBvc2l0aW9uKCk7XG4gICAgICBfcC5zdGFydFBvc2l0aW9uID0gX3Auc3RhcnRQb3NpdGlvbiB8fCB7XG4gICAgICAgIHg6IHBvcy54LFxuICAgICAgICB5OiBwb3MueVxuICAgICAgfTtcbiAgICAgIF9wLnN0YXJ0U3R5bGUgPSBfcC5zdGFydFN0eWxlIHx8IHRhcmdldC5jeSgpLnN0eWxlKCkuZ2V0QW5pbWF0aW9uU3RhcnRTdHlsZSh0YXJnZXQsIF9wLnN0eWxlKTtcbiAgICB9XG5cbiAgICBpZiAoaXNDb3JlKSB7XG4gICAgICB2YXIgcGFuID0gdGFyZ2V0LnBhbigpO1xuICAgICAgX3Auc3RhcnRQYW4gPSB7XG4gICAgICAgIHg6IHBhbi54LFxuICAgICAgICB5OiBwYW4ueVxuICAgICAgfTtcbiAgICAgIF9wLnN0YXJ0Wm9vbSA9IHRhcmdldC56b29tKCk7XG4gICAgfSAvLyBmb3IgZnV0dXJlIHRpbWVsaW5lL2FuaW1hdGlvbnMgaW1wbFxuXG5cbiAgICB0aGlzLmxlbmd0aCA9IDE7XG4gICAgdGhpc1swXSA9IHRoaXM7XG4gIH07XG5cbiAgdmFyIGFuaWZuID0gQW5pbWF0aW9uLnByb3RvdHlwZTtcbiAgZXh0ZW5kKGFuaWZuLCB7XG4gICAgaW5zdGFuY2VTdHJpbmc6IGZ1bmN0aW9uIGluc3RhbmNlU3RyaW5nKCkge1xuICAgICAgcmV0dXJuICdhbmltYXRpb24nO1xuICAgIH0sXG4gICAgaG9vazogZnVuY3Rpb24gaG9vaygpIHtcbiAgICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG5cbiAgICAgIGlmICghX3AuaG9va2VkKSB7XG4gICAgICAgIC8vIGFkZCB0byB0YXJnZXQncyBhbmltYXRpb24gcXVldWVcbiAgICAgICAgdmFyIHE7XG4gICAgICAgIHZhciB0QW5pID0gX3AudGFyZ2V0Ll9wcml2YXRlLmFuaW1hdGlvbjtcblxuICAgICAgICBpZiAoX3AucXVldWUpIHtcbiAgICAgICAgICBxID0gdEFuaS5xdWV1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBxID0gdEFuaS5jdXJyZW50O1xuICAgICAgICB9XG5cbiAgICAgICAgcS5wdXNoKHRoaXMpOyAvLyBhZGQgdG8gdGhlIGFuaW1hdGlvbiBsb29wIHBvb2xcblxuICAgICAgICBpZiAoZWxlbWVudE9yQ29sbGVjdGlvbihfcC50YXJnZXQpKSB7XG4gICAgICAgICAgX3AudGFyZ2V0LmN5KCkuYWRkVG9BbmltYXRpb25Qb29sKF9wLnRhcmdldCk7XG4gICAgICAgIH1cblxuICAgICAgICBfcC5ob29rZWQgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIHBsYXk6IGZ1bmN0aW9uIHBsYXkoKSB7XG4gICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlOyAvLyBhdXRvcmV3aW5kXG5cbiAgICAgIGlmIChfcC5wcm9ncmVzcyA9PT0gMSkge1xuICAgICAgICBfcC5wcm9ncmVzcyA9IDA7XG4gICAgICB9XG5cbiAgICAgIF9wLnBsYXlpbmcgPSB0cnVlO1xuICAgICAgX3Auc3RhcnRlZCA9IGZhbHNlOyAvLyBuZWVkcyB0byBiZSBzdGFydGVkIGJ5IGFuaW1hdGlvbiBsb29wXG5cbiAgICAgIF9wLnN0b3BwZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuaG9vaygpOyAvLyB0aGUgYW5pbWF0aW9uIGxvb3Agd2lsbCBzdGFydCB0aGUgYW5pbWF0aW9uLi4uXG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgcGxheWluZzogZnVuY3Rpb24gcGxheWluZygpIHtcbiAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLnBsYXlpbmc7XG4gICAgfSxcbiAgICBhcHBseTogZnVuY3Rpb24gYXBwbHkoKSB7XG4gICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuICAgICAgX3AuYXBwbHlpbmcgPSB0cnVlO1xuICAgICAgX3Auc3RhcnRlZCA9IGZhbHNlOyAvLyBuZWVkcyB0byBiZSBzdGFydGVkIGJ5IGFuaW1hdGlvbiBsb29wXG5cbiAgICAgIF9wLnN0b3BwZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuaG9vaygpOyAvLyB0aGUgYW5pbWF0aW9uIGxvb3Agd2lsbCBhcHBseSB0aGUgYW5pbWF0aW9uIGF0IHRoaXMgcHJvZ3Jlc3NcblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICBhcHBseWluZzogZnVuY3Rpb24gYXBwbHlpbmcoKSB7XG4gICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5hcHBseWluZztcbiAgICB9LFxuICAgIHBhdXNlOiBmdW5jdGlvbiBwYXVzZSgpIHtcbiAgICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG4gICAgICBfcC5wbGF5aW5nID0gZmFsc2U7XG4gICAgICBfcC5zdGFydGVkID0gZmFsc2U7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIHN0b3A6IGZ1bmN0aW9uIHN0b3AoKSB7XG4gICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuICAgICAgX3AucGxheWluZyA9IGZhbHNlO1xuICAgICAgX3Auc3RhcnRlZCA9IGZhbHNlO1xuICAgICAgX3Auc3RvcHBlZCA9IHRydWU7IC8vIHRvIGJlIHJlbW92ZWQgZnJvbSBhbmltYXRpb24gcXVldWVzXG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgcmV3aW5kOiBmdW5jdGlvbiByZXdpbmQoKSB7XG4gICAgICByZXR1cm4gdGhpcy5wcm9ncmVzcygwKTtcbiAgICB9LFxuICAgIGZhc3Rmb3J3YXJkOiBmdW5jdGlvbiBmYXN0Zm9yd2FyZCgpIHtcbiAgICAgIHJldHVybiB0aGlzLnByb2dyZXNzKDEpO1xuICAgIH0sXG4gICAgdGltZTogZnVuY3Rpb24gdGltZSh0KSB7XG4gICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuXG4gICAgICBpZiAodCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBfcC5wcm9ncmVzcyAqIF9wLmR1cmF0aW9uO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucHJvZ3Jlc3ModCAvIF9wLmR1cmF0aW9uKTtcbiAgICAgIH1cbiAgICB9LFxuICAgIHByb2dyZXNzOiBmdW5jdGlvbiBwcm9ncmVzcyhwKSB7XG4gICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuICAgICAgdmFyIHdhc1BsYXlpbmcgPSBfcC5wbGF5aW5nO1xuXG4gICAgICBpZiAocCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBfcC5wcm9ncmVzcztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICh3YXNQbGF5aW5nKSB7XG4gICAgICAgICAgdGhpcy5wYXVzZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgX3AucHJvZ3Jlc3MgPSBwO1xuICAgICAgICBfcC5zdGFydGVkID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKHdhc1BsYXlpbmcpIHtcbiAgICAgICAgICB0aGlzLnBsYXkoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIGNvbXBsZXRlZDogZnVuY3Rpb24gY29tcGxldGVkKCkge1xuICAgICAgcmV0dXJuIHRoaXMuX3ByaXZhdGUucHJvZ3Jlc3MgPT09IDE7XG4gICAgfSxcbiAgICByZXZlcnNlOiBmdW5jdGlvbiByZXZlcnNlKCkge1xuICAgICAgdmFyIF9wID0gdGhpcy5fcHJpdmF0ZTtcbiAgICAgIHZhciB3YXNQbGF5aW5nID0gX3AucGxheWluZztcblxuICAgICAgaWYgKHdhc1BsYXlpbmcpIHtcbiAgICAgICAgdGhpcy5wYXVzZSgpO1xuICAgICAgfVxuXG4gICAgICBfcC5wcm9ncmVzcyA9IDEgLSBfcC5wcm9ncmVzcztcbiAgICAgIF9wLnN0YXJ0ZWQgPSBmYWxzZTtcblxuICAgICAgdmFyIHN3YXAgPSBmdW5jdGlvbiBzd2FwKGEsIGIpIHtcbiAgICAgICAgdmFyIF9wYSA9IF9wW2FdO1xuXG4gICAgICAgIGlmIChfcGEgPT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF9wW2FdID0gX3BbYl07XG4gICAgICAgIF9wW2JdID0gX3BhO1xuICAgICAgfTtcblxuICAgICAgc3dhcCgnem9vbScsICdzdGFydFpvb20nKTtcbiAgICAgIHN3YXAoJ3BhbicsICdzdGFydFBhbicpO1xuICAgICAgc3dhcCgncG9zaXRpb24nLCAnc3RhcnRQb3NpdGlvbicpOyAvLyBzd2FwIHN0eWxlc1xuXG4gICAgICBpZiAoX3Auc3R5bGUpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBfcC5zdHlsZS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBwcm9wID0gX3Auc3R5bGVbaV07XG4gICAgICAgICAgdmFyIG5hbWUgPSBwcm9wLm5hbWU7XG4gICAgICAgICAgdmFyIHN0YXJ0U3R5bGVQcm9wID0gX3Auc3RhcnRTdHlsZVtuYW1lXTtcbiAgICAgICAgICBfcC5zdGFydFN0eWxlW25hbWVdID0gcHJvcDtcbiAgICAgICAgICBfcC5zdHlsZVtpXSA9IHN0YXJ0U3R5bGVQcm9wO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh3YXNQbGF5aW5nKSB7XG4gICAgICAgIHRoaXMucGxheSgpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIHByb21pc2U6IGZ1bmN0aW9uIHByb21pc2UodHlwZSkge1xuICAgICAgdmFyIF9wID0gdGhpcy5fcHJpdmF0ZTtcbiAgICAgIHZhciBhcnI7XG5cbiAgICAgIHN3aXRjaCAodHlwZSkge1xuICAgICAgICBjYXNlICdmcmFtZSc6XG4gICAgICAgICAgYXJyID0gX3AuZnJhbWVzO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGNhc2UgJ2NvbXBsZXRlJzpcbiAgICAgICAgY2FzZSAnY29tcGxldGVkJzpcbiAgICAgICAgICBhcnIgPSBfcC5jb21wbGV0ZXM7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSQxKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgICAgYXJyLnB1c2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9XG4gIH0pO1xuICBhbmlmbi5jb21wbGV0ZSA9IGFuaWZuLmNvbXBsZXRlZDtcbiAgYW5pZm4ucnVuID0gYW5pZm4ucGxheTtcbiAgYW5pZm4ucnVubmluZyA9IGFuaWZuLnBsYXlpbmc7XG5cbiAgdmFyIGRlZmluZSQzID0ge1xuICAgIGFuaW1hdGVkOiBmdW5jdGlvbiBhbmltYXRlZCgpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiBhbmltYXRlZEltcGwoKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgdmFyIHNlbGZJc0FycmF5TGlrZSA9IHNlbGYubGVuZ3RoICE9PSB1bmRlZmluZWQ7XG4gICAgICAgIHZhciBhbGwgPSBzZWxmSXNBcnJheUxpa2UgPyBzZWxmIDogW3NlbGZdOyAvLyBwdXQgaW4gYXJyYXkgaWYgbm90IGFycmF5LWxpa2VcblxuICAgICAgICB2YXIgY3kgPSB0aGlzLl9wcml2YXRlLmN5IHx8IHRoaXM7XG5cbiAgICAgICAgaWYgKCFjeS5zdHlsZUVuYWJsZWQoKSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBlbGUgPSBhbGxbMF07XG5cbiAgICAgICAgaWYgKGVsZSkge1xuICAgICAgICAgIHJldHVybiBlbGUuX3ByaXZhdGUuYW5pbWF0aW9uLmN1cnJlbnQubGVuZ3RoID4gMDtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9LFxuICAgIC8vIGFuaW1hdGVkXG4gICAgY2xlYXJRdWV1ZTogZnVuY3Rpb24gY2xlYXJRdWV1ZSgpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiBjbGVhclF1ZXVlSW1wbCgpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB2YXIgc2VsZklzQXJyYXlMaWtlID0gc2VsZi5sZW5ndGggIT09IHVuZGVmaW5lZDtcbiAgICAgICAgdmFyIGFsbCA9IHNlbGZJc0FycmF5TGlrZSA/IHNlbGYgOiBbc2VsZl07IC8vIHB1dCBpbiBhcnJheSBpZiBub3QgYXJyYXktbGlrZVxuXG4gICAgICAgIHZhciBjeSA9IHRoaXMuX3ByaXZhdGUuY3kgfHwgdGhpcztcblxuICAgICAgICBpZiAoIWN5LnN0eWxlRW5hYmxlZCgpKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFsbC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBlbGUgPSBhbGxbaV07XG4gICAgICAgICAgZWxlLl9wcml2YXRlLmFuaW1hdGlvbi5xdWV1ZSA9IFtdO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9O1xuICAgIH0sXG4gICAgLy8gY2xlYXJRdWV1ZVxuICAgIGRlbGF5OiBmdW5jdGlvbiBkZWxheSgpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiBkZWxheUltcGwodGltZSwgY29tcGxldGUpIHtcbiAgICAgICAgdmFyIGN5ID0gdGhpcy5fcHJpdmF0ZS5jeSB8fCB0aGlzO1xuXG4gICAgICAgIGlmICghY3kuc3R5bGVFbmFibGVkKCkpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLmFuaW1hdGUoe1xuICAgICAgICAgIGRlbGF5OiB0aW1lLFxuICAgICAgICAgIGR1cmF0aW9uOiB0aW1lLFxuICAgICAgICAgIGNvbXBsZXRlOiBjb21wbGV0ZVxuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgfSxcbiAgICAvLyBkZWxheVxuICAgIGRlbGF5QW5pbWF0aW9uOiBmdW5jdGlvbiBkZWxheUFuaW1hdGlvbigpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiBkZWxheUFuaW1hdGlvbkltcGwodGltZSwgY29tcGxldGUpIHtcbiAgICAgICAgdmFyIGN5ID0gdGhpcy5fcHJpdmF0ZS5jeSB8fCB0aGlzO1xuXG4gICAgICAgIGlmICghY3kuc3R5bGVFbmFibGVkKCkpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLmFuaW1hdGlvbih7XG4gICAgICAgICAgZGVsYXk6IHRpbWUsXG4gICAgICAgICAgZHVyYXRpb246IHRpbWUsXG4gICAgICAgICAgY29tcGxldGU6IGNvbXBsZXRlXG4gICAgICAgIH0pO1xuICAgICAgfTtcbiAgICB9LFxuICAgIC8vIGRlbGF5XG4gICAgYW5pbWF0aW9uOiBmdW5jdGlvbiBhbmltYXRpb24oKSB7XG4gICAgICByZXR1cm4gZnVuY3Rpb24gYW5pbWF0aW9uSW1wbChwcm9wZXJ0aWVzLCBwYXJhbXMpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB2YXIgc2VsZklzQXJyYXlMaWtlID0gc2VsZi5sZW5ndGggIT09IHVuZGVmaW5lZDtcbiAgICAgICAgdmFyIGFsbCA9IHNlbGZJc0FycmF5TGlrZSA/IHNlbGYgOiBbc2VsZl07IC8vIHB1dCBpbiBhcnJheSBpZiBub3QgYXJyYXktbGlrZVxuXG4gICAgICAgIHZhciBjeSA9IHRoaXMuX3ByaXZhdGUuY3kgfHwgdGhpcztcbiAgICAgICAgdmFyIGlzQ29yZSA9ICFzZWxmSXNBcnJheUxpa2U7XG4gICAgICAgIHZhciBpc0VsZXMgPSAhaXNDb3JlO1xuXG4gICAgICAgIGlmICghY3kuc3R5bGVFbmFibGVkKCkpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBzdHlsZSA9IGN5LnN0eWxlKCk7XG4gICAgICAgIHByb3BlcnRpZXMgPSBleHRlbmQoe30sIHByb3BlcnRpZXMsIHBhcmFtcyk7XG4gICAgICAgIHZhciBwcm9wZXJ0aWVzRW1wdHkgPSBPYmplY3Qua2V5cyhwcm9wZXJ0aWVzKS5sZW5ndGggPT09IDA7XG5cbiAgICAgICAgaWYgKHByb3BlcnRpZXNFbXB0eSkge1xuICAgICAgICAgIHJldHVybiBuZXcgQW5pbWF0aW9uKGFsbFswXSwgcHJvcGVydGllcyk7IC8vIG5vdGhpbmcgdG8gYW5pbWF0ZVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHByb3BlcnRpZXMuZHVyYXRpb24gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHByb3BlcnRpZXMuZHVyYXRpb24gPSA0MDA7XG4gICAgICAgIH1cblxuICAgICAgICBzd2l0Y2ggKHByb3BlcnRpZXMuZHVyYXRpb24pIHtcbiAgICAgICAgICBjYXNlICdzbG93JzpcbiAgICAgICAgICAgIHByb3BlcnRpZXMuZHVyYXRpb24gPSA2MDA7XG4gICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgIGNhc2UgJ2Zhc3QnOlxuICAgICAgICAgICAgcHJvcGVydGllcy5kdXJhdGlvbiA9IDIwMDtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzRWxlcykge1xuICAgICAgICAgIHByb3BlcnRpZXMuc3R5bGUgPSBzdHlsZS5nZXRQcm9wc0xpc3QocHJvcGVydGllcy5zdHlsZSB8fCBwcm9wZXJ0aWVzLmNzcyk7XG4gICAgICAgICAgcHJvcGVydGllcy5jc3MgPSB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNFbGVzICYmIHByb3BlcnRpZXMucmVuZGVyZWRQb3NpdGlvbiAhPSBudWxsKSB7XG4gICAgICAgICAgdmFyIHJwb3MgPSBwcm9wZXJ0aWVzLnJlbmRlcmVkUG9zaXRpb247XG4gICAgICAgICAgdmFyIHBhbiA9IGN5LnBhbigpO1xuICAgICAgICAgIHZhciB6b29tID0gY3kuem9vbSgpO1xuICAgICAgICAgIHByb3BlcnRpZXMucG9zaXRpb24gPSByZW5kZXJlZFRvTW9kZWxQb3NpdGlvbihycG9zLCB6b29tLCBwYW4pO1xuICAgICAgICB9IC8vIG92ZXJyaWRlIHBhbiB3LyBwYW5CeSBpZiBzZXRcblxuXG4gICAgICAgIGlmIChpc0NvcmUgJiYgcHJvcGVydGllcy5wYW5CeSAhPSBudWxsKSB7XG4gICAgICAgICAgdmFyIHBhbkJ5ID0gcHJvcGVydGllcy5wYW5CeTtcbiAgICAgICAgICB2YXIgY3lQYW4gPSBjeS5wYW4oKTtcbiAgICAgICAgICBwcm9wZXJ0aWVzLnBhbiA9IHtcbiAgICAgICAgICAgIHg6IGN5UGFuLnggKyBwYW5CeS54LFxuICAgICAgICAgICAgeTogY3lQYW4ueSArIHBhbkJ5LnlcbiAgICAgICAgICB9O1xuICAgICAgICB9IC8vIG92ZXJyaWRlIHBhbiB3LyBjZW50ZXIgaWYgc2V0XG5cblxuICAgICAgICB2YXIgY2VudGVyID0gcHJvcGVydGllcy5jZW50ZXIgfHwgcHJvcGVydGllcy5jZW50cmU7XG5cbiAgICAgICAgaWYgKGlzQ29yZSAmJiBjZW50ZXIgIT0gbnVsbCkge1xuICAgICAgICAgIHZhciBjZW50ZXJQYW4gPSBjeS5nZXRDZW50ZXJQYW4oY2VudGVyLmVsZXMsIHByb3BlcnRpZXMuem9vbSk7XG5cbiAgICAgICAgICBpZiAoY2VudGVyUGFuICE9IG51bGwpIHtcbiAgICAgICAgICAgIHByb3BlcnRpZXMucGFuID0gY2VudGVyUGFuO1xuICAgICAgICAgIH1cbiAgICAgICAgfSAvLyBvdmVycmlkZSBwYW4gJiB6b29tIHcvIGZpdCBpZiBzZXRcblxuXG4gICAgICAgIGlmIChpc0NvcmUgJiYgcHJvcGVydGllcy5maXQgIT0gbnVsbCkge1xuICAgICAgICAgIHZhciBmaXQgPSBwcm9wZXJ0aWVzLmZpdDtcbiAgICAgICAgICB2YXIgZml0VnAgPSBjeS5nZXRGaXRWaWV3cG9ydChmaXQuZWxlcyB8fCBmaXQuYm91bmRpbmdCb3gsIGZpdC5wYWRkaW5nKTtcblxuICAgICAgICAgIGlmIChmaXRWcCAhPSBudWxsKSB7XG4gICAgICAgICAgICBwcm9wZXJ0aWVzLnBhbiA9IGZpdFZwLnBhbjtcbiAgICAgICAgICAgIHByb3BlcnRpZXMuem9vbSA9IGZpdFZwLnpvb207XG4gICAgICAgICAgfVxuICAgICAgICB9IC8vIG92ZXJyaWRlIHpvb20gKCYgcG90ZW50aWFsbHkgcGFuKSB3LyB6b29tIG9iaiBpZiBzZXRcblxuXG4gICAgICAgIGlmIChpc0NvcmUgJiYgcGxhaW5PYmplY3QocHJvcGVydGllcy56b29tKSkge1xuICAgICAgICAgIHZhciB2cCA9IGN5LmdldFpvb21lZFZpZXdwb3J0KHByb3BlcnRpZXMuem9vbSk7XG5cbiAgICAgICAgICBpZiAodnAgIT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKHZwLnpvb21lZCkge1xuICAgICAgICAgICAgICBwcm9wZXJ0aWVzLnpvb20gPSB2cC56b29tO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodnAucGFubmVkKSB7XG4gICAgICAgICAgICAgIHByb3BlcnRpZXMucGFuID0gdnAucGFuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwcm9wZXJ0aWVzLnpvb20gPSBudWxsOyAvLyBhbiBpbmF2YWxpZCB6b29tIChlLmcuIG5vIGRlbHRhKSBnZXRzIGF1dG9tYXRpY2FsbHkgZGVzdHJveWVkXG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyBBbmltYXRpb24oYWxsWzBdLCBwcm9wZXJ0aWVzKTtcbiAgICAgIH07XG4gICAgfSxcbiAgICAvLyBhbmltYXRlXG4gICAgYW5pbWF0ZTogZnVuY3Rpb24gYW5pbWF0ZSgpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiBhbmltYXRlSW1wbChwcm9wZXJ0aWVzLCBwYXJhbXMpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB2YXIgc2VsZklzQXJyYXlMaWtlID0gc2VsZi5sZW5ndGggIT09IHVuZGVmaW5lZDtcbiAgICAgICAgdmFyIGFsbCA9IHNlbGZJc0FycmF5TGlrZSA/IHNlbGYgOiBbc2VsZl07IC8vIHB1dCBpbiBhcnJheSBpZiBub3QgYXJyYXktbGlrZVxuXG4gICAgICAgIHZhciBjeSA9IHRoaXMuX3ByaXZhdGUuY3kgfHwgdGhpcztcblxuICAgICAgICBpZiAoIWN5LnN0eWxlRW5hYmxlZCgpKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocGFyYW1zKSB7XG4gICAgICAgICAgcHJvcGVydGllcyA9IGV4dGVuZCh7fSwgcHJvcGVydGllcywgcGFyYW1zKTtcbiAgICAgICAgfSAvLyBtYW51YWxseSBob29rIGFuZCBydW4gdGhlIGFuaW1hdGlvblxuXG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhbGwubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWxlID0gYWxsW2ldO1xuICAgICAgICAgIHZhciBxdWV1ZSA9IGVsZS5hbmltYXRlZCgpICYmIChwcm9wZXJ0aWVzLnF1ZXVlID09PSB1bmRlZmluZWQgfHwgcHJvcGVydGllcy5xdWV1ZSk7XG4gICAgICAgICAgdmFyIGFuaSA9IGVsZS5hbmltYXRpb24ocHJvcGVydGllcywgcXVldWUgPyB7XG4gICAgICAgICAgICBxdWV1ZTogdHJ1ZVxuICAgICAgICAgIH0gOiB1bmRlZmluZWQpO1xuICAgICAgICAgIGFuaS5wbGF5KCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgICAgIH07XG4gICAgfSxcbiAgICAvLyBhbmltYXRlXG4gICAgc3RvcDogZnVuY3Rpb24gc3RvcCgpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiBzdG9wSW1wbChjbGVhclF1ZXVlLCBqdW1wVG9FbmQpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB2YXIgc2VsZklzQXJyYXlMaWtlID0gc2VsZi5sZW5ndGggIT09IHVuZGVmaW5lZDtcbiAgICAgICAgdmFyIGFsbCA9IHNlbGZJc0FycmF5TGlrZSA/IHNlbGYgOiBbc2VsZl07IC8vIHB1dCBpbiBhcnJheSBpZiBub3QgYXJyYXktbGlrZVxuXG4gICAgICAgIHZhciBjeSA9IHRoaXMuX3ByaXZhdGUuY3kgfHwgdGhpcztcblxuICAgICAgICBpZiAoIWN5LnN0eWxlRW5hYmxlZCgpKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFsbC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBlbGUgPSBhbGxbaV07XG4gICAgICAgICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgICAgICAgIHZhciBhbmlzID0gX3AuYW5pbWF0aW9uLmN1cnJlbnQ7XG5cbiAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGFuaXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIHZhciBhbmkgPSBhbmlzW2pdO1xuICAgICAgICAgICAgdmFyIGFuaV9wID0gYW5pLl9wcml2YXRlO1xuXG4gICAgICAgICAgICBpZiAoanVtcFRvRW5kKSB7XG4gICAgICAgICAgICAgIC8vIG5leHQgaXRlcmF0aW9uIG9mIHRoZSBhbmltYXRpb24gbG9vcCwgdGhlIGFuaW1hdGlvblxuICAgICAgICAgICAgICAvLyB3aWxsIGdvIHN0cmFpZ2h0IHRvIHRoZSBlbmQgYW5kIGJlIHJlbW92ZWRcbiAgICAgICAgICAgICAgYW5pX3AuZHVyYXRpb24gPSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gY2xlYXIgdGhlIHF1ZXVlIG9mIGZ1dHVyZSBhbmltYXRpb25zXG5cblxuICAgICAgICAgIGlmIChjbGVhclF1ZXVlKSB7XG4gICAgICAgICAgICBfcC5hbmltYXRpb24ucXVldWUgPSBbXTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIWp1bXBUb0VuZCkge1xuICAgICAgICAgICAgX3AuYW5pbWF0aW9uLmN1cnJlbnQgPSBbXTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gLy8gd2UgaGF2ZSB0byBub3RpZnkgKHRoZSBhbmltYXRpb24gbG9vcCBkb2Vzbid0IGRvIGl0IGZvciB1cyBvbiBgc3RvcGApXG5cblxuICAgICAgICBjeS5ub3RpZnkoJ2RyYXcnKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9O1xuICAgIH0gLy8gc3RvcFxuXG4gIH07IC8vIGRlZmluZVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBjbGFzc2lmaWVkIGFzIGFuIGBBcnJheWAgb2JqZWN0LlxuICAgKlxuICAgKiBAc3RhdGljXG4gICAqIEBtZW1iZXJPZiBfXG4gICAqIEBzaW5jZSAwLjEuMFxuICAgKiBAY2F0ZWdvcnkgTGFuZ1xuICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYW4gYXJyYXksIGVsc2UgYGZhbHNlYC5cbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogXy5pc0FycmF5KFsxLCAyLCAzXSk7XG4gICAqIC8vID0+IHRydWVcbiAgICpcbiAgICogXy5pc0FycmF5KGRvY3VtZW50LmJvZHkuY2hpbGRyZW4pO1xuICAgKiAvLyA9PiBmYWxzZVxuICAgKlxuICAgKiBfLmlzQXJyYXkoJ2FiYycpO1xuICAgKiAvLyA9PiBmYWxzZVxuICAgKlxuICAgKiBfLmlzQXJyYXkoXy5ub29wKTtcbiAgICogLy8gPT4gZmFsc2VcbiAgICovXG4gIHZhciBpc0FycmF5ID0gQXJyYXkuaXNBcnJheTtcblxuICB2YXIgaXNBcnJheV8xID0gaXNBcnJheTtcblxuICAvKiogVXNlZCB0byBtYXRjaCBwcm9wZXJ0eSBuYW1lcyB3aXRoaW4gcHJvcGVydHkgcGF0aHMuICovXG4gIHZhciByZUlzRGVlcFByb3AgPSAvXFwufFxcWyg/OlteW1xcXV0qfChbXCInXSkoPzooPyFcXDEpW15cXFxcXXxcXFxcLikqP1xcMSlcXF0vLFxuICAgICAgcmVJc1BsYWluUHJvcCA9IC9eXFx3KiQvO1xuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhIHByb3BlcnR5IG5hbWUgYW5kIG5vdCBhIHByb3BlcnR5IHBhdGguXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgKiBAcGFyYW0ge09iamVjdH0gW29iamVjdF0gVGhlIG9iamVjdCB0byBxdWVyeSBrZXlzIG9uLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBhIHByb3BlcnR5IG5hbWUsIGVsc2UgYGZhbHNlYC5cbiAgICovXG4gIGZ1bmN0aW9uIGlzS2V5KHZhbHVlLCBvYmplY3QpIHtcbiAgICBpZiAoaXNBcnJheV8xKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICB2YXIgdHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgICBpZiAodHlwZSA9PSAnbnVtYmVyJyB8fCB0eXBlID09ICdzeW1ib2wnIHx8IHR5cGUgPT0gJ2Jvb2xlYW4nIHx8XG4gICAgICAgIHZhbHVlID09IG51bGwgfHwgaXNTeW1ib2xfMSh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gcmVJc1BsYWluUHJvcC50ZXN0KHZhbHVlKSB8fCAhcmVJc0RlZXBQcm9wLnRlc3QodmFsdWUpIHx8XG4gICAgICAob2JqZWN0ICE9IG51bGwgJiYgdmFsdWUgaW4gT2JqZWN0KG9iamVjdCkpO1xuICB9XG5cbiAgdmFyIF9pc0tleSA9IGlzS2V5O1xuXG4gIC8qKiBgT2JqZWN0I3RvU3RyaW5nYCByZXN1bHQgcmVmZXJlbmNlcy4gKi9cbiAgdmFyIGFzeW5jVGFnID0gJ1tvYmplY3QgQXN5bmNGdW5jdGlvbl0nLFxuICAgICAgZnVuY1RhZyA9ICdbb2JqZWN0IEZ1bmN0aW9uXScsXG4gICAgICBnZW5UYWcgPSAnW29iamVjdCBHZW5lcmF0b3JGdW5jdGlvbl0nLFxuICAgICAgcHJveHlUYWcgPSAnW29iamVjdCBQcm94eV0nO1xuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBjbGFzc2lmaWVkIGFzIGEgYEZ1bmN0aW9uYCBvYmplY3QuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQG1lbWJlck9mIF9cbiAgICogQHNpbmNlIDAuMS4wXG4gICAqIEBjYXRlZ29yeSBMYW5nXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBhIGZ1bmN0aW9uLCBlbHNlIGBmYWxzZWAuXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIF8uaXNGdW5jdGlvbihfKTtcbiAgICogLy8gPT4gdHJ1ZVxuICAgKlxuICAgKiBfLmlzRnVuY3Rpb24oL2FiYy8pO1xuICAgKiAvLyA9PiBmYWxzZVxuICAgKi9cbiAgZnVuY3Rpb24gaXNGdW5jdGlvbih2YWx1ZSkge1xuICAgIGlmICghaXNPYmplY3RfMSh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gVGhlIHVzZSBvZiBgT2JqZWN0I3RvU3RyaW5nYCBhdm9pZHMgaXNzdWVzIHdpdGggdGhlIGB0eXBlb2ZgIG9wZXJhdG9yXG4gICAgLy8gaW4gU2FmYXJpIDkgd2hpY2ggcmV0dXJucyAnb2JqZWN0JyBmb3IgdHlwZWQgYXJyYXlzIGFuZCBvdGhlciBjb25zdHJ1Y3RvcnMuXG4gICAgdmFyIHRhZyA9IF9iYXNlR2V0VGFnKHZhbHVlKTtcbiAgICByZXR1cm4gdGFnID09IGZ1bmNUYWcgfHwgdGFnID09IGdlblRhZyB8fCB0YWcgPT0gYXN5bmNUYWcgfHwgdGFnID09IHByb3h5VGFnO1xuICB9XG5cbiAgdmFyIGlzRnVuY3Rpb25fMSA9IGlzRnVuY3Rpb247XG5cbiAgLyoqIFVzZWQgdG8gZGV0ZWN0IG92ZXJyZWFjaGluZyBjb3JlLWpzIHNoaW1zLiAqL1xuICB2YXIgY29yZUpzRGF0YSA9IF9yb290WydfX2NvcmUtanNfc2hhcmVkX18nXTtcblxuICB2YXIgX2NvcmVKc0RhdGEgPSBjb3JlSnNEYXRhO1xuXG4gIC8qKiBVc2VkIHRvIGRldGVjdCBtZXRob2RzIG1hc3F1ZXJhZGluZyBhcyBuYXRpdmUuICovXG4gIHZhciBtYXNrU3JjS2V5ID0gKGZ1bmN0aW9uKCkge1xuICAgIHZhciB1aWQgPSAvW14uXSskLy5leGVjKF9jb3JlSnNEYXRhICYmIF9jb3JlSnNEYXRhLmtleXMgJiYgX2NvcmVKc0RhdGEua2V5cy5JRV9QUk9UTyB8fCAnJyk7XG4gICAgcmV0dXJuIHVpZCA/ICgnU3ltYm9sKHNyYylfMS4nICsgdWlkKSA6ICcnO1xuICB9KCkpO1xuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYGZ1bmNgIGhhcyBpdHMgc291cmNlIG1hc2tlZC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gY2hlY2suXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgZnVuY2AgaXMgbWFza2VkLCBlbHNlIGBmYWxzZWAuXG4gICAqL1xuICBmdW5jdGlvbiBpc01hc2tlZChmdW5jKSB7XG4gICAgcmV0dXJuICEhbWFza1NyY0tleSAmJiAobWFza1NyY0tleSBpbiBmdW5jKTtcbiAgfVxuXG4gIHZhciBfaXNNYXNrZWQgPSBpc01hc2tlZDtcblxuICAvKiogVXNlZCBmb3IgYnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMuICovXG4gIHZhciBmdW5jUHJvdG8kMSA9IEZ1bmN0aW9uLnByb3RvdHlwZTtcblxuICAvKiogVXNlZCB0byByZXNvbHZlIHRoZSBkZWNvbXBpbGVkIHNvdXJjZSBvZiBmdW5jdGlvbnMuICovXG4gIHZhciBmdW5jVG9TdHJpbmckMSA9IGZ1bmNQcm90byQxLnRvU3RyaW5nO1xuXG4gIC8qKlxuICAgKiBDb252ZXJ0cyBgZnVuY2AgdG8gaXRzIHNvdXJjZSBjb2RlLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byBjb252ZXJ0LlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBSZXR1cm5zIHRoZSBzb3VyY2UgY29kZS5cbiAgICovXG4gIGZ1bmN0aW9uIHRvU291cmNlKGZ1bmMpIHtcbiAgICBpZiAoZnVuYyAhPSBudWxsKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gZnVuY1RvU3RyaW5nJDEuY2FsbChmdW5jKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHt9XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gKGZ1bmMgKyAnJyk7XG4gICAgICB9IGNhdGNoIChlKSB7fVxuICAgIH1cbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICB2YXIgX3RvU291cmNlID0gdG9Tb3VyY2U7XG5cbiAgLyoqXG4gICAqIFVzZWQgdG8gbWF0Y2ggYFJlZ0V4cGBcbiAgICogW3N5bnRheCBjaGFyYWN0ZXJzXShodHRwOi8vZWNtYS1pbnRlcm5hdGlvbmFsLm9yZy9lY21hLTI2Mi83LjAvI3NlYy1wYXR0ZXJucykuXG4gICAqL1xuICB2YXIgcmVSZWdFeHBDaGFyID0gL1tcXFxcXiQuKis/KClbXFxde318XS9nO1xuXG4gIC8qKiBVc2VkIHRvIGRldGVjdCBob3N0IGNvbnN0cnVjdG9ycyAoU2FmYXJpKS4gKi9cbiAgdmFyIHJlSXNIb3N0Q3RvciA9IC9eXFxbb2JqZWN0IC4rP0NvbnN0cnVjdG9yXFxdJC87XG5cbiAgLyoqIFVzZWQgZm9yIGJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzLiAqL1xuICB2YXIgZnVuY1Byb3RvID0gRnVuY3Rpb24ucHJvdG90eXBlLFxuICAgICAgb2JqZWN0UHJvdG8kMyA9IE9iamVjdC5wcm90b3R5cGU7XG5cbiAgLyoqIFVzZWQgdG8gcmVzb2x2ZSB0aGUgZGVjb21waWxlZCBzb3VyY2Ugb2YgZnVuY3Rpb25zLiAqL1xuICB2YXIgZnVuY1RvU3RyaW5nID0gZnVuY1Byb3RvLnRvU3RyaW5nO1xuXG4gIC8qKiBVc2VkIHRvIGNoZWNrIG9iamVjdHMgZm9yIG93biBwcm9wZXJ0aWVzLiAqL1xuICB2YXIgaGFzT3duUHJvcGVydHkkMyA9IG9iamVjdFByb3RvJDMuaGFzT3duUHJvcGVydHk7XG5cbiAgLyoqIFVzZWQgdG8gZGV0ZWN0IGlmIGEgbWV0aG9kIGlzIG5hdGl2ZS4gKi9cbiAgdmFyIHJlSXNOYXRpdmUgPSBSZWdFeHAoJ14nICtcbiAgICBmdW5jVG9TdHJpbmcuY2FsbChoYXNPd25Qcm9wZXJ0eSQzKS5yZXBsYWNlKHJlUmVnRXhwQ2hhciwgJ1xcXFwkJicpXG4gICAgLnJlcGxhY2UoL2hhc093blByb3BlcnR5fChmdW5jdGlvbikuKj8oPz1cXFxcXFwoKXwgZm9yIC4rPyg/PVxcXFxcXF0pL2csICckMS4qPycpICsgJyQnXG4gICk7XG5cbiAgLyoqXG4gICAqIFRoZSBiYXNlIGltcGxlbWVudGF0aW9uIG9mIGBfLmlzTmF0aXZlYCB3aXRob3V0IGJhZCBzaGltIGNoZWNrcy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIGEgbmF0aXZlIGZ1bmN0aW9uLFxuICAgKiAgZWxzZSBgZmFsc2VgLlxuICAgKi9cbiAgZnVuY3Rpb24gYmFzZUlzTmF0aXZlKHZhbHVlKSB7XG4gICAgaWYgKCFpc09iamVjdF8xKHZhbHVlKSB8fCBfaXNNYXNrZWQodmFsdWUpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHZhciBwYXR0ZXJuID0gaXNGdW5jdGlvbl8xKHZhbHVlKSA/IHJlSXNOYXRpdmUgOiByZUlzSG9zdEN0b3I7XG4gICAgcmV0dXJuIHBhdHRlcm4udGVzdChfdG9Tb3VyY2UodmFsdWUpKTtcbiAgfVxuXG4gIHZhciBfYmFzZUlzTmF0aXZlID0gYmFzZUlzTmF0aXZlO1xuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSB2YWx1ZSBhdCBga2V5YCBvZiBgb2JqZWN0YC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtPYmplY3R9IFtvYmplY3RdIFRoZSBvYmplY3QgdG8gcXVlcnkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVGhlIGtleSBvZiB0aGUgcHJvcGVydHkgdG8gZ2V0LlxuICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgcHJvcGVydHkgdmFsdWUuXG4gICAqL1xuICBmdW5jdGlvbiBnZXRWYWx1ZSQxKG9iamVjdCwga2V5KSB7XG4gICAgcmV0dXJuIG9iamVjdCA9PSBudWxsID8gdW5kZWZpbmVkIDogb2JqZWN0W2tleV07XG4gIH1cblxuICB2YXIgX2dldFZhbHVlID0gZ2V0VmFsdWUkMTtcblxuICAvKipcbiAgICogR2V0cyB0aGUgbmF0aXZlIGZ1bmN0aW9uIGF0IGBrZXlgIG9mIGBvYmplY3RgLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gcXVlcnkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVGhlIGtleSBvZiB0aGUgbWV0aG9kIHRvIGdldC5cbiAgICogQHJldHVybnMgeyp9IFJldHVybnMgdGhlIGZ1bmN0aW9uIGlmIGl0J3MgbmF0aXZlLCBlbHNlIGB1bmRlZmluZWRgLlxuICAgKi9cbiAgZnVuY3Rpb24gZ2V0TmF0aXZlKG9iamVjdCwga2V5KSB7XG4gICAgdmFyIHZhbHVlID0gX2dldFZhbHVlKG9iamVjdCwga2V5KTtcbiAgICByZXR1cm4gX2Jhc2VJc05hdGl2ZSh2YWx1ZSkgPyB2YWx1ZSA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHZhciBfZ2V0TmF0aXZlID0gZ2V0TmF0aXZlO1xuXG4gIC8qIEJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzIHRoYXQgYXJlIHZlcmlmaWVkIHRvIGJlIG5hdGl2ZS4gKi9cbiAgdmFyIG5hdGl2ZUNyZWF0ZSA9IF9nZXROYXRpdmUoT2JqZWN0LCAnY3JlYXRlJyk7XG5cbiAgdmFyIF9uYXRpdmVDcmVhdGUgPSBuYXRpdmVDcmVhdGU7XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYWxsIGtleS12YWx1ZSBlbnRyaWVzIGZyb20gdGhlIGhhc2guXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBuYW1lIGNsZWFyXG4gICAqIEBtZW1iZXJPZiBIYXNoXG4gICAqL1xuICBmdW5jdGlvbiBoYXNoQ2xlYXIoKSB7XG4gICAgdGhpcy5fX2RhdGFfXyA9IF9uYXRpdmVDcmVhdGUgPyBfbmF0aXZlQ3JlYXRlKG51bGwpIDoge307XG4gICAgdGhpcy5zaXplID0gMDtcbiAgfVxuXG4gIHZhciBfaGFzaENsZWFyID0gaGFzaENsZWFyO1xuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGBrZXlgIGFuZCBpdHMgdmFsdWUgZnJvbSB0aGUgaGFzaC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQG5hbWUgZGVsZXRlXG4gICAqIEBtZW1iZXJPZiBIYXNoXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBoYXNoIFRoZSBoYXNoIHRvIG1vZGlmeS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBUaGUga2V5IG9mIHRoZSB2YWx1ZSB0byByZW1vdmUuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgZW50cnkgd2FzIHJlbW92ZWQsIGVsc2UgYGZhbHNlYC5cbiAgICovXG4gIGZ1bmN0aW9uIGhhc2hEZWxldGUoa2V5KSB7XG4gICAgdmFyIHJlc3VsdCA9IHRoaXMuaGFzKGtleSkgJiYgZGVsZXRlIHRoaXMuX19kYXRhX19ba2V5XTtcbiAgICB0aGlzLnNpemUgLT0gcmVzdWx0ID8gMSA6IDA7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHZhciBfaGFzaERlbGV0ZSA9IGhhc2hEZWxldGU7XG5cbiAgLyoqIFVzZWQgdG8gc3RhbmQtaW4gZm9yIGB1bmRlZmluZWRgIGhhc2ggdmFsdWVzLiAqL1xuICB2YXIgSEFTSF9VTkRFRklORUQkMSA9ICdfX2xvZGFzaF9oYXNoX3VuZGVmaW5lZF9fJztcblxuICAvKiogVXNlZCBmb3IgYnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMuICovXG4gIHZhciBvYmplY3RQcm90byQyID0gT2JqZWN0LnByb3RvdHlwZTtcblxuICAvKiogVXNlZCB0byBjaGVjayBvYmplY3RzIGZvciBvd24gcHJvcGVydGllcy4gKi9cbiAgdmFyIGhhc093blByb3BlcnR5JDIgPSBvYmplY3RQcm90byQyLmhhc093blByb3BlcnR5O1xuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBoYXNoIHZhbHVlIGZvciBga2V5YC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQG5hbWUgZ2V0XG4gICAqIEBtZW1iZXJPZiBIYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVGhlIGtleSBvZiB0aGUgdmFsdWUgdG8gZ2V0LlxuICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgZW50cnkgdmFsdWUuXG4gICAqL1xuICBmdW5jdGlvbiBoYXNoR2V0KGtleSkge1xuICAgIHZhciBkYXRhID0gdGhpcy5fX2RhdGFfXztcbiAgICBpZiAoX25hdGl2ZUNyZWF0ZSkge1xuICAgICAgdmFyIHJlc3VsdCA9IGRhdGFba2V5XTtcbiAgICAgIHJldHVybiByZXN1bHQgPT09IEhBU0hfVU5ERUZJTkVEJDEgPyB1bmRlZmluZWQgOiByZXN1bHQ7XG4gICAgfVxuICAgIHJldHVybiBoYXNPd25Qcm9wZXJ0eSQyLmNhbGwoZGF0YSwga2V5KSA/IGRhdGFba2V5XSA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHZhciBfaGFzaEdldCA9IGhhc2hHZXQ7XG5cbiAgLyoqIFVzZWQgZm9yIGJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzLiAqL1xuICB2YXIgb2JqZWN0UHJvdG8kMSA9IE9iamVjdC5wcm90b3R5cGU7XG5cbiAgLyoqIFVzZWQgdG8gY2hlY2sgb2JqZWN0cyBmb3Igb3duIHByb3BlcnRpZXMuICovXG4gIHZhciBoYXNPd25Qcm9wZXJ0eSQxID0gb2JqZWN0UHJvdG8kMS5oYXNPd25Qcm9wZXJ0eTtcblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGEgaGFzaCB2YWx1ZSBmb3IgYGtleWAgZXhpc3RzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAbmFtZSBoYXNcbiAgICogQG1lbWJlck9mIEhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBUaGUga2V5IG9mIHRoZSBlbnRyeSB0byBjaGVjay5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGFuIGVudHJ5IGZvciBga2V5YCBleGlzdHMsIGVsc2UgYGZhbHNlYC5cbiAgICovXG4gIGZ1bmN0aW9uIGhhc2hIYXMoa2V5KSB7XG4gICAgdmFyIGRhdGEgPSB0aGlzLl9fZGF0YV9fO1xuICAgIHJldHVybiBfbmF0aXZlQ3JlYXRlID8gKGRhdGFba2V5XSAhPT0gdW5kZWZpbmVkKSA6IGhhc093blByb3BlcnR5JDEuY2FsbChkYXRhLCBrZXkpO1xuICB9XG5cbiAgdmFyIF9oYXNoSGFzID0gaGFzaEhhcztcblxuICAvKiogVXNlZCB0byBzdGFuZC1pbiBmb3IgYHVuZGVmaW5lZGAgaGFzaCB2YWx1ZXMuICovXG4gIHZhciBIQVNIX1VOREVGSU5FRCA9ICdfX2xvZGFzaF9oYXNoX3VuZGVmaW5lZF9fJztcblxuICAvKipcbiAgICogU2V0cyB0aGUgaGFzaCBga2V5YCB0byBgdmFsdWVgLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAbmFtZSBzZXRcbiAgICogQG1lbWJlck9mIEhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBUaGUga2V5IG9mIHRoZSB2YWx1ZSB0byBzZXQuXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIHNldC5cbiAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgaGFzaCBpbnN0YW5jZS5cbiAgICovXG4gIGZ1bmN0aW9uIGhhc2hTZXQoa2V5LCB2YWx1ZSkge1xuICAgIHZhciBkYXRhID0gdGhpcy5fX2RhdGFfXztcbiAgICB0aGlzLnNpemUgKz0gdGhpcy5oYXMoa2V5KSA/IDAgOiAxO1xuICAgIGRhdGFba2V5XSA9IChfbmF0aXZlQ3JlYXRlICYmIHZhbHVlID09PSB1bmRlZmluZWQpID8gSEFTSF9VTkRFRklORUQgOiB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHZhciBfaGFzaFNldCA9IGhhc2hTZXQ7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBoYXNoIG9iamVjdC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQGNvbnN0cnVjdG9yXG4gICAqIEBwYXJhbSB7QXJyYXl9IFtlbnRyaWVzXSBUaGUga2V5LXZhbHVlIHBhaXJzIHRvIGNhY2hlLlxuICAgKi9cbiAgZnVuY3Rpb24gSGFzaChlbnRyaWVzKSB7XG4gICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgIGxlbmd0aCA9IGVudHJpZXMgPT0gbnVsbCA/IDAgOiBlbnRyaWVzLmxlbmd0aDtcblxuICAgIHRoaXMuY2xlYXIoKTtcbiAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgdmFyIGVudHJ5ID0gZW50cmllc1tpbmRleF07XG4gICAgICB0aGlzLnNldChlbnRyeVswXSwgZW50cnlbMV0pO1xuICAgIH1cbiAgfVxuXG4gIC8vIEFkZCBtZXRob2RzIHRvIGBIYXNoYC5cbiAgSGFzaC5wcm90b3R5cGUuY2xlYXIgPSBfaGFzaENsZWFyO1xuICBIYXNoLnByb3RvdHlwZVsnZGVsZXRlJ10gPSBfaGFzaERlbGV0ZTtcbiAgSGFzaC5wcm90b3R5cGUuZ2V0ID0gX2hhc2hHZXQ7XG4gIEhhc2gucHJvdG90eXBlLmhhcyA9IF9oYXNoSGFzO1xuICBIYXNoLnByb3RvdHlwZS5zZXQgPSBfaGFzaFNldDtcblxuICB2YXIgX0hhc2ggPSBIYXNoO1xuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGFsbCBrZXktdmFsdWUgZW50cmllcyBmcm9tIHRoZSBsaXN0IGNhY2hlLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAbmFtZSBjbGVhclxuICAgKiBAbWVtYmVyT2YgTGlzdENhY2hlXG4gICAqL1xuICBmdW5jdGlvbiBsaXN0Q2FjaGVDbGVhcigpIHtcbiAgICB0aGlzLl9fZGF0YV9fID0gW107XG4gICAgdGhpcy5zaXplID0gMDtcbiAgfVxuXG4gIHZhciBfbGlzdENhY2hlQ2xlYXIgPSBsaXN0Q2FjaGVDbGVhcjtcblxuICAvKipcbiAgICogUGVyZm9ybXMgYVxuICAgKiBbYFNhbWVWYWx1ZVplcm9gXShodHRwOi8vZWNtYS1pbnRlcm5hdGlvbmFsLm9yZy9lY21hLTI2Mi83LjAvI3NlYy1zYW1ldmFsdWV6ZXJvKVxuICAgKiBjb21wYXJpc29uIGJldHdlZW4gdHdvIHZhbHVlcyB0byBkZXRlcm1pbmUgaWYgdGhleSBhcmUgZXF1aXZhbGVudC5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKiBAbWVtYmVyT2YgX1xuICAgKiBAc2luY2UgNC4wLjBcbiAgICogQGNhdGVnb3J5IExhbmdcbiAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY29tcGFyZS5cbiAgICogQHBhcmFtIHsqfSBvdGhlciBUaGUgb3RoZXIgdmFsdWUgdG8gY29tcGFyZS5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHRoZSB2YWx1ZXMgYXJlIGVxdWl2YWxlbnQsIGVsc2UgYGZhbHNlYC5cbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogdmFyIG9iamVjdCA9IHsgJ2EnOiAxIH07XG4gICAqIHZhciBvdGhlciA9IHsgJ2EnOiAxIH07XG4gICAqXG4gICAqIF8uZXEob2JqZWN0LCBvYmplY3QpO1xuICAgKiAvLyA9PiB0cnVlXG4gICAqXG4gICAqIF8uZXEob2JqZWN0LCBvdGhlcik7XG4gICAqIC8vID0+IGZhbHNlXG4gICAqXG4gICAqIF8uZXEoJ2EnLCAnYScpO1xuICAgKiAvLyA9PiB0cnVlXG4gICAqXG4gICAqIF8uZXEoJ2EnLCBPYmplY3QoJ2EnKSk7XG4gICAqIC8vID0+IGZhbHNlXG4gICAqXG4gICAqIF8uZXEoTmFOLCBOYU4pO1xuICAgKiAvLyA9PiB0cnVlXG4gICAqL1xuICBmdW5jdGlvbiBlcSh2YWx1ZSwgb3RoZXIpIHtcbiAgICByZXR1cm4gdmFsdWUgPT09IG90aGVyIHx8ICh2YWx1ZSAhPT0gdmFsdWUgJiYgb3RoZXIgIT09IG90aGVyKTtcbiAgfVxuXG4gIHZhciBlcV8xID0gZXE7XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGluZGV4IGF0IHdoaWNoIHRoZSBga2V5YCBpcyBmb3VuZCBpbiBgYXJyYXlgIG9mIGtleS12YWx1ZSBwYWlycy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIGluc3BlY3QuXG4gICAqIEBwYXJhbSB7Kn0ga2V5IFRoZSBrZXkgdG8gc2VhcmNoIGZvci5cbiAgICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgaW5kZXggb2YgdGhlIG1hdGNoZWQgdmFsdWUsIGVsc2UgYC0xYC5cbiAgICovXG4gIGZ1bmN0aW9uIGFzc29jSW5kZXhPZihhcnJheSwga2V5KSB7XG4gICAgdmFyIGxlbmd0aCA9IGFycmF5Lmxlbmd0aDtcbiAgICB3aGlsZSAobGVuZ3RoLS0pIHtcbiAgICAgIGlmIChlcV8xKGFycmF5W2xlbmd0aF1bMF0sIGtleSkpIHtcbiAgICAgICAgcmV0dXJuIGxlbmd0aDtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIC0xO1xuICB9XG5cbiAgdmFyIF9hc3NvY0luZGV4T2YgPSBhc3NvY0luZGV4T2Y7XG5cbiAgLyoqIFVzZWQgZm9yIGJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzLiAqL1xuICB2YXIgYXJyYXlQcm90byA9IEFycmF5LnByb3RvdHlwZTtcblxuICAvKiogQnVpbHQtaW4gdmFsdWUgcmVmZXJlbmNlcy4gKi9cbiAgdmFyIHNwbGljZSA9IGFycmF5UHJvdG8uc3BsaWNlO1xuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGBrZXlgIGFuZCBpdHMgdmFsdWUgZnJvbSB0aGUgbGlzdCBjYWNoZS5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQG5hbWUgZGVsZXRlXG4gICAqIEBtZW1iZXJPZiBMaXN0Q2FjaGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBUaGUga2V5IG9mIHRoZSB2YWx1ZSB0byByZW1vdmUuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgZW50cnkgd2FzIHJlbW92ZWQsIGVsc2UgYGZhbHNlYC5cbiAgICovXG4gIGZ1bmN0aW9uIGxpc3RDYWNoZURlbGV0ZShrZXkpIHtcbiAgICB2YXIgZGF0YSA9IHRoaXMuX19kYXRhX18sXG4gICAgICAgIGluZGV4ID0gX2Fzc29jSW5kZXhPZihkYXRhLCBrZXkpO1xuXG4gICAgaWYgKGluZGV4IDwgMCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICB2YXIgbGFzdEluZGV4ID0gZGF0YS5sZW5ndGggLSAxO1xuICAgIGlmIChpbmRleCA9PSBsYXN0SW5kZXgpIHtcbiAgICAgIGRhdGEucG9wKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNwbGljZS5jYWxsKGRhdGEsIGluZGV4LCAxKTtcbiAgICB9XG4gICAgLS10aGlzLnNpemU7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICB2YXIgX2xpc3RDYWNoZURlbGV0ZSA9IGxpc3RDYWNoZURlbGV0ZTtcblxuICAvKipcbiAgICogR2V0cyB0aGUgbGlzdCBjYWNoZSB2YWx1ZSBmb3IgYGtleWAuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBuYW1lIGdldFxuICAgKiBAbWVtYmVyT2YgTGlzdENhY2hlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVGhlIGtleSBvZiB0aGUgdmFsdWUgdG8gZ2V0LlxuICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgZW50cnkgdmFsdWUuXG4gICAqL1xuICBmdW5jdGlvbiBsaXN0Q2FjaGVHZXQoa2V5KSB7XG4gICAgdmFyIGRhdGEgPSB0aGlzLl9fZGF0YV9fLFxuICAgICAgICBpbmRleCA9IF9hc3NvY0luZGV4T2YoZGF0YSwga2V5KTtcblxuICAgIHJldHVybiBpbmRleCA8IDAgPyB1bmRlZmluZWQgOiBkYXRhW2luZGV4XVsxXTtcbiAgfVxuXG4gIHZhciBfbGlzdENhY2hlR2V0ID0gbGlzdENhY2hlR2V0O1xuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYSBsaXN0IGNhY2hlIHZhbHVlIGZvciBga2V5YCBleGlzdHMuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBuYW1lIGhhc1xuICAgKiBAbWVtYmVyT2YgTGlzdENhY2hlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVGhlIGtleSBvZiB0aGUgZW50cnkgdG8gY2hlY2suXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBhbiBlbnRyeSBmb3IgYGtleWAgZXhpc3RzLCBlbHNlIGBmYWxzZWAuXG4gICAqL1xuICBmdW5jdGlvbiBsaXN0Q2FjaGVIYXMoa2V5KSB7XG4gICAgcmV0dXJuIF9hc3NvY0luZGV4T2YodGhpcy5fX2RhdGFfXywga2V5KSA+IC0xO1xuICB9XG5cbiAgdmFyIF9saXN0Q2FjaGVIYXMgPSBsaXN0Q2FjaGVIYXM7XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGxpc3QgY2FjaGUgYGtleWAgdG8gYHZhbHVlYC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQG5hbWUgc2V0XG4gICAqIEBtZW1iZXJPZiBMaXN0Q2FjaGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBUaGUga2V5IG9mIHRoZSB2YWx1ZSB0byBzZXQuXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIHNldC5cbiAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgbGlzdCBjYWNoZSBpbnN0YW5jZS5cbiAgICovXG4gIGZ1bmN0aW9uIGxpc3RDYWNoZVNldChrZXksIHZhbHVlKSB7XG4gICAgdmFyIGRhdGEgPSB0aGlzLl9fZGF0YV9fLFxuICAgICAgICBpbmRleCA9IF9hc3NvY0luZGV4T2YoZGF0YSwga2V5KTtcblxuICAgIGlmIChpbmRleCA8IDApIHtcbiAgICAgICsrdGhpcy5zaXplO1xuICAgICAgZGF0YS5wdXNoKFtrZXksIHZhbHVlXSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRhdGFbaW5kZXhdWzFdID0gdmFsdWU7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdmFyIF9saXN0Q2FjaGVTZXQgPSBsaXN0Q2FjaGVTZXQ7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gbGlzdCBjYWNoZSBvYmplY3QuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAcGFyYW0ge0FycmF5fSBbZW50cmllc10gVGhlIGtleS12YWx1ZSBwYWlycyB0byBjYWNoZS5cbiAgICovXG4gIGZ1bmN0aW9uIExpc3RDYWNoZShlbnRyaWVzKSB7XG4gICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgIGxlbmd0aCA9IGVudHJpZXMgPT0gbnVsbCA/IDAgOiBlbnRyaWVzLmxlbmd0aDtcblxuICAgIHRoaXMuY2xlYXIoKTtcbiAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgdmFyIGVudHJ5ID0gZW50cmllc1tpbmRleF07XG4gICAgICB0aGlzLnNldChlbnRyeVswXSwgZW50cnlbMV0pO1xuICAgIH1cbiAgfVxuXG4gIC8vIEFkZCBtZXRob2RzIHRvIGBMaXN0Q2FjaGVgLlxuICBMaXN0Q2FjaGUucHJvdG90eXBlLmNsZWFyID0gX2xpc3RDYWNoZUNsZWFyO1xuICBMaXN0Q2FjaGUucHJvdG90eXBlWydkZWxldGUnXSA9IF9saXN0Q2FjaGVEZWxldGU7XG4gIExpc3RDYWNoZS5wcm90b3R5cGUuZ2V0ID0gX2xpc3RDYWNoZUdldDtcbiAgTGlzdENhY2hlLnByb3RvdHlwZS5oYXMgPSBfbGlzdENhY2hlSGFzO1xuICBMaXN0Q2FjaGUucHJvdG90eXBlLnNldCA9IF9saXN0Q2FjaGVTZXQ7XG5cbiAgdmFyIF9MaXN0Q2FjaGUgPSBMaXN0Q2FjaGU7XG5cbiAgLyogQnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMgdGhhdCBhcmUgdmVyaWZpZWQgdG8gYmUgbmF0aXZlLiAqL1xuICB2YXIgTWFwJDEgPSBfZ2V0TmF0aXZlKF9yb290LCAnTWFwJyk7XG5cbiAgdmFyIF9NYXAgPSBNYXAkMTtcblxuICAvKipcbiAgICogUmVtb3ZlcyBhbGwga2V5LXZhbHVlIGVudHJpZXMgZnJvbSB0aGUgbWFwLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAbmFtZSBjbGVhclxuICAgKiBAbWVtYmVyT2YgTWFwQ2FjaGVcbiAgICovXG4gIGZ1bmN0aW9uIG1hcENhY2hlQ2xlYXIoKSB7XG4gICAgdGhpcy5zaXplID0gMDtcbiAgICB0aGlzLl9fZGF0YV9fID0ge1xuICAgICAgJ2hhc2gnOiBuZXcgX0hhc2gsXG4gICAgICAnbWFwJzogbmV3IChfTWFwIHx8IF9MaXN0Q2FjaGUpLFxuICAgICAgJ3N0cmluZyc6IG5ldyBfSGFzaFxuICAgIH07XG4gIH1cblxuICB2YXIgX21hcENhY2hlQ2xlYXIgPSBtYXBDYWNoZUNsZWFyO1xuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBzdWl0YWJsZSBmb3IgdXNlIGFzIHVuaXF1ZSBvYmplY3Qga2V5LlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgc3VpdGFibGUsIGVsc2UgYGZhbHNlYC5cbiAgICovXG4gIGZ1bmN0aW9uIGlzS2V5YWJsZSh2YWx1ZSkge1xuICAgIHZhciB0eXBlID0gdHlwZW9mIHZhbHVlO1xuICAgIHJldHVybiAodHlwZSA9PSAnc3RyaW5nJyB8fCB0eXBlID09ICdudW1iZXInIHx8IHR5cGUgPT0gJ3N5bWJvbCcgfHwgdHlwZSA9PSAnYm9vbGVhbicpXG4gICAgICA/ICh2YWx1ZSAhPT0gJ19fcHJvdG9fXycpXG4gICAgICA6ICh2YWx1ZSA9PT0gbnVsbCk7XG4gIH1cblxuICB2YXIgX2lzS2V5YWJsZSA9IGlzS2V5YWJsZTtcblxuICAvKipcbiAgICogR2V0cyB0aGUgZGF0YSBmb3IgYG1hcGAuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBtYXAgVGhlIG1hcCB0byBxdWVyeS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBUaGUgcmVmZXJlbmNlIGtleS5cbiAgICogQHJldHVybnMgeyp9IFJldHVybnMgdGhlIG1hcCBkYXRhLlxuICAgKi9cbiAgZnVuY3Rpb24gZ2V0TWFwRGF0YShtYXAsIGtleSkge1xuICAgIHZhciBkYXRhID0gbWFwLl9fZGF0YV9fO1xuICAgIHJldHVybiBfaXNLZXlhYmxlKGtleSlcbiAgICAgID8gZGF0YVt0eXBlb2Yga2V5ID09ICdzdHJpbmcnID8gJ3N0cmluZycgOiAnaGFzaCddXG4gICAgICA6IGRhdGEubWFwO1xuICB9XG5cbiAgdmFyIF9nZXRNYXBEYXRhID0gZ2V0TWFwRGF0YTtcblxuICAvKipcbiAgICogUmVtb3ZlcyBga2V5YCBhbmQgaXRzIHZhbHVlIGZyb20gdGhlIG1hcC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQG5hbWUgZGVsZXRlXG4gICAqIEBtZW1iZXJPZiBNYXBDYWNoZVxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IFRoZSBrZXkgb2YgdGhlIHZhbHVlIHRvIHJlbW92ZS5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHRoZSBlbnRyeSB3YXMgcmVtb3ZlZCwgZWxzZSBgZmFsc2VgLlxuICAgKi9cbiAgZnVuY3Rpb24gbWFwQ2FjaGVEZWxldGUoa2V5KSB7XG4gICAgdmFyIHJlc3VsdCA9IF9nZXRNYXBEYXRhKHRoaXMsIGtleSlbJ2RlbGV0ZSddKGtleSk7XG4gICAgdGhpcy5zaXplIC09IHJlc3VsdCA/IDEgOiAwO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICB2YXIgX21hcENhY2hlRGVsZXRlID0gbWFwQ2FjaGVEZWxldGU7XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIG1hcCB2YWx1ZSBmb3IgYGtleWAuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBuYW1lIGdldFxuICAgKiBAbWVtYmVyT2YgTWFwQ2FjaGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBUaGUga2V5IG9mIHRoZSB2YWx1ZSB0byBnZXQuXG4gICAqIEByZXR1cm5zIHsqfSBSZXR1cm5zIHRoZSBlbnRyeSB2YWx1ZS5cbiAgICovXG4gIGZ1bmN0aW9uIG1hcENhY2hlR2V0KGtleSkge1xuICAgIHJldHVybiBfZ2V0TWFwRGF0YSh0aGlzLCBrZXkpLmdldChrZXkpO1xuICB9XG5cbiAgdmFyIF9tYXBDYWNoZUdldCA9IG1hcENhY2hlR2V0O1xuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYSBtYXAgdmFsdWUgZm9yIGBrZXlgIGV4aXN0cy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQG5hbWUgaGFzXG4gICAqIEBtZW1iZXJPZiBNYXBDYWNoZVxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IFRoZSBrZXkgb2YgdGhlIGVudHJ5IHRvIGNoZWNrLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYW4gZW50cnkgZm9yIGBrZXlgIGV4aXN0cywgZWxzZSBgZmFsc2VgLlxuICAgKi9cbiAgZnVuY3Rpb24gbWFwQ2FjaGVIYXMoa2V5KSB7XG4gICAgcmV0dXJuIF9nZXRNYXBEYXRhKHRoaXMsIGtleSkuaGFzKGtleSk7XG4gIH1cblxuICB2YXIgX21hcENhY2hlSGFzID0gbWFwQ2FjaGVIYXM7XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIG1hcCBga2V5YCB0byBgdmFsdWVgLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAbmFtZSBzZXRcbiAgICogQG1lbWJlck9mIE1hcENhY2hlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVGhlIGtleSBvZiB0aGUgdmFsdWUgdG8gc2V0LlxuICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBzZXQuXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgdGhlIG1hcCBjYWNoZSBpbnN0YW5jZS5cbiAgICovXG4gIGZ1bmN0aW9uIG1hcENhY2hlU2V0KGtleSwgdmFsdWUpIHtcbiAgICB2YXIgZGF0YSA9IF9nZXRNYXBEYXRhKHRoaXMsIGtleSksXG4gICAgICAgIHNpemUgPSBkYXRhLnNpemU7XG5cbiAgICBkYXRhLnNldChrZXksIHZhbHVlKTtcbiAgICB0aGlzLnNpemUgKz0gZGF0YS5zaXplID09IHNpemUgPyAwIDogMTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHZhciBfbWFwQ2FjaGVTZXQgPSBtYXBDYWNoZVNldDtcblxuICAvKipcbiAgICogQ3JlYXRlcyBhIG1hcCBjYWNoZSBvYmplY3QgdG8gc3RvcmUga2V5LXZhbHVlIHBhaXJzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQHBhcmFtIHtBcnJheX0gW2VudHJpZXNdIFRoZSBrZXktdmFsdWUgcGFpcnMgdG8gY2FjaGUuXG4gICAqL1xuICBmdW5jdGlvbiBNYXBDYWNoZShlbnRyaWVzKSB7XG4gICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgIGxlbmd0aCA9IGVudHJpZXMgPT0gbnVsbCA/IDAgOiBlbnRyaWVzLmxlbmd0aDtcblxuICAgIHRoaXMuY2xlYXIoKTtcbiAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgdmFyIGVudHJ5ID0gZW50cmllc1tpbmRleF07XG4gICAgICB0aGlzLnNldChlbnRyeVswXSwgZW50cnlbMV0pO1xuICAgIH1cbiAgfVxuXG4gIC8vIEFkZCBtZXRob2RzIHRvIGBNYXBDYWNoZWAuXG4gIE1hcENhY2hlLnByb3RvdHlwZS5jbGVhciA9IF9tYXBDYWNoZUNsZWFyO1xuICBNYXBDYWNoZS5wcm90b3R5cGVbJ2RlbGV0ZSddID0gX21hcENhY2hlRGVsZXRlO1xuICBNYXBDYWNoZS5wcm90b3R5cGUuZ2V0ID0gX21hcENhY2hlR2V0O1xuICBNYXBDYWNoZS5wcm90b3R5cGUuaGFzID0gX21hcENhY2hlSGFzO1xuICBNYXBDYWNoZS5wcm90b3R5cGUuc2V0ID0gX21hcENhY2hlU2V0O1xuXG4gIHZhciBfTWFwQ2FjaGUgPSBNYXBDYWNoZTtcblxuICAvKiogRXJyb3IgbWVzc2FnZSBjb25zdGFudHMuICovXG4gIHZhciBGVU5DX0VSUk9SX1RFWFQgPSAnRXhwZWN0ZWQgYSBmdW5jdGlvbic7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IG1lbW9pemVzIHRoZSByZXN1bHQgb2YgYGZ1bmNgLiBJZiBgcmVzb2x2ZXJgIGlzXG4gICAqIHByb3ZpZGVkLCBpdCBkZXRlcm1pbmVzIHRoZSBjYWNoZSBrZXkgZm9yIHN0b3JpbmcgdGhlIHJlc3VsdCBiYXNlZCBvbiB0aGVcbiAgICogYXJndW1lbnRzIHByb3ZpZGVkIHRvIHRoZSBtZW1vaXplZCBmdW5jdGlvbi4gQnkgZGVmYXVsdCwgdGhlIGZpcnN0IGFyZ3VtZW50XG4gICAqIHByb3ZpZGVkIHRvIHRoZSBtZW1vaXplZCBmdW5jdGlvbiBpcyB1c2VkIGFzIHRoZSBtYXAgY2FjaGUga2V5LiBUaGUgYGZ1bmNgXG4gICAqIGlzIGludm9rZWQgd2l0aCB0aGUgYHRoaXNgIGJpbmRpbmcgb2YgdGhlIG1lbW9pemVkIGZ1bmN0aW9uLlxuICAgKlxuICAgKiAqKk5vdGU6KiogVGhlIGNhY2hlIGlzIGV4cG9zZWQgYXMgdGhlIGBjYWNoZWAgcHJvcGVydHkgb24gdGhlIG1lbW9pemVkXG4gICAqIGZ1bmN0aW9uLiBJdHMgY3JlYXRpb24gbWF5IGJlIGN1c3RvbWl6ZWQgYnkgcmVwbGFjaW5nIHRoZSBgXy5tZW1vaXplLkNhY2hlYFxuICAgKiBjb25zdHJ1Y3RvciB3aXRoIG9uZSB3aG9zZSBpbnN0YW5jZXMgaW1wbGVtZW50IHRoZVxuICAgKiBbYE1hcGBdKGh0dHA6Ly9lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLXByb3BlcnRpZXMtb2YtdGhlLW1hcC1wcm90b3R5cGUtb2JqZWN0KVxuICAgKiBtZXRob2QgaW50ZXJmYWNlIG9mIGBjbGVhcmAsIGBkZWxldGVgLCBgZ2V0YCwgYGhhc2AsIGFuZCBgc2V0YC5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKiBAbWVtYmVyT2YgX1xuICAgKiBAc2luY2UgMC4xLjBcbiAgICogQGNhdGVnb3J5IEZ1bmN0aW9uXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGhhdmUgaXRzIG91dHB1dCBtZW1vaXplZC5cbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gW3Jlc29sdmVyXSBUaGUgZnVuY3Rpb24gdG8gcmVzb2x2ZSB0aGUgY2FjaGUga2V5LlxuICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyBtZW1vaXplZCBmdW5jdGlvbi5cbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogdmFyIG9iamVjdCA9IHsgJ2EnOiAxLCAnYic6IDIgfTtcbiAgICogdmFyIG90aGVyID0geyAnYyc6IDMsICdkJzogNCB9O1xuICAgKlxuICAgKiB2YXIgdmFsdWVzID0gXy5tZW1vaXplKF8udmFsdWVzKTtcbiAgICogdmFsdWVzKG9iamVjdCk7XG4gICAqIC8vID0+IFsxLCAyXVxuICAgKlxuICAgKiB2YWx1ZXMob3RoZXIpO1xuICAgKiAvLyA9PiBbMywgNF1cbiAgICpcbiAgICogb2JqZWN0LmEgPSAyO1xuICAgKiB2YWx1ZXMob2JqZWN0KTtcbiAgICogLy8gPT4gWzEsIDJdXG4gICAqXG4gICAqIC8vIE1vZGlmeSB0aGUgcmVzdWx0IGNhY2hlLlxuICAgKiB2YWx1ZXMuY2FjaGUuc2V0KG9iamVjdCwgWydhJywgJ2InXSk7XG4gICAqIHZhbHVlcyhvYmplY3QpO1xuICAgKiAvLyA9PiBbJ2EnLCAnYiddXG4gICAqXG4gICAqIC8vIFJlcGxhY2UgYF8ubWVtb2l6ZS5DYWNoZWAuXG4gICAqIF8ubWVtb2l6ZS5DYWNoZSA9IFdlYWtNYXA7XG4gICAqL1xuICBmdW5jdGlvbiBtZW1vaXplKGZ1bmMsIHJlc29sdmVyKSB7XG4gICAgaWYgKHR5cGVvZiBmdW5jICE9ICdmdW5jdGlvbicgfHwgKHJlc29sdmVyICE9IG51bGwgJiYgdHlwZW9mIHJlc29sdmVyICE9ICdmdW5jdGlvbicpKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKEZVTkNfRVJST1JfVEVYVCk7XG4gICAgfVxuICAgIHZhciBtZW1vaXplZCA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHMsXG4gICAgICAgICAga2V5ID0gcmVzb2x2ZXIgPyByZXNvbHZlci5hcHBseSh0aGlzLCBhcmdzKSA6IGFyZ3NbMF0sXG4gICAgICAgICAgY2FjaGUgPSBtZW1vaXplZC5jYWNoZTtcblxuICAgICAgaWYgKGNhY2hlLmhhcyhrZXkpKSB7XG4gICAgICAgIHJldHVybiBjYWNoZS5nZXQoa2V5KTtcbiAgICAgIH1cbiAgICAgIHZhciByZXN1bHQgPSBmdW5jLmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgICAgbWVtb2l6ZWQuY2FjaGUgPSBjYWNoZS5zZXQoa2V5LCByZXN1bHQpIHx8IGNhY2hlO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIG1lbW9pemVkLmNhY2hlID0gbmV3IChtZW1vaXplLkNhY2hlIHx8IF9NYXBDYWNoZSk7XG4gICAgcmV0dXJuIG1lbW9pemVkO1xuICB9XG5cbiAgLy8gRXhwb3NlIGBNYXBDYWNoZWAuXG4gIG1lbW9pemUuQ2FjaGUgPSBfTWFwQ2FjaGU7XG5cbiAgdmFyIG1lbW9pemVfMSA9IG1lbW9pemU7XG5cbiAgLyoqIFVzZWQgYXMgdGhlIG1heGltdW0gbWVtb2l6ZSBjYWNoZSBzaXplLiAqL1xuICB2YXIgTUFYX01FTU9JWkVfU0laRSA9IDUwMDtcblxuICAvKipcbiAgICogQSBzcGVjaWFsaXplZCB2ZXJzaW9uIG9mIGBfLm1lbW9pemVgIHdoaWNoIGNsZWFycyB0aGUgbWVtb2l6ZWQgZnVuY3Rpb24nc1xuICAgKiBjYWNoZSB3aGVuIGl0IGV4Y2VlZHMgYE1BWF9NRU1PSVpFX1NJWkVgLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byBoYXZlIGl0cyBvdXRwdXQgbWVtb2l6ZWQuXG4gICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IG1lbW9pemVkIGZ1bmN0aW9uLlxuICAgKi9cbiAgZnVuY3Rpb24gbWVtb2l6ZUNhcHBlZChmdW5jKSB7XG4gICAgdmFyIHJlc3VsdCA9IG1lbW9pemVfMShmdW5jLCBmdW5jdGlvbihrZXkpIHtcbiAgICAgIGlmIChjYWNoZS5zaXplID09PSBNQVhfTUVNT0laRV9TSVpFKSB7XG4gICAgICAgIGNhY2hlLmNsZWFyKCk7XG4gICAgICB9XG4gICAgICByZXR1cm4ga2V5O1xuICAgIH0pO1xuXG4gICAgdmFyIGNhY2hlID0gcmVzdWx0LmNhY2hlO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICB2YXIgX21lbW9pemVDYXBwZWQgPSBtZW1vaXplQ2FwcGVkO1xuXG4gIC8qKiBVc2VkIHRvIG1hdGNoIHByb3BlcnR5IG5hbWVzIHdpdGhpbiBwcm9wZXJ0eSBwYXRocy4gKi9cbiAgdmFyIHJlUHJvcE5hbWUgPSAvW14uW1xcXV0rfFxcWyg/OigtP1xcZCsoPzpcXC5cXGQrKT8pfChbXCInXSkoKD86KD8hXFwyKVteXFxcXF18XFxcXC4pKj8pXFwyKVxcXXwoPz0oPzpcXC58XFxbXFxdKSg/OlxcLnxcXFtcXF18JCkpL2c7XG5cbiAgLyoqIFVzZWQgdG8gbWF0Y2ggYmFja3NsYXNoZXMgaW4gcHJvcGVydHkgcGF0aHMuICovXG4gIHZhciByZUVzY2FwZUNoYXIgPSAvXFxcXChcXFxcKT8vZztcblxuICAvKipcbiAgICogQ29udmVydHMgYHN0cmluZ2AgdG8gYSBwcm9wZXJ0eSBwYXRoIGFycmF5LlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nIFRoZSBzdHJpbmcgdG8gY29udmVydC5cbiAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIHRoZSBwcm9wZXJ0eSBwYXRoIGFycmF5LlxuICAgKi9cbiAgdmFyIHN0cmluZ1RvUGF0aCA9IF9tZW1vaXplQ2FwcGVkKGZ1bmN0aW9uKHN0cmluZykge1xuICAgIHZhciByZXN1bHQgPSBbXTtcbiAgICBpZiAoc3RyaW5nLmNoYXJDb2RlQXQoMCkgPT09IDQ2IC8qIC4gKi8pIHtcbiAgICAgIHJlc3VsdC5wdXNoKCcnKTtcbiAgICB9XG4gICAgc3RyaW5nLnJlcGxhY2UocmVQcm9wTmFtZSwgZnVuY3Rpb24obWF0Y2gsIG51bWJlciwgcXVvdGUsIHN1YlN0cmluZykge1xuICAgICAgcmVzdWx0LnB1c2gocXVvdGUgPyBzdWJTdHJpbmcucmVwbGFjZShyZUVzY2FwZUNoYXIsICckMScpIDogKG51bWJlciB8fCBtYXRjaCkpO1xuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH0pO1xuXG4gIHZhciBfc3RyaW5nVG9QYXRoID0gc3RyaW5nVG9QYXRoO1xuXG4gIC8qKlxuICAgKiBBIHNwZWNpYWxpemVkIHZlcnNpb24gb2YgYF8ubWFwYCBmb3IgYXJyYXlzIHdpdGhvdXQgc3VwcG9ydCBmb3IgaXRlcmF0ZWVcbiAgICogc2hvcnRoYW5kcy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtBcnJheX0gW2FycmF5XSBUaGUgYXJyYXkgdG8gaXRlcmF0ZSBvdmVyLlxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBpdGVyYXRlZSBUaGUgZnVuY3Rpb24gaW52b2tlZCBwZXIgaXRlcmF0aW9uLlxuICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgdGhlIG5ldyBtYXBwZWQgYXJyYXkuXG4gICAqL1xuICBmdW5jdGlvbiBhcnJheU1hcChhcnJheSwgaXRlcmF0ZWUpIHtcbiAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgbGVuZ3RoID0gYXJyYXkgPT0gbnVsbCA/IDAgOiBhcnJheS5sZW5ndGgsXG4gICAgICAgIHJlc3VsdCA9IEFycmF5KGxlbmd0aCk7XG5cbiAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgcmVzdWx0W2luZGV4XSA9IGl0ZXJhdGVlKGFycmF5W2luZGV4XSwgaW5kZXgsIGFycmF5KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHZhciBfYXJyYXlNYXAgPSBhcnJheU1hcDtcblxuICAvKiogVXNlZCBhcyByZWZlcmVuY2VzIGZvciB2YXJpb3VzIGBOdW1iZXJgIGNvbnN0YW50cy4gKi9cbiAgdmFyIElORklOSVRZJDEgPSAxIC8gMDtcblxuICAvKiogVXNlZCB0byBjb252ZXJ0IHN5bWJvbHMgdG8gcHJpbWl0aXZlcyBhbmQgc3RyaW5ncy4gKi9cbiAgdmFyIHN5bWJvbFByb3RvID0gX1N5bWJvbCA/IF9TeW1ib2wucHJvdG90eXBlIDogdW5kZWZpbmVkLFxuICAgICAgc3ltYm9sVG9TdHJpbmcgPSBzeW1ib2xQcm90byA/IHN5bWJvbFByb3RvLnRvU3RyaW5nIDogdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBUaGUgYmFzZSBpbXBsZW1lbnRhdGlvbiBvZiBgXy50b1N0cmluZ2Agd2hpY2ggZG9lc24ndCBjb252ZXJ0IG51bGxpc2hcbiAgICogdmFsdWVzIHRvIGVtcHR5IHN0cmluZ3MuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIHByb2Nlc3MuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IFJldHVybnMgdGhlIHN0cmluZy5cbiAgICovXG4gIGZ1bmN0aW9uIGJhc2VUb1N0cmluZyh2YWx1ZSkge1xuICAgIC8vIEV4aXQgZWFybHkgZm9yIHN0cmluZ3MgdG8gYXZvaWQgYSBwZXJmb3JtYW5jZSBoaXQgaW4gc29tZSBlbnZpcm9ubWVudHMuXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgICBpZiAoaXNBcnJheV8xKHZhbHVlKSkge1xuICAgICAgLy8gUmVjdXJzaXZlbHkgY29udmVydCB2YWx1ZXMgKHN1c2NlcHRpYmxlIHRvIGNhbGwgc3RhY2sgbGltaXRzKS5cbiAgICAgIHJldHVybiBfYXJyYXlNYXAodmFsdWUsIGJhc2VUb1N0cmluZykgKyAnJztcbiAgICB9XG4gICAgaWYgKGlzU3ltYm9sXzEodmFsdWUpKSB7XG4gICAgICByZXR1cm4gc3ltYm9sVG9TdHJpbmcgPyBzeW1ib2xUb1N0cmluZy5jYWxsKHZhbHVlKSA6ICcnO1xuICAgIH1cbiAgICB2YXIgcmVzdWx0ID0gKHZhbHVlICsgJycpO1xuICAgIHJldHVybiAocmVzdWx0ID09ICcwJyAmJiAoMSAvIHZhbHVlKSA9PSAtSU5GSU5JVFkkMSkgPyAnLTAnIDogcmVzdWx0O1xuICB9XG5cbiAgdmFyIF9iYXNlVG9TdHJpbmcgPSBiYXNlVG9TdHJpbmc7XG5cbiAgLyoqXG4gICAqIENvbnZlcnRzIGB2YWx1ZWAgdG8gYSBzdHJpbmcuIEFuIGVtcHR5IHN0cmluZyBpcyByZXR1cm5lZCBmb3IgYG51bGxgXG4gICAqIGFuZCBgdW5kZWZpbmVkYCB2YWx1ZXMuIFRoZSBzaWduIG9mIGAtMGAgaXMgcHJlc2VydmVkLlxuICAgKlxuICAgKiBAc3RhdGljXG4gICAqIEBtZW1iZXJPZiBfXG4gICAqIEBzaW5jZSA0LjAuMFxuICAgKiBAY2F0ZWdvcnkgTGFuZ1xuICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjb252ZXJ0LlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBSZXR1cm5zIHRoZSBjb252ZXJ0ZWQgc3RyaW5nLlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiBfLnRvU3RyaW5nKG51bGwpO1xuICAgKiAvLyA9PiAnJ1xuICAgKlxuICAgKiBfLnRvU3RyaW5nKC0wKTtcbiAgICogLy8gPT4gJy0wJ1xuICAgKlxuICAgKiBfLnRvU3RyaW5nKFsxLCAyLCAzXSk7XG4gICAqIC8vID0+ICcxLDIsMydcbiAgICovXG4gIGZ1bmN0aW9uIHRvU3RyaW5nJDEodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgPT0gbnVsbCA/ICcnIDogX2Jhc2VUb1N0cmluZyh2YWx1ZSk7XG4gIH1cblxuICB2YXIgdG9TdHJpbmdfMSA9IHRvU3RyaW5nJDE7XG5cbiAgLyoqXG4gICAqIENhc3RzIGB2YWx1ZWAgdG8gYSBwYXRoIGFycmF5IGlmIGl0J3Mgbm90IG9uZS5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gaW5zcGVjdC5cbiAgICogQHBhcmFtIHtPYmplY3R9IFtvYmplY3RdIFRoZSBvYmplY3QgdG8gcXVlcnkga2V5cyBvbi5cbiAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIHRoZSBjYXN0IHByb3BlcnR5IHBhdGggYXJyYXkuXG4gICAqL1xuICBmdW5jdGlvbiBjYXN0UGF0aCh2YWx1ZSwgb2JqZWN0KSB7XG4gICAgaWYgKGlzQXJyYXlfMSh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gICAgcmV0dXJuIF9pc0tleSh2YWx1ZSwgb2JqZWN0KSA/IFt2YWx1ZV0gOiBfc3RyaW5nVG9QYXRoKHRvU3RyaW5nXzEodmFsdWUpKTtcbiAgfVxuXG4gIHZhciBfY2FzdFBhdGggPSBjYXN0UGF0aDtcblxuICAvKiogVXNlZCBhcyByZWZlcmVuY2VzIGZvciB2YXJpb3VzIGBOdW1iZXJgIGNvbnN0YW50cy4gKi9cbiAgdmFyIElORklOSVRZID0gMSAvIDA7XG5cbiAgLyoqXG4gICAqIENvbnZlcnRzIGB2YWx1ZWAgdG8gYSBzdHJpbmcga2V5IGlmIGl0J3Mgbm90IGEgc3RyaW5nIG9yIHN5bWJvbC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gaW5zcGVjdC5cbiAgICogQHJldHVybnMge3N0cmluZ3xzeW1ib2x9IFJldHVybnMgdGhlIGtleS5cbiAgICovXG4gIGZ1bmN0aW9uIHRvS2V5KHZhbHVlKSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PSAnc3RyaW5nJyB8fCBpc1N5bWJvbF8xKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgICB2YXIgcmVzdWx0ID0gKHZhbHVlICsgJycpO1xuICAgIHJldHVybiAocmVzdWx0ID09ICcwJyAmJiAoMSAvIHZhbHVlKSA9PSAtSU5GSU5JVFkpID8gJy0wJyA6IHJlc3VsdDtcbiAgfVxuXG4gIHZhciBfdG9LZXkgPSB0b0tleTtcblxuICAvKipcbiAgICogVGhlIGJhc2UgaW1wbGVtZW50YXRpb24gb2YgYF8uZ2V0YCB3aXRob3V0IHN1cHBvcnQgZm9yIGRlZmF1bHQgdmFsdWVzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gcXVlcnkuXG4gICAqIEBwYXJhbSB7QXJyYXl8c3RyaW5nfSBwYXRoIFRoZSBwYXRoIG9mIHRoZSBwcm9wZXJ0eSB0byBnZXQuXG4gICAqIEByZXR1cm5zIHsqfSBSZXR1cm5zIHRoZSByZXNvbHZlZCB2YWx1ZS5cbiAgICovXG4gIGZ1bmN0aW9uIGJhc2VHZXQob2JqZWN0LCBwYXRoKSB7XG4gICAgcGF0aCA9IF9jYXN0UGF0aChwYXRoLCBvYmplY3QpO1xuXG4gICAgdmFyIGluZGV4ID0gMCxcbiAgICAgICAgbGVuZ3RoID0gcGF0aC5sZW5ndGg7XG5cbiAgICB3aGlsZSAob2JqZWN0ICE9IG51bGwgJiYgaW5kZXggPCBsZW5ndGgpIHtcbiAgICAgIG9iamVjdCA9IG9iamVjdFtfdG9LZXkocGF0aFtpbmRleCsrXSldO1xuICAgIH1cbiAgICByZXR1cm4gKGluZGV4ICYmIGluZGV4ID09IGxlbmd0aCkgPyBvYmplY3QgOiB1bmRlZmluZWQ7XG4gIH1cblxuICB2YXIgX2Jhc2VHZXQgPSBiYXNlR2V0O1xuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSB2YWx1ZSBhdCBgcGF0aGAgb2YgYG9iamVjdGAuIElmIHRoZSByZXNvbHZlZCB2YWx1ZSBpc1xuICAgKiBgdW5kZWZpbmVkYCwgdGhlIGBkZWZhdWx0VmFsdWVgIGlzIHJldHVybmVkIGluIGl0cyBwbGFjZS5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKiBAbWVtYmVyT2YgX1xuICAgKiBAc2luY2UgMy43LjBcbiAgICogQGNhdGVnb3J5IE9iamVjdFxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gcXVlcnkuXG4gICAqIEBwYXJhbSB7QXJyYXl8c3RyaW5nfSBwYXRoIFRoZSBwYXRoIG9mIHRoZSBwcm9wZXJ0eSB0byBnZXQuXG4gICAqIEBwYXJhbSB7Kn0gW2RlZmF1bHRWYWx1ZV0gVGhlIHZhbHVlIHJldHVybmVkIGZvciBgdW5kZWZpbmVkYCByZXNvbHZlZCB2YWx1ZXMuXG4gICAqIEByZXR1cm5zIHsqfSBSZXR1cm5zIHRoZSByZXNvbHZlZCB2YWx1ZS5cbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogdmFyIG9iamVjdCA9IHsgJ2EnOiBbeyAnYic6IHsgJ2MnOiAzIH0gfV0gfTtcbiAgICpcbiAgICogXy5nZXQob2JqZWN0LCAnYVswXS5iLmMnKTtcbiAgICogLy8gPT4gM1xuICAgKlxuICAgKiBfLmdldChvYmplY3QsIFsnYScsICcwJywgJ2InLCAnYyddKTtcbiAgICogLy8gPT4gM1xuICAgKlxuICAgKiBfLmdldChvYmplY3QsICdhLmIuYycsICdkZWZhdWx0Jyk7XG4gICAqIC8vID0+ICdkZWZhdWx0J1xuICAgKi9cbiAgZnVuY3Rpb24gZ2V0KG9iamVjdCwgcGF0aCwgZGVmYXVsdFZhbHVlKSB7XG4gICAgdmFyIHJlc3VsdCA9IG9iamVjdCA9PSBudWxsID8gdW5kZWZpbmVkIDogX2Jhc2VHZXQob2JqZWN0LCBwYXRoKTtcbiAgICByZXR1cm4gcmVzdWx0ID09PSB1bmRlZmluZWQgPyBkZWZhdWx0VmFsdWUgOiByZXN1bHQ7XG4gIH1cblxuICB2YXIgZ2V0XzEgPSBnZXQ7XG5cbiAgdmFyIGRlZmluZVByb3BlcnR5ID0gKGZ1bmN0aW9uKCkge1xuICAgIHRyeSB7XG4gICAgICB2YXIgZnVuYyA9IF9nZXROYXRpdmUoT2JqZWN0LCAnZGVmaW5lUHJvcGVydHknKTtcbiAgICAgIGZ1bmMoe30sICcnLCB7fSk7XG4gICAgICByZXR1cm4gZnVuYztcbiAgICB9IGNhdGNoIChlKSB7fVxuICB9KCkpO1xuXG4gIHZhciBfZGVmaW5lUHJvcGVydHkgPSBkZWZpbmVQcm9wZXJ0eTtcblxuICAvKipcbiAgICogVGhlIGJhc2UgaW1wbGVtZW50YXRpb24gb2YgYGFzc2lnblZhbHVlYCBhbmQgYGFzc2lnbk1lcmdlVmFsdWVgIHdpdGhvdXRcbiAgICogdmFsdWUgY2hlY2tzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gbW9kaWZ5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IFRoZSBrZXkgb2YgdGhlIHByb3BlcnR5IHRvIGFzc2lnbi5cbiAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gYXNzaWduLlxuICAgKi9cbiAgZnVuY3Rpb24gYmFzZUFzc2lnblZhbHVlKG9iamVjdCwga2V5LCB2YWx1ZSkge1xuICAgIGlmIChrZXkgPT0gJ19fcHJvdG9fXycgJiYgX2RlZmluZVByb3BlcnR5KSB7XG4gICAgICBfZGVmaW5lUHJvcGVydHkob2JqZWN0LCBrZXksIHtcbiAgICAgICAgJ2NvbmZpZ3VyYWJsZSc6IHRydWUsXG4gICAgICAgICdlbnVtZXJhYmxlJzogdHJ1ZSxcbiAgICAgICAgJ3ZhbHVlJzogdmFsdWUsXG4gICAgICAgICd3cml0YWJsZSc6IHRydWVcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBvYmplY3Rba2V5XSA9IHZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIHZhciBfYmFzZUFzc2lnblZhbHVlID0gYmFzZUFzc2lnblZhbHVlO1xuXG4gIC8qKiBVc2VkIGZvciBidWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcy4gKi9cbiAgdmFyIG9iamVjdFByb3RvID0gT2JqZWN0LnByb3RvdHlwZTtcblxuICAvKiogVXNlZCB0byBjaGVjayBvYmplY3RzIGZvciBvd24gcHJvcGVydGllcy4gKi9cbiAgdmFyIGhhc093blByb3BlcnR5ID0gb2JqZWN0UHJvdG8uaGFzT3duUHJvcGVydHk7XG5cbiAgLyoqXG4gICAqIEFzc2lnbnMgYHZhbHVlYCB0byBga2V5YCBvZiBgb2JqZWN0YCBpZiB0aGUgZXhpc3RpbmcgdmFsdWUgaXMgbm90IGVxdWl2YWxlbnRcbiAgICogdXNpbmcgW2BTYW1lVmFsdWVaZXJvYF0oaHR0cDovL2VjbWEtaW50ZXJuYXRpb25hbC5vcmcvZWNtYS0yNjIvNy4wLyNzZWMtc2FtZXZhbHVlemVybylcbiAgICogZm9yIGVxdWFsaXR5IGNvbXBhcmlzb25zLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gbW9kaWZ5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IFRoZSBrZXkgb2YgdGhlIHByb3BlcnR5IHRvIGFzc2lnbi5cbiAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gYXNzaWduLlxuICAgKi9cbiAgZnVuY3Rpb24gYXNzaWduVmFsdWUob2JqZWN0LCBrZXksIHZhbHVlKSB7XG4gICAgdmFyIG9ialZhbHVlID0gb2JqZWN0W2tleV07XG4gICAgaWYgKCEoaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3QsIGtleSkgJiYgZXFfMShvYmpWYWx1ZSwgdmFsdWUpKSB8fFxuICAgICAgICAodmFsdWUgPT09IHVuZGVmaW5lZCAmJiAhKGtleSBpbiBvYmplY3QpKSkge1xuICAgICAgX2Jhc2VBc3NpZ25WYWx1ZShvYmplY3QsIGtleSwgdmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIHZhciBfYXNzaWduVmFsdWUgPSBhc3NpZ25WYWx1ZTtcblxuICAvKiogVXNlZCBhcyByZWZlcmVuY2VzIGZvciB2YXJpb3VzIGBOdW1iZXJgIGNvbnN0YW50cy4gKi9cbiAgdmFyIE1BWF9TQUZFX0lOVEVHRVIgPSA5MDA3MTk5MjU0NzQwOTkxO1xuXG4gIC8qKiBVc2VkIHRvIGRldGVjdCB1bnNpZ25lZCBpbnRlZ2VyIHZhbHVlcy4gKi9cbiAgdmFyIHJlSXNVaW50ID0gL14oPzowfFsxLTldXFxkKikkLztcblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgYSB2YWxpZCBhcnJheS1saWtlIGluZGV4LlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFtsZW5ndGg9TUFYX1NBRkVfSU5URUdFUl0gVGhlIHVwcGVyIGJvdW5kcyBvZiBhIHZhbGlkIGluZGV4LlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBhIHZhbGlkIGluZGV4LCBlbHNlIGBmYWxzZWAuXG4gICAqL1xuICBmdW5jdGlvbiBpc0luZGV4KHZhbHVlLCBsZW5ndGgpIHtcbiAgICB2YXIgdHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgICBsZW5ndGggPSBsZW5ndGggPT0gbnVsbCA/IE1BWF9TQUZFX0lOVEVHRVIgOiBsZW5ndGg7XG5cbiAgICByZXR1cm4gISFsZW5ndGggJiZcbiAgICAgICh0eXBlID09ICdudW1iZXInIHx8XG4gICAgICAgICh0eXBlICE9ICdzeW1ib2wnICYmIHJlSXNVaW50LnRlc3QodmFsdWUpKSkgJiZcbiAgICAgICAgICAodmFsdWUgPiAtMSAmJiB2YWx1ZSAlIDEgPT0gMCAmJiB2YWx1ZSA8IGxlbmd0aCk7XG4gIH1cblxuICB2YXIgX2lzSW5kZXggPSBpc0luZGV4O1xuXG4gIC8qKlxuICAgKiBUaGUgYmFzZSBpbXBsZW1lbnRhdGlvbiBvZiBgXy5zZXRgLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gbW9kaWZ5LlxuICAgKiBAcGFyYW0ge0FycmF5fHN0cmluZ30gcGF0aCBUaGUgcGF0aCBvZiB0aGUgcHJvcGVydHkgdG8gc2V0LlxuICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBzZXQuXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjdXN0b21pemVyXSBUaGUgZnVuY3Rpb24gdG8gY3VzdG9taXplIHBhdGggY3JlYXRpb24uXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgYG9iamVjdGAuXG4gICAqL1xuICBmdW5jdGlvbiBiYXNlU2V0KG9iamVjdCwgcGF0aCwgdmFsdWUsIGN1c3RvbWl6ZXIpIHtcbiAgICBpZiAoIWlzT2JqZWN0XzEob2JqZWN0KSkge1xuICAgICAgcmV0dXJuIG9iamVjdDtcbiAgICB9XG4gICAgcGF0aCA9IF9jYXN0UGF0aChwYXRoLCBvYmplY3QpO1xuXG4gICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgIGxlbmd0aCA9IHBhdGgubGVuZ3RoLFxuICAgICAgICBsYXN0SW5kZXggPSBsZW5ndGggLSAxLFxuICAgICAgICBuZXN0ZWQgPSBvYmplY3Q7XG5cbiAgICB3aGlsZSAobmVzdGVkICE9IG51bGwgJiYgKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgdmFyIGtleSA9IF90b0tleShwYXRoW2luZGV4XSksXG4gICAgICAgICAgbmV3VmFsdWUgPSB2YWx1ZTtcblxuICAgICAgaWYgKGtleSA9PT0gJ19fcHJvdG9fXycgfHwga2V5ID09PSAnY29uc3RydWN0b3InIHx8IGtleSA9PT0gJ3Byb3RvdHlwZScpIHtcbiAgICAgICAgcmV0dXJuIG9iamVjdDtcbiAgICAgIH1cblxuICAgICAgaWYgKGluZGV4ICE9IGxhc3RJbmRleCkge1xuICAgICAgICB2YXIgb2JqVmFsdWUgPSBuZXN0ZWRba2V5XTtcbiAgICAgICAgbmV3VmFsdWUgPSBjdXN0b21pemVyID8gY3VzdG9taXplcihvYmpWYWx1ZSwga2V5LCBuZXN0ZWQpIDogdW5kZWZpbmVkO1xuICAgICAgICBpZiAobmV3VmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIG5ld1ZhbHVlID0gaXNPYmplY3RfMShvYmpWYWx1ZSlcbiAgICAgICAgICAgID8gb2JqVmFsdWVcbiAgICAgICAgICAgIDogKF9pc0luZGV4KHBhdGhbaW5kZXggKyAxXSkgPyBbXSA6IHt9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgX2Fzc2lnblZhbHVlKG5lc3RlZCwga2V5LCBuZXdWYWx1ZSk7XG4gICAgICBuZXN0ZWQgPSBuZXN0ZWRba2V5XTtcbiAgICB9XG4gICAgcmV0dXJuIG9iamVjdDtcbiAgfVxuXG4gIHZhciBfYmFzZVNldCA9IGJhc2VTZXQ7XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIHZhbHVlIGF0IGBwYXRoYCBvZiBgb2JqZWN0YC4gSWYgYSBwb3J0aW9uIG9mIGBwYXRoYCBkb2Vzbid0IGV4aXN0LFxuICAgKiBpdCdzIGNyZWF0ZWQuIEFycmF5cyBhcmUgY3JlYXRlZCBmb3IgbWlzc2luZyBpbmRleCBwcm9wZXJ0aWVzIHdoaWxlIG9iamVjdHNcbiAgICogYXJlIGNyZWF0ZWQgZm9yIGFsbCBvdGhlciBtaXNzaW5nIHByb3BlcnRpZXMuIFVzZSBgXy5zZXRXaXRoYCB0byBjdXN0b21pemVcbiAgICogYHBhdGhgIGNyZWF0aW9uLlxuICAgKlxuICAgKiAqKk5vdGU6KiogVGhpcyBtZXRob2QgbXV0YXRlcyBgb2JqZWN0YC5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKiBAbWVtYmVyT2YgX1xuICAgKiBAc2luY2UgMy43LjBcbiAgICogQGNhdGVnb3J5IE9iamVjdFxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gbW9kaWZ5LlxuICAgKiBAcGFyYW0ge0FycmF5fHN0cmluZ30gcGF0aCBUaGUgcGF0aCBvZiB0aGUgcHJvcGVydHkgdG8gc2V0LlxuICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBzZXQuXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgYG9iamVjdGAuXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIHZhciBvYmplY3QgPSB7ICdhJzogW3sgJ2InOiB7ICdjJzogMyB9IH1dIH07XG4gICAqXG4gICAqIF8uc2V0KG9iamVjdCwgJ2FbMF0uYi5jJywgNCk7XG4gICAqIGNvbnNvbGUubG9nKG9iamVjdC5hWzBdLmIuYyk7XG4gICAqIC8vID0+IDRcbiAgICpcbiAgICogXy5zZXQob2JqZWN0LCBbJ3gnLCAnMCcsICd5JywgJ3onXSwgNSk7XG4gICAqIGNvbnNvbGUubG9nKG9iamVjdC54WzBdLnkueik7XG4gICAqIC8vID0+IDVcbiAgICovXG4gIGZ1bmN0aW9uIHNldChvYmplY3QsIHBhdGgsIHZhbHVlKSB7XG4gICAgcmV0dXJuIG9iamVjdCA9PSBudWxsID8gb2JqZWN0IDogX2Jhc2VTZXQob2JqZWN0LCBwYXRoLCB2YWx1ZSk7XG4gIH1cblxuICB2YXIgc2V0XzEgPSBzZXQ7XG5cbiAgLyoqXG4gICAqIENvcGllcyB0aGUgdmFsdWVzIG9mIGBzb3VyY2VgIHRvIGBhcnJheWAuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7QXJyYXl9IHNvdXJjZSBUaGUgYXJyYXkgdG8gY29weSB2YWx1ZXMgZnJvbS5cbiAgICogQHBhcmFtIHtBcnJheX0gW2FycmF5PVtdXSBUaGUgYXJyYXkgdG8gY29weSB2YWx1ZXMgdG8uXG4gICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBgYXJyYXlgLlxuICAgKi9cbiAgZnVuY3Rpb24gY29weUFycmF5KHNvdXJjZSwgYXJyYXkpIHtcbiAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgbGVuZ3RoID0gc291cmNlLmxlbmd0aDtcblxuICAgIGFycmF5IHx8IChhcnJheSA9IEFycmF5KGxlbmd0aCkpO1xuICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICBhcnJheVtpbmRleF0gPSBzb3VyY2VbaW5kZXhdO1xuICAgIH1cbiAgICByZXR1cm4gYXJyYXk7XG4gIH1cblxuICB2YXIgX2NvcHlBcnJheSA9IGNvcHlBcnJheTtcblxuICAvKipcbiAgICogQ29udmVydHMgYHZhbHVlYCB0byBhIHByb3BlcnR5IHBhdGggYXJyYXkuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQG1lbWJlck9mIF9cbiAgICogQHNpbmNlIDQuMC4wXG4gICAqIEBjYXRlZ29yeSBVdGlsXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNvbnZlcnQuXG4gICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyB0aGUgbmV3IHByb3BlcnR5IHBhdGggYXJyYXkuXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIF8udG9QYXRoKCdhLmIuYycpO1xuICAgKiAvLyA9PiBbJ2EnLCAnYicsICdjJ11cbiAgICpcbiAgICogXy50b1BhdGgoJ2FbMF0uYi5jJyk7XG4gICAqIC8vID0+IFsnYScsICcwJywgJ2InLCAnYyddXG4gICAqL1xuICBmdW5jdGlvbiB0b1BhdGgodmFsdWUpIHtcbiAgICBpZiAoaXNBcnJheV8xKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIF9hcnJheU1hcCh2YWx1ZSwgX3RvS2V5KTtcbiAgICB9XG4gICAgcmV0dXJuIGlzU3ltYm9sXzEodmFsdWUpID8gW3ZhbHVlXSA6IF9jb3B5QXJyYXkoX3N0cmluZ1RvUGF0aCh0b1N0cmluZ18xKHZhbHVlKSkpO1xuICB9XG5cbiAgdmFyIHRvUGF0aF8xID0gdG9QYXRoO1xuXG4gIHZhciBkZWZpbmUkMiA9IHtcbiAgICAvLyBhY2Nlc3MgZGF0YSBmaWVsZFxuICAgIGRhdGE6IGZ1bmN0aW9uIGRhdGEocGFyYW1zKSB7XG4gICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIGZpZWxkOiAnZGF0YScsXG4gICAgICAgIGJpbmRpbmdFdmVudDogJ2RhdGEnLFxuICAgICAgICBhbGxvd0JpbmRpbmc6IGZhbHNlLFxuICAgICAgICBhbGxvd1NldHRpbmc6IGZhbHNlLFxuICAgICAgICBhbGxvd0dldHRpbmc6IGZhbHNlLFxuICAgICAgICBzZXR0aW5nRXZlbnQ6ICdkYXRhJyxcbiAgICAgICAgc2V0dGluZ1RyaWdnZXJzRXZlbnQ6IGZhbHNlLFxuICAgICAgICB0cmlnZ2VyRm5OYW1lOiAndHJpZ2dlcicsXG4gICAgICAgIGltbXV0YWJsZUtleXM6IHt9LFxuICAgICAgICAvLyBrZXkgPT4gdHJ1ZSBpZiBpbW11dGFibGVcbiAgICAgICAgdXBkYXRlU3R5bGU6IGZhbHNlLFxuICAgICAgICBiZWZvcmVHZXQ6IGZ1bmN0aW9uIGJlZm9yZUdldChzZWxmKSB7fSxcbiAgICAgICAgYmVmb3JlU2V0OiBmdW5jdGlvbiBiZWZvcmVTZXQoc2VsZiwgb2JqKSB7fSxcbiAgICAgICAgb25TZXQ6IGZ1bmN0aW9uIG9uU2V0KHNlbGYpIHt9LFxuICAgICAgICBjYW5TZXQ6IGZ1bmN0aW9uIGNhblNldChzZWxmKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICBwYXJhbXMgPSBleHRlbmQoe30sIGRlZmF1bHRzLCBwYXJhbXMpO1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uIGRhdGFJbXBsKG5hbWUsIHZhbHVlKSB7XG4gICAgICAgIHZhciBwID0gcGFyYW1zO1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHZhciBzZWxmSXNBcnJheUxpa2UgPSBzZWxmLmxlbmd0aCAhPT0gdW5kZWZpbmVkO1xuICAgICAgICB2YXIgYWxsID0gc2VsZklzQXJyYXlMaWtlID8gc2VsZiA6IFtzZWxmXTsgLy8gcHV0IGluIGFycmF5IGlmIG5vdCBhcnJheS1saWtlXG5cbiAgICAgICAgdmFyIHNpbmdsZSA9IHNlbGZJc0FycmF5TGlrZSA/IHNlbGZbMF0gOiBzZWxmOyAvLyAuZGF0YSgnZm9vJywgLi4uKVxuXG4gICAgICAgIGlmIChzdHJpbmcobmFtZSkpIHtcbiAgICAgICAgICAvLyBzZXQgb3IgZ2V0IHByb3BlcnR5XG4gICAgICAgICAgdmFyIGlzUGF0aExpa2UgPSBuYW1lLmluZGV4T2YoJy4nKSAhPT0gLTE7IC8vIHRoZXJlIG1pZ2h0IGJlIGEgbm9ybWFsIGZpZWxkIHdpdGggYSBkb3QgXG5cbiAgICAgICAgICB2YXIgcGF0aCA9IGlzUGF0aExpa2UgJiYgdG9QYXRoXzEobmFtZSk7IC8vIC5kYXRhKCdmb28nKVxuXG4gICAgICAgICAgaWYgKHAuYWxsb3dHZXR0aW5nICYmIHZhbHVlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIGdldFxuICAgICAgICAgICAgdmFyIHJldDtcblxuICAgICAgICAgICAgaWYgKHNpbmdsZSkge1xuICAgICAgICAgICAgICBwLmJlZm9yZUdldChzaW5nbGUpOyAvLyBjaGVjayBpZiBpdCdzIHBhdGggYW5kIGEgZmllbGQgd2l0aCB0aGUgc2FtZSBuYW1lIGRvZXNuJ3QgZXhpc3RcblxuICAgICAgICAgICAgICBpZiAocGF0aCAmJiBzaW5nbGUuX3ByaXZhdGVbcC5maWVsZF1bbmFtZV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldCA9IGdldF8xKHNpbmdsZS5fcHJpdmF0ZVtwLmZpZWxkXSwgcGF0aCk7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0ID0gc2luZ2xlLl9wcml2YXRlW3AuZmllbGRdW25hbWVdO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiByZXQ7IC8vIC5kYXRhKCdmb28nLCAnYmFyJylcbiAgICAgICAgICB9IGVsc2UgaWYgKHAuYWxsb3dTZXR0aW5nICYmIHZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIHNldFxuICAgICAgICAgICAgdmFyIHZhbGlkID0gIXAuaW1tdXRhYmxlS2V5c1tuYW1lXTtcblxuICAgICAgICAgICAgaWYgKHZhbGlkKSB7XG4gICAgICAgICAgICAgIHZhciBjaGFuZ2UgPSBfZGVmaW5lUHJvcGVydHkkMSh7fSwgbmFtZSwgdmFsdWUpO1xuXG4gICAgICAgICAgICAgIHAuYmVmb3JlU2V0KHNlbGYsIGNoYW5nZSk7XG5cbiAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBhbGwubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVsZSA9IGFsbFtpXTtcblxuICAgICAgICAgICAgICAgIGlmIChwLmNhblNldChlbGUpKSB7XG4gICAgICAgICAgICAgICAgICBpZiAocGF0aCAmJiBzaW5nbGUuX3ByaXZhdGVbcC5maWVsZF1bbmFtZV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICBzZXRfMShlbGUuX3ByaXZhdGVbcC5maWVsZF0sIHBhdGgsIHZhbHVlKTtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGVsZS5fcHJpdmF0ZVtwLmZpZWxkXVtuYW1lXSA9IHZhbHVlO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSAvLyB1cGRhdGUgbWFwcGVycyBpZiBhc2tlZFxuXG5cbiAgICAgICAgICAgICAgaWYgKHAudXBkYXRlU3R5bGUpIHtcbiAgICAgICAgICAgICAgICBzZWxmLnVwZGF0ZVN0eWxlKCk7XG4gICAgICAgICAgICAgIH0gLy8gY2FsbCBvblNldCBjYWxsYmFja1xuXG5cbiAgICAgICAgICAgICAgcC5vblNldChzZWxmKTtcblxuICAgICAgICAgICAgICBpZiAocC5zZXR0aW5nVHJpZ2dlcnNFdmVudCkge1xuICAgICAgICAgICAgICAgIHNlbGZbcC50cmlnZ2VyRm5OYW1lXShwLnNldHRpbmdFdmVudCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIC5kYXRhKHsgJ2Zvbyc6ICdiYXInIH0pXG5cbiAgICAgICAgfSBlbHNlIGlmIChwLmFsbG93U2V0dGluZyAmJiBwbGFpbk9iamVjdChuYW1lKSkge1xuICAgICAgICAgIC8vIGV4dGVuZFxuICAgICAgICAgIHZhciBvYmogPSBuYW1lO1xuICAgICAgICAgIHZhciBrLCB2O1xuICAgICAgICAgIHZhciBrZXlzID0gT2JqZWN0LmtleXMob2JqKTtcbiAgICAgICAgICBwLmJlZm9yZVNldChzZWxmLCBvYmopO1xuXG4gICAgICAgICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IGtleXMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICBrID0ga2V5c1tfaV07XG4gICAgICAgICAgICB2ID0gb2JqW2tdO1xuXG4gICAgICAgICAgICB2YXIgX3ZhbGlkID0gIXAuaW1tdXRhYmxlS2V5c1trXTtcblxuICAgICAgICAgICAgaWYgKF92YWxpZCkge1xuICAgICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGFsbC5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIHZhciBfZWxlID0gYWxsW2pdO1xuXG4gICAgICAgICAgICAgICAgaWYgKHAuY2FuU2V0KF9lbGUpKSB7XG4gICAgICAgICAgICAgICAgICBfZWxlLl9wcml2YXRlW3AuZmllbGRdW2tdID0gdjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIHVwZGF0ZSBtYXBwZXJzIGlmIGFza2VkXG5cblxuICAgICAgICAgIGlmIChwLnVwZGF0ZVN0eWxlKSB7XG4gICAgICAgICAgICBzZWxmLnVwZGF0ZVN0eWxlKCk7XG4gICAgICAgICAgfSAvLyBjYWxsIG9uU2V0IGNhbGxiYWNrXG5cblxuICAgICAgICAgIHAub25TZXQoc2VsZik7XG5cbiAgICAgICAgICBpZiAocC5zZXR0aW5nVHJpZ2dlcnNFdmVudCkge1xuICAgICAgICAgICAgc2VsZltwLnRyaWdnZXJGbk5hbWVdKHAuc2V0dGluZ0V2ZW50KTtcbiAgICAgICAgICB9IC8vIC5kYXRhKGZ1bmN0aW9uKCl7IC4uLiB9KVxuXG4gICAgICAgIH0gZWxzZSBpZiAocC5hbGxvd0JpbmRpbmcgJiYgZm4kNihuYW1lKSkge1xuICAgICAgICAgIC8vIGJpbmQgdG8gZXZlbnRcbiAgICAgICAgICB2YXIgZm4gPSBuYW1lO1xuICAgICAgICAgIHNlbGYub24ocC5iaW5kaW5nRXZlbnQsIGZuKTsgLy8gLmRhdGEoKVxuICAgICAgICB9IGVsc2UgaWYgKHAuYWxsb3dHZXR0aW5nICYmIG5hbWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIC8vIGdldCB3aG9sZSBvYmplY3RcbiAgICAgICAgICB2YXIgX3JldDtcblxuICAgICAgICAgIGlmIChzaW5nbGUpIHtcbiAgICAgICAgICAgIHAuYmVmb3JlR2V0KHNpbmdsZSk7XG4gICAgICAgICAgICBfcmV0ID0gc2luZ2xlLl9wcml2YXRlW3AuZmllbGRdO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBfcmV0O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHNlbGY7IC8vIG1haW50YWluIGNoYWluYWJpbGl0eVxuICAgICAgfTsgLy8gZnVuY3Rpb25cbiAgICB9LFxuICAgIC8vIGRhdGFcbiAgICAvLyByZW1vdmUgZGF0YSBmaWVsZFxuICAgIHJlbW92ZURhdGE6IGZ1bmN0aW9uIHJlbW92ZURhdGEocGFyYW1zKSB7XG4gICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIGZpZWxkOiAnZGF0YScsXG4gICAgICAgIGV2ZW50OiAnZGF0YScsXG4gICAgICAgIHRyaWdnZXJGbk5hbWU6ICd0cmlnZ2VyJyxcbiAgICAgICAgdHJpZ2dlckV2ZW50OiBmYWxzZSxcbiAgICAgICAgaW1tdXRhYmxlS2V5czoge30gLy8ga2V5ID0+IHRydWUgaWYgaW1tdXRhYmxlXG5cbiAgICAgIH07XG4gICAgICBwYXJhbXMgPSBleHRlbmQoe30sIGRlZmF1bHRzLCBwYXJhbXMpO1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uIHJlbW92ZURhdGFJbXBsKG5hbWVzKSB7XG4gICAgICAgIHZhciBwID0gcGFyYW1zO1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHZhciBzZWxmSXNBcnJheUxpa2UgPSBzZWxmLmxlbmd0aCAhPT0gdW5kZWZpbmVkO1xuICAgICAgICB2YXIgYWxsID0gc2VsZklzQXJyYXlMaWtlID8gc2VsZiA6IFtzZWxmXTsgLy8gcHV0IGluIGFycmF5IGlmIG5vdCBhcnJheS1saWtlXG4gICAgICAgIC8vIC5yZW1vdmVEYXRhKCdmb28gYmFyJylcblxuICAgICAgICBpZiAoc3RyaW5nKG5hbWVzKSkge1xuICAgICAgICAgIC8vIHRoZW4gZ2V0IHRoZSBsaXN0IG9mIGtleXMsIGFuZCBkZWxldGUgdGhlbVxuICAgICAgICAgIHZhciBrZXlzID0gbmFtZXMuc3BsaXQoL1xccysvKTtcbiAgICAgICAgICB2YXIgbCA9IGtleXMubGVuZ3RoO1xuXG4gICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgIC8vIGRlbGV0ZSBlYWNoIG5vbi1lbXB0eSBrZXlcbiAgICAgICAgICAgIHZhciBrZXkgPSBrZXlzW2ldO1xuXG4gICAgICAgICAgICBpZiAoZW1wdHlTdHJpbmcoa2V5KSkge1xuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHZhbGlkID0gIXAuaW1tdXRhYmxlS2V5c1trZXldOyAvLyBub3QgdmFsaWQgaWYgaW1tdXRhYmxlXG5cbiAgICAgICAgICAgIGlmICh2YWxpZCkge1xuICAgICAgICAgICAgICBmb3IgKHZhciBpX2EgPSAwLCBsX2EgPSBhbGwubGVuZ3RoOyBpX2EgPCBsX2E7IGlfYSsrKSB7XG4gICAgICAgICAgICAgICAgYWxsW2lfYV0uX3ByaXZhdGVbcC5maWVsZF1ba2V5XSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChwLnRyaWdnZXJFdmVudCkge1xuICAgICAgICAgICAgc2VsZltwLnRyaWdnZXJGbk5hbWVdKHAuZXZlbnQpO1xuICAgICAgICAgIH0gLy8gLnJlbW92ZURhdGEoKVxuXG4gICAgICAgIH0gZWxzZSBpZiAobmFtZXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIC8vIHRoZW4gZGVsZXRlIGFsbCBrZXlzXG4gICAgICAgICAgZm9yICh2YXIgX2lfYSA9IDAsIF9sX2EgPSBhbGwubGVuZ3RoOyBfaV9hIDwgX2xfYTsgX2lfYSsrKSB7XG4gICAgICAgICAgICB2YXIgX3ByaXZhdGVGaWVsZHMgPSBhbGxbX2lfYV0uX3ByaXZhdGVbcC5maWVsZF07XG5cbiAgICAgICAgICAgIHZhciBfa2V5cyA9IE9iamVjdC5rZXlzKF9wcml2YXRlRmllbGRzKTtcblxuICAgICAgICAgICAgZm9yICh2YXIgX2kyID0gMDsgX2kyIDwgX2tleXMubGVuZ3RoOyBfaTIrKykge1xuICAgICAgICAgICAgICB2YXIgX2tleSA9IF9rZXlzW19pMl07XG4gICAgICAgICAgICAgIHZhciB2YWxpZEtleVRvRGVsZXRlID0gIXAuaW1tdXRhYmxlS2V5c1tfa2V5XTtcblxuICAgICAgICAgICAgICBpZiAodmFsaWRLZXlUb0RlbGV0ZSkge1xuICAgICAgICAgICAgICAgIF9wcml2YXRlRmllbGRzW19rZXldID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHAudHJpZ2dlckV2ZW50KSB7XG4gICAgICAgICAgICBzZWxmW3AudHJpZ2dlckZuTmFtZV0ocC5ldmVudCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHNlbGY7IC8vIG1haW50YWluIGNoYWluaW5nXG4gICAgICB9OyAvLyBmdW5jdGlvblxuICAgIH0gLy8gcmVtb3ZlRGF0YVxuXG4gIH07IC8vIGRlZmluZVxuXG4gIHZhciBkZWZpbmUkMSA9IHtcbiAgICBldmVudEFsaWFzZXNPbjogZnVuY3Rpb24gZXZlbnRBbGlhc2VzT24ocHJvdG8pIHtcbiAgICAgIHZhciBwID0gcHJvdG87XG4gICAgICBwLmFkZExpc3RlbmVyID0gcC5saXN0ZW4gPSBwLmJpbmQgPSBwLm9uO1xuICAgICAgcC51bmxpc3RlbiA9IHAudW5iaW5kID0gcC5vZmYgPSBwLnJlbW92ZUxpc3RlbmVyO1xuICAgICAgcC50cmlnZ2VyID0gcC5lbWl0OyAvLyB0aGlzIGlzIGp1c3QgYSB3cmFwcGVyIGFsaWFzIG9mIC5vbigpXG5cbiAgICAgIHAucG9uID0gcC5wcm9taXNlT24gPSBmdW5jdGlvbiAoZXZlbnRzLCBzZWxlY3Rvcikge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlJDEoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICAgIHZhciBjYWxsYmFjayA9IGZ1bmN0aW9uIGNhbGxiYWNrKGUpIHtcbiAgICAgICAgICAgIHNlbGYub2ZmLmFwcGx5KHNlbGYsIG9mZkFyZ3MpO1xuICAgICAgICAgICAgcmVzb2x2ZShlKTtcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgdmFyIG9uQXJncyA9IGFyZ3MuY29uY2F0KFtjYWxsYmFja10pO1xuICAgICAgICAgIHZhciBvZmZBcmdzID0gb25BcmdzLmNvbmNhdChbXSk7XG4gICAgICAgICAgc2VsZi5vbi5hcHBseShzZWxmLCBvbkFyZ3MpO1xuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgfVxuICB9OyAvLyBkZWZpbmVcblxuICAvLyB1c2UgdGhpcyBtb2R1bGUgdG8gY2hlcnJ5IHBpY2sgZnVuY3Rpb25zIGludG8geW91ciBwcm90b3R5cGVcbiAgdmFyIGRlZmluZSA9IHt9O1xuICBbZGVmaW5lJDMsIGRlZmluZSQyLCBkZWZpbmUkMV0uZm9yRWFjaChmdW5jdGlvbiAobSkge1xuICAgIGV4dGVuZChkZWZpbmUsIG0pO1xuICB9KTtcblxuICB2YXIgZWxlc2ZuJGkgPSB7XG4gICAgYW5pbWF0ZTogZGVmaW5lLmFuaW1hdGUoKSxcbiAgICBhbmltYXRpb246IGRlZmluZS5hbmltYXRpb24oKSxcbiAgICBhbmltYXRlZDogZGVmaW5lLmFuaW1hdGVkKCksXG4gICAgY2xlYXJRdWV1ZTogZGVmaW5lLmNsZWFyUXVldWUoKSxcbiAgICBkZWxheTogZGVmaW5lLmRlbGF5KCksXG4gICAgZGVsYXlBbmltYXRpb246IGRlZmluZS5kZWxheUFuaW1hdGlvbigpLFxuICAgIHN0b3A6IGRlZmluZS5zdG9wKClcbiAgfTtcblxuICB2YXIgZWxlc2ZuJGggPSB7XG4gICAgY2xhc3NlczogZnVuY3Rpb24gY2xhc3NlcyhfY2xhc3Nlcykge1xuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICBpZiAoX2NsYXNzZXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB2YXIgcmV0ID0gW107XG5cbiAgICAgICAgc2VsZlswXS5fcHJpdmF0ZS5jbGFzc2VzLmZvckVhY2goZnVuY3Rpb24gKGNscykge1xuICAgICAgICAgIHJldHVybiByZXQucHVzaChjbHMpO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gcmV0O1xuICAgICAgfSBlbHNlIGlmICghYXJyYXkoX2NsYXNzZXMpKSB7XG4gICAgICAgIC8vIGV4dHJhY3QgY2xhc3NlcyBmcm9tIHN0cmluZ1xuICAgICAgICBfY2xhc3NlcyA9IChfY2xhc3NlcyB8fCAnJykubWF0Y2goL1xcUysvZykgfHwgW107XG4gICAgICB9XG5cbiAgICAgIHZhciBjaGFuZ2VkID0gW107XG4gICAgICB2YXIgY2xhc3Nlc1NldCA9IG5ldyBTZXQkMShfY2xhc3Nlcyk7IC8vIGNoZWNrIGFuZCB1cGRhdGUgZWFjaCBlbGVcblxuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBzZWxmLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHZhciBlbGUgPSBzZWxmW2pdO1xuICAgICAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG4gICAgICAgIHZhciBlbGVDbGFzc2VzID0gX3AuY2xhc3NlcztcbiAgICAgICAgdmFyIGNoYW5nZWRFbGUgPSBmYWxzZTsgLy8gY2hlY2sgaWYgZWxlIGhhcyBhbGwgb2YgdGhlIHBhc3NlZCBjbGFzc2VzXG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBfY2xhc3Nlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBjbHMgPSBfY2xhc3Nlc1tpXTtcbiAgICAgICAgICB2YXIgZWxlSGFzQ2xhc3MgPSBlbGVDbGFzc2VzLmhhcyhjbHMpO1xuXG4gICAgICAgICAgaWYgKCFlbGVIYXNDbGFzcykge1xuICAgICAgICAgICAgY2hhbmdlZEVsZSA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH0gLy8gY2hlY2sgaWYgZWxlIGhhcyBjbGFzc2VzIG91dHNpZGUgb2YgdGhvc2UgcGFzc2VkXG5cblxuICAgICAgICBpZiAoIWNoYW5nZWRFbGUpIHtcbiAgICAgICAgICBjaGFuZ2VkRWxlID0gZWxlQ2xhc3Nlcy5zaXplICE9PSBfY2xhc3Nlcy5sZW5ndGg7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2hhbmdlZEVsZSkge1xuICAgICAgICAgIF9wLmNsYXNzZXMgPSBjbGFzc2VzU2V0O1xuICAgICAgICAgIGNoYW5nZWQucHVzaChlbGUpO1xuICAgICAgICB9XG4gICAgICB9IC8vIHRyaWdnZXIgdXBkYXRlIHN0eWxlIG9uIHRob3NlIGVsZXMgdGhhdCBoYWQgY2xhc3MgY2hhbmdlc1xuXG5cbiAgICAgIGlmIChjaGFuZ2VkLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGhpcy5zcGF3bihjaGFuZ2VkKS51cGRhdGVTdHlsZSgpLmVtaXQoJ2NsYXNzJyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzZWxmO1xuICAgIH0sXG4gICAgYWRkQ2xhc3M6IGZ1bmN0aW9uIGFkZENsYXNzKGNsYXNzZXMpIHtcbiAgICAgIHJldHVybiB0aGlzLnRvZ2dsZUNsYXNzKGNsYXNzZXMsIHRydWUpO1xuICAgIH0sXG4gICAgaGFzQ2xhc3M6IGZ1bmN0aW9uIGhhc0NsYXNzKGNsYXNzTmFtZSkge1xuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG4gICAgICByZXR1cm4gZWxlICE9IG51bGwgJiYgZWxlLl9wcml2YXRlLmNsYXNzZXMuaGFzKGNsYXNzTmFtZSk7XG4gICAgfSxcbiAgICB0b2dnbGVDbGFzczogZnVuY3Rpb24gdG9nZ2xlQ2xhc3MoY2xhc3NlcywgdG9nZ2xlKSB7XG4gICAgICBpZiAoIWFycmF5KGNsYXNzZXMpKSB7XG4gICAgICAgIC8vIGV4dHJhY3QgY2xhc3NlcyBmcm9tIHN0cmluZ1xuICAgICAgICBjbGFzc2VzID0gY2xhc3Nlcy5tYXRjaCgvXFxTKy9nKSB8fCBbXTtcbiAgICAgIH1cblxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgdmFyIHRvZ2dsZVVuZGVmZCA9IHRvZ2dsZSA9PT0gdW5kZWZpbmVkO1xuICAgICAgdmFyIGNoYW5nZWQgPSBbXTsgLy8gZWxlcyB3aG8gaGFkIGNsYXNzZXMgY2hhbmdlZFxuXG4gICAgICBmb3IgKHZhciBpID0gMCwgaWwgPSBzZWxmLmxlbmd0aDsgaSA8IGlsOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IHNlbGZbaV07XG4gICAgICAgIHZhciBlbGVDbGFzc2VzID0gZWxlLl9wcml2YXRlLmNsYXNzZXM7XG4gICAgICAgIHZhciBjaGFuZ2VkRWxlID0gZmFsc2U7XG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBjbGFzc2VzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgdmFyIGNscyA9IGNsYXNzZXNbal07XG4gICAgICAgICAgdmFyIGhhc0NsYXNzID0gZWxlQ2xhc3Nlcy5oYXMoY2xzKTtcbiAgICAgICAgICB2YXIgY2hhbmdlZE5vdyA9IGZhbHNlO1xuXG4gICAgICAgICAgaWYgKHRvZ2dsZSB8fCB0b2dnbGVVbmRlZmQgJiYgIWhhc0NsYXNzKSB7XG4gICAgICAgICAgICBlbGVDbGFzc2VzLmFkZChjbHMpO1xuICAgICAgICAgICAgY2hhbmdlZE5vdyA9IHRydWU7XG4gICAgICAgICAgfSBlbHNlIGlmICghdG9nZ2xlIHx8IHRvZ2dsZVVuZGVmZCAmJiBoYXNDbGFzcykge1xuICAgICAgICAgICAgZWxlQ2xhc3Nlc1tcImRlbGV0ZVwiXShjbHMpO1xuICAgICAgICAgICAgY2hhbmdlZE5vdyA9IHRydWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFjaGFuZ2VkRWxlICYmIGNoYW5nZWROb3cpIHtcbiAgICAgICAgICAgIGNoYW5nZWQucHVzaChlbGUpO1xuICAgICAgICAgICAgY2hhbmdlZEVsZSA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9IC8vIGZvciBqIGNsYXNzZXNcblxuICAgICAgfSAvLyBmb3IgaSBlbGVzXG4gICAgICAvLyB0cmlnZ2VyIHVwZGF0ZSBzdHlsZSBvbiB0aG9zZSBlbGVzIHRoYXQgaGFkIGNsYXNzIGNoYW5nZXNcblxuXG4gICAgICBpZiAoY2hhbmdlZC5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuc3Bhd24oY2hhbmdlZCkudXBkYXRlU3R5bGUoKS5lbWl0KCdjbGFzcycpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gc2VsZjtcbiAgICB9LFxuICAgIHJlbW92ZUNsYXNzOiBmdW5jdGlvbiByZW1vdmVDbGFzcyhjbGFzc2VzKSB7XG4gICAgICByZXR1cm4gdGhpcy50b2dnbGVDbGFzcyhjbGFzc2VzLCBmYWxzZSk7XG4gICAgfSxcbiAgICBmbGFzaENsYXNzOiBmdW5jdGlvbiBmbGFzaENsYXNzKGNsYXNzZXMsIGR1cmF0aW9uKSB7XG4gICAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAgIGlmIChkdXJhdGlvbiA9PSBudWxsKSB7XG4gICAgICAgIGR1cmF0aW9uID0gMjUwO1xuICAgICAgfSBlbHNlIGlmIChkdXJhdGlvbiA9PT0gMCkge1xuICAgICAgICByZXR1cm4gc2VsZjsgLy8gbm90aGluZyB0byBkbyByZWFsbHlcbiAgICAgIH1cblxuICAgICAgc2VsZi5hZGRDbGFzcyhjbGFzc2VzKTtcbiAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICBzZWxmLnJlbW92ZUNsYXNzKGNsYXNzZXMpO1xuICAgICAgfSwgZHVyYXRpb24pO1xuICAgICAgcmV0dXJuIHNlbGY7XG4gICAgfVxuICB9O1xuICBlbGVzZm4kaC5jbGFzc05hbWUgPSBlbGVzZm4kaC5jbGFzc05hbWVzID0gZWxlc2ZuJGguY2xhc3NlcztcblxuICB2YXIgdG9rZW5zID0ge1xuICAgIG1ldGFDaGFyOiAnW1xcXFwhXFxcXFwiXFxcXCNcXFxcJFxcXFwlXFxcXCZcXFxcXFwnXFxcXChcXFxcKVxcXFwqXFxcXCtcXFxcLFxcXFwuXFxcXC9cXFxcOlxcXFw7XFxcXDxcXFxcPVxcXFw+XFxcXD9cXFxcQFxcXFxbXFxcXF1cXFxcXlxcXFxgXFxcXHtcXFxcfFxcXFx9XFxcXH5dJyxcbiAgICAvLyBjaGFycyB3ZSBuZWVkIHRvIGVzY2FwZSBpbiBsZXQgbmFtZXMsIGV0Y1xuICAgIGNvbXBhcmF0b3JPcDogJz18XFxcXCE9fD58Pj18PHw8PXxcXFxcJD18XFxcXF49fFxcXFwqPScsXG4gICAgLy8gYmluYXJ5IGNvbXBhcmlzb24gb3AgKHVzZWQgaW4gZGF0YSBzZWxlY3RvcnMpXG4gICAgYm9vbE9wOiAnXFxcXD98XFxcXCF8XFxcXF4nLFxuICAgIC8vIGJvb2xlYW4gKHVuYXJ5KSBvcGVyYXRvcnMgKHVzZWQgaW4gZGF0YSBzZWxlY3RvcnMpXG4gICAgc3RyaW5nOiAnXCIoPzpcXFxcXFxcXFwifFteXCJdKSpcIicgKyAnfCcgKyBcIicoPzpcXFxcXFxcXCd8W14nXSkqJ1wiLFxuICAgIC8vIHN0cmluZyBsaXRlcmFscyAodXNlZCBpbiBkYXRhIHNlbGVjdG9ycykgLS0gZG91YmxlcXVvdGVzIHwgc2luZ2xlcXVvdGVzXG4gICAgbnVtYmVyOiBudW1iZXIsXG4gICAgLy8gbnVtYmVyIGxpdGVyYWwgKHVzZWQgaW4gZGF0YSBzZWxlY3RvcnMpIC0tLSBlLmcuIDAuMTIzNCwgMTIzNCwgMTJlMTIzXG4gICAgbWV0YTogJ2RlZ3JlZXxpbmRlZ3JlZXxvdXRkZWdyZWUnLFxuICAgIC8vIGFsbG93ZWQgbWV0YWRhdGEgZmllbGRzIChpLmUuIGFsbG93ZWQgZnVuY3Rpb25zIHRvIHVzZSBmcm9tIENvbGxlY3Rpb24pXG4gICAgc2VwYXJhdG9yOiAnXFxcXHMqLFxcXFxzKicsXG4gICAgLy8gcXVlcmllcyBhcmUgc2VwYXJhdGVkIGJ5IGNvbW1hcywgZS5nLiBlZGdlW2ZvbyA9ICdiYXInXSwgbm9kZS5zb21lQ2xhc3NcbiAgICBkZXNjZW5kYW50OiAnXFxcXHMrJyxcbiAgICBjaGlsZDogJ1xcXFxzKz5cXFxccysnLFxuICAgIHN1YmplY3Q6ICdcXFxcJCcsXG4gICAgZ3JvdXA6ICdub2RlfGVkZ2V8XFxcXConLFxuICAgIGRpcmVjdGVkRWRnZTogJ1xcXFxzKy0+XFxcXHMrJyxcbiAgICB1bmRpcmVjdGVkRWRnZTogJ1xcXFxzKzwtPlxcXFxzKydcbiAgfTtcbiAgdG9rZW5zLnZhcmlhYmxlID0gJyg/OltcXFxcdy0uXXwoPzpcXFxcXFxcXCcgKyB0b2tlbnMubWV0YUNoYXIgKyAnKSkrJzsgLy8gYSB2YXJpYWJsZSBuYW1lIGNhbiBoYXZlIGxldHRlcnMsIG51bWJlcnMsIGRhc2hlcywgYW5kIHBlcmlvZHNcblxuICB0b2tlbnMuY2xhc3NOYW1lID0gJyg/OltcXFxcdy1dfCg/OlxcXFxcXFxcJyArIHRva2Vucy5tZXRhQ2hhciArICcpKSsnOyAvLyBhIGNsYXNzIG5hbWUgaGFzIHRoZSBzYW1lIHJ1bGVzIGFzIGEgdmFyaWFibGUgZXhjZXB0IGl0IGNhbid0IGhhdmUgYSAnLicgaW4gdGhlIG5hbWVcblxuICB0b2tlbnMudmFsdWUgPSB0b2tlbnMuc3RyaW5nICsgJ3wnICsgdG9rZW5zLm51bWJlcjsgLy8gYSB2YWx1ZSBsaXRlcmFsLCBlaXRoZXIgYSBzdHJpbmcgb3IgbnVtYmVyXG5cbiAgdG9rZW5zLmlkID0gdG9rZW5zLnZhcmlhYmxlOyAvLyBhbiBlbGVtZW50IGlkIChmb2xsb3dzIHZhcmlhYmxlIGNvbnZlbnRpb25zKVxuXG4gIChmdW5jdGlvbiAoKSB7XG4gICAgdmFyIG9wcywgb3AsIGk7IC8vIGFkZCBAIHZhcmlhbnRzIHRvIGNvbXBhcmF0b3JPcFxuXG4gICAgb3BzID0gdG9rZW5zLmNvbXBhcmF0b3JPcC5zcGxpdCgnfCcpO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IG9wcy5sZW5ndGg7IGkrKykge1xuICAgICAgb3AgPSBvcHNbaV07XG4gICAgICB0b2tlbnMuY29tcGFyYXRvck9wICs9ICd8QCcgKyBvcDtcbiAgICB9IC8vIGFkZCAhIHZhcmlhbnRzIHRvIGNvbXBhcmF0b3JPcFxuXG5cbiAgICBvcHMgPSB0b2tlbnMuY29tcGFyYXRvck9wLnNwbGl0KCd8Jyk7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBvcCA9IG9wc1tpXTtcblxuICAgICAgaWYgKG9wLmluZGV4T2YoJyEnKSA+PSAwKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfSAvLyBza2lwIG9wcyB0aGF0IGV4cGxpY2l0bHkgY29udGFpbiAhXG5cblxuICAgICAgaWYgKG9wID09PSAnPScpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9IC8vIHNraXAgPSBiL2MgIT0gaXMgZXhwbGljaXRseSBkZWZpbmVkXG5cblxuICAgICAgdG9rZW5zLmNvbXBhcmF0b3JPcCArPSAnfFxcXFwhJyArIG9wO1xuICAgIH1cbiAgfSkoKTtcblxuICAvKipcbiAgICogTWFrZSBhIG5ldyBxdWVyeSBvYmplY3RcbiAgICpcbiAgICogQHByb3AgdHlwZSB7VHlwZX0gVGhlIHR5cGUgZW51bSAoaW50KSBvZiB0aGUgcXVlcnlcbiAgICogQHByb3AgY2hlY2tzIExpc3Qgb2YgY2hlY2tzIHRvIG1ha2UgYWdhaW5zdCBhbiBlbGUgdG8gdGVzdCBmb3IgYSBtYXRjaFxuICAgKi9cbiAgdmFyIG5ld1F1ZXJ5ID0gZnVuY3Rpb24gbmV3UXVlcnkoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNoZWNrczogW11cbiAgICB9O1xuICB9O1xuXG4gIC8qKlxuICAgKiBBIGNoZWNrIHR5cGUgZW51bS1saWtlIG9iamVjdC4gIFVzZXMgaW50ZWdlciB2YWx1ZXMgZm9yIGZhc3QgbWF0Y2goKSBsb29rdXAuXG4gICAqIFRoZSBvcmRlcmluZyBkb2VzIG5vdCBtYXR0ZXIgYXMgbG9uZyBhcyB0aGUgaW50cyBhcmUgdW5pcXVlLlxuICAgKi9cbiAgdmFyIFR5cGUgPSB7XG4gICAgLyoqIEUuZy4gbm9kZSAqL1xuICAgIEdST1VQOiAwLFxuXG4gICAgLyoqIEEgY29sbGVjdGlvbiBvZiBlbGVtZW50cyAqL1xuICAgIENPTExFQ1RJT046IDEsXG5cbiAgICAvKiogQSBmaWx0ZXIoZWxlKSBmdW5jdGlvbiAqL1xuICAgIEZJTFRFUjogMixcblxuICAgIC8qKiBFLmcuIFtmb28gPiAxXSAqL1xuICAgIERBVEFfQ09NUEFSRTogMyxcblxuICAgIC8qKiBFLmcuIFtmb29dICovXG4gICAgREFUQV9FWElTVDogNCxcblxuICAgIC8qKiBFLmcuIFs/Zm9vXSAqL1xuICAgIERBVEFfQk9PTDogNSxcblxuICAgIC8qKiBFLmcuIFtbZGVncmVlID4gMl1dICovXG4gICAgTUVUQV9DT01QQVJFOiA2LFxuXG4gICAgLyoqIEUuZy4gOnNlbGVjdGVkICovXG4gICAgU1RBVEU6IDcsXG5cbiAgICAvKiogRS5nLiAjZm9vICovXG4gICAgSUQ6IDgsXG5cbiAgICAvKiogRS5nLiAuZm9vICovXG4gICAgQ0xBU1M6IDksXG5cbiAgICAvKiogRS5nLiAjZm9vIDwtPiAjYmFyICovXG4gICAgVU5ESVJFQ1RFRF9FREdFOiAxMCxcblxuICAgIC8qKiBFLmcuICNmb28gLT4gI2JhciAqL1xuICAgIERJUkVDVEVEX0VER0U6IDExLFxuXG4gICAgLyoqIEUuZy4gJCNmb28gLT4gI2JhciAqL1xuICAgIE5PREVfU09VUkNFOiAxMixcblxuICAgIC8qKiBFLmcuICNmb28gLT4gJCNiYXIgKi9cbiAgICBOT0RFX1RBUkdFVDogMTMsXG5cbiAgICAvKiogRS5nLiAkI2ZvbyA8LT4gI2JhciAqL1xuICAgIE5PREVfTkVJR0hCT1I6IDE0LFxuXG4gICAgLyoqIEUuZy4gI2ZvbyA+ICNiYXIgKi9cbiAgICBDSElMRDogMTUsXG5cbiAgICAvKiogRS5nLiAjZm9vICNiYXIgKi9cbiAgICBERVNDRU5EQU5UOiAxNixcblxuICAgIC8qKiBFLmcuICQjZm9vID4gI2JhciAqL1xuICAgIFBBUkVOVDogMTcsXG5cbiAgICAvKiogRS5nLiAkI2ZvbyAjYmFyICovXG4gICAgQU5DRVNUT1I6IDE4LFxuXG4gICAgLyoqIEUuZy4gI2ZvbyA+ICRiYXIgPiAjYmF6ICovXG4gICAgQ09NUE9VTkRfU1BMSVQ6IDE5LFxuXG4gICAgLyoqIEFsd2F5cyBtYXRjaGVzLCB1c2VmdWwgcGxhY2Vob2xkZXIgZm9yIHN1YmplY3QgaW4gYENPTVBPVU5EX1NQTElUYCAqL1xuICAgIFRSVUU6IDIwXG4gIH07XG5cbiAgdmFyIHN0YXRlU2VsZWN0b3JzID0gW3tcbiAgICBzZWxlY3RvcjogJzpzZWxlY3RlZCcsXG4gICAgbWF0Y2hlczogZnVuY3Rpb24gbWF0Y2hlcyhlbGUpIHtcbiAgICAgIHJldHVybiBlbGUuc2VsZWN0ZWQoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzp1bnNlbGVjdGVkJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuICFlbGUuc2VsZWN0ZWQoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzpzZWxlY3RhYmxlJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS5zZWxlY3RhYmxlKCk7XG4gICAgfVxuICB9LCB7XG4gICAgc2VsZWN0b3I6ICc6dW5zZWxlY3RhYmxlJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuICFlbGUuc2VsZWN0YWJsZSgpO1xuICAgIH1cbiAgfSwge1xuICAgIHNlbGVjdG9yOiAnOmxvY2tlZCcsXG4gICAgbWF0Y2hlczogZnVuY3Rpb24gbWF0Y2hlcyhlbGUpIHtcbiAgICAgIHJldHVybiBlbGUubG9ja2VkKCk7XG4gICAgfVxuICB9LCB7XG4gICAgc2VsZWN0b3I6ICc6dW5sb2NrZWQnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gIWVsZS5sb2NrZWQoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzp2aXNpYmxlJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS52aXNpYmxlKCk7XG4gICAgfVxuICB9LCB7XG4gICAgc2VsZWN0b3I6ICc6aGlkZGVuJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuICFlbGUudmlzaWJsZSgpO1xuICAgIH1cbiAgfSwge1xuICAgIHNlbGVjdG9yOiAnOnRyYW5zcGFyZW50JyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS50cmFuc3BhcmVudCgpO1xuICAgIH1cbiAgfSwge1xuICAgIHNlbGVjdG9yOiAnOmdyYWJiZWQnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLmdyYWJiZWQoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzpmcmVlJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuICFlbGUuZ3JhYmJlZCgpO1xuICAgIH1cbiAgfSwge1xuICAgIHNlbGVjdG9yOiAnOnJlbW92ZWQnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLnJlbW92ZWQoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzppbnNpZGUnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gIWVsZS5yZW1vdmVkKCk7XG4gICAgfVxuICB9LCB7XG4gICAgc2VsZWN0b3I6ICc6Z3JhYmJhYmxlJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS5ncmFiYmFibGUoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzp1bmdyYWJiYWJsZScsXG4gICAgbWF0Y2hlczogZnVuY3Rpb24gbWF0Y2hlcyhlbGUpIHtcbiAgICAgIHJldHVybiAhZWxlLmdyYWJiYWJsZSgpO1xuICAgIH1cbiAgfSwge1xuICAgIHNlbGVjdG9yOiAnOmFuaW1hdGVkJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS5hbmltYXRlZCgpO1xuICAgIH1cbiAgfSwge1xuICAgIHNlbGVjdG9yOiAnOnVuYW5pbWF0ZWQnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gIWVsZS5hbmltYXRlZCgpO1xuICAgIH1cbiAgfSwge1xuICAgIHNlbGVjdG9yOiAnOnBhcmVudCcsXG4gICAgbWF0Y2hlczogZnVuY3Rpb24gbWF0Y2hlcyhlbGUpIHtcbiAgICAgIHJldHVybiBlbGUuaXNQYXJlbnQoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzpjaGlsZGxlc3MnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLmlzQ2hpbGRsZXNzKCk7XG4gICAgfVxuICB9LCB7XG4gICAgc2VsZWN0b3I6ICc6Y2hpbGQnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLmlzQ2hpbGQoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzpvcnBoYW4nLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLmlzT3JwaGFuKCk7XG4gICAgfVxuICB9LCB7XG4gICAgc2VsZWN0b3I6ICc6bm9ub3JwaGFuJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS5pc0NoaWxkKCk7XG4gICAgfVxuICB9LCB7XG4gICAgc2VsZWN0b3I6ICc6Y29tcG91bmQnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICBpZiAoZWxlLmlzTm9kZSgpKSB7XG4gICAgICAgIHJldHVybiBlbGUuaXNQYXJlbnQoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBlbGUuc291cmNlKCkuaXNQYXJlbnQoKSB8fCBlbGUudGFyZ2V0KCkuaXNQYXJlbnQoKTtcbiAgICAgIH1cbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzpsb29wJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS5pc0xvb3AoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzpzaW1wbGUnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLmlzU2ltcGxlKCk7XG4gICAgfVxuICB9LCB7XG4gICAgc2VsZWN0b3I6ICc6YWN0aXZlJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS5hY3RpdmUoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzppbmFjdGl2ZScsXG4gICAgbWF0Y2hlczogZnVuY3Rpb24gbWF0Y2hlcyhlbGUpIHtcbiAgICAgIHJldHVybiAhZWxlLmFjdGl2ZSgpO1xuICAgIH1cbiAgfSwge1xuICAgIHNlbGVjdG9yOiAnOmJhY2tncm91bmRpbmcnLFxuICAgIG1hdGNoZXM6IGZ1bmN0aW9uIG1hdGNoZXMoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLmJhY2tncm91bmRpbmcoKTtcbiAgICB9XG4gIH0sIHtcbiAgICBzZWxlY3RvcjogJzpub25iYWNrZ3JvdW5kaW5nJyxcbiAgICBtYXRjaGVzOiBmdW5jdGlvbiBtYXRjaGVzKGVsZSkge1xuICAgICAgcmV0dXJuICFlbGUuYmFja2dyb3VuZGluZygpO1xuICAgIH1cbiAgfV0uc29ydChmdW5jdGlvbiAoYSwgYikge1xuICAgIC8vIG4uYi4gc2VsZWN0b3JzIHRoYXQgYXJlIHN0YXJ0aW5nIHN1YnN0cmluZ3Mgb2Ygb3RoZXJzIG11c3QgaGF2ZSB0aGUgbG9uZ2VyIG9uZXMgZmlyc3RcbiAgICByZXR1cm4gZGVzY2VuZGluZyhhLnNlbGVjdG9yLCBiLnNlbGVjdG9yKTtcbiAgfSk7XG5cbiAgdmFyIGxvb2t1cCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2VsVG9GbiA9IHt9O1xuICAgIHZhciBzO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdGF0ZVNlbGVjdG9ycy5sZW5ndGg7IGkrKykge1xuICAgICAgcyA9IHN0YXRlU2VsZWN0b3JzW2ldO1xuICAgICAgc2VsVG9GbltzLnNlbGVjdG9yXSA9IHMubWF0Y2hlcztcbiAgICB9XG5cbiAgICByZXR1cm4gc2VsVG9GbjtcbiAgfSgpO1xuXG4gIHZhciBzdGF0ZVNlbGVjdG9yTWF0Y2hlcyA9IGZ1bmN0aW9uIHN0YXRlU2VsZWN0b3JNYXRjaGVzKHNlbCwgZWxlKSB7XG4gICAgcmV0dXJuIGxvb2t1cFtzZWxdKGVsZSk7XG4gIH07XG4gIHZhciBzdGF0ZVNlbGVjdG9yUmVnZXggPSAnKCcgKyBzdGF0ZVNlbGVjdG9ycy5tYXAoZnVuY3Rpb24gKHMpIHtcbiAgICByZXR1cm4gcy5zZWxlY3RvcjtcbiAgfSkuam9pbignfCcpICsgJyknO1xuXG4gIC8vIHNvIHRoYXQgdmFsdWVzIGdldCBjb21wYXJlZCBwcm9wZXJseSBpbiBTZWxlY3Rvci5maWx0ZXIoKVxuXG4gIHZhciBjbGVhbk1ldGFDaGFycyA9IGZ1bmN0aW9uIGNsZWFuTWV0YUNoYXJzKHN0cikge1xuICAgIHJldHVybiBzdHIucmVwbGFjZShuZXcgUmVnRXhwKCdcXFxcXFxcXCgnICsgdG9rZW5zLm1ldGFDaGFyICsgJyknLCAnZycpLCBmdW5jdGlvbiAobWF0Y2gsICQxKSB7XG4gICAgICByZXR1cm4gJDE7XG4gICAgfSk7XG4gIH07XG5cbiAgdmFyIHJlcGxhY2VMYXN0UXVlcnkgPSBmdW5jdGlvbiByZXBsYWNlTGFzdFF1ZXJ5KHNlbGVjdG9yLCBleGFtaW5pbmdRdWVyeSwgcmVwbGFjZW1lbnRRdWVyeSkge1xuICAgIHNlbGVjdG9yW3NlbGVjdG9yLmxlbmd0aCAtIDFdID0gcmVwbGFjZW1lbnRRdWVyeTtcbiAgfTsgLy8gTk9URTogYWRkIG5ldyBleHByZXNzaW9uIHN5bnRheCBoZXJlIHRvIGhhdmUgaXQgcmVjb2duaXNlZCBieSB0aGUgcGFyc2VyO1xuICAvLyAtIGEgcXVlcnkgY29udGFpbnMgYWxsIGFkamFjZW50IChpLmUuIG5vIHNlcGFyYXRvciBpbiBiZXR3ZWVuKSBleHByZXNzaW9ucztcbiAgLy8gLSB0aGUgY3VycmVudCBxdWVyeSBpcyBzdG9yZWQgaW4gc2VsZWN0b3JbaV1cbiAgLy8gLSB5b3UgbmVlZCB0byBjaGVjayB0aGUgcXVlcnkgb2JqZWN0cyBpbiBtYXRjaCgpIGZvciBpdCBhY3R1YWxseSBmaWx0ZXIgcHJvcGVybHksIGJ1dCB0aGF0J3MgcHJldHR5IHN0cmFpZ2h0IGZvcndhcmRcblxuXG4gIHZhciBleHBycyA9IFt7XG4gICAgbmFtZTogJ2dyb3VwJyxcbiAgICAvLyBqdXN0IHVzZWQgZm9yIGlkZW50aWZ5aW5nIHdoZW4gZGVidWdnaW5nXG4gICAgcXVlcnk6IHRydWUsXG4gICAgcmVnZXg6ICcoJyArIHRva2Vucy5ncm91cCArICcpJyxcbiAgICBwb3B1bGF0ZTogZnVuY3Rpb24gcG9wdWxhdGUoc2VsZWN0b3IsIHF1ZXJ5LCBfcmVmKSB7XG4gICAgICB2YXIgX3JlZjIgPSBfc2xpY2VkVG9BcnJheShfcmVmLCAxKSxcbiAgICAgICAgICBncm91cCA9IF9yZWYyWzBdO1xuXG4gICAgICBxdWVyeS5jaGVja3MucHVzaCh7XG4gICAgICAgIHR5cGU6IFR5cGUuR1JPVVAsXG4gICAgICAgIHZhbHVlOiBncm91cCA9PT0gJyonID8gZ3JvdXAgOiBncm91cCArICdzJ1xuICAgICAgfSk7XG4gICAgfVxuICB9LCB7XG4gICAgbmFtZTogJ3N0YXRlJyxcbiAgICBxdWVyeTogdHJ1ZSxcbiAgICByZWdleDogc3RhdGVTZWxlY3RvclJlZ2V4LFxuICAgIHBvcHVsYXRlOiBmdW5jdGlvbiBwb3B1bGF0ZShzZWxlY3RvciwgcXVlcnksIF9yZWYzKSB7XG4gICAgICB2YXIgX3JlZjQgPSBfc2xpY2VkVG9BcnJheShfcmVmMywgMSksXG4gICAgICAgICAgc3RhdGUgPSBfcmVmNFswXTtcblxuICAgICAgcXVlcnkuY2hlY2tzLnB1c2goe1xuICAgICAgICB0eXBlOiBUeXBlLlNUQVRFLFxuICAgICAgICB2YWx1ZTogc3RhdGVcbiAgICAgIH0pO1xuICAgIH1cbiAgfSwge1xuICAgIG5hbWU6ICdpZCcsXG4gICAgcXVlcnk6IHRydWUsXG4gICAgcmVnZXg6ICdcXFxcIygnICsgdG9rZW5zLmlkICsgJyknLFxuICAgIHBvcHVsYXRlOiBmdW5jdGlvbiBwb3B1bGF0ZShzZWxlY3RvciwgcXVlcnksIF9yZWY1KSB7XG4gICAgICB2YXIgX3JlZjYgPSBfc2xpY2VkVG9BcnJheShfcmVmNSwgMSksXG4gICAgICAgICAgaWQgPSBfcmVmNlswXTtcblxuICAgICAgcXVlcnkuY2hlY2tzLnB1c2goe1xuICAgICAgICB0eXBlOiBUeXBlLklELFxuICAgICAgICB2YWx1ZTogY2xlYW5NZXRhQ2hhcnMoaWQpXG4gICAgICB9KTtcbiAgICB9XG4gIH0sIHtcbiAgICBuYW1lOiAnY2xhc3NOYW1lJyxcbiAgICBxdWVyeTogdHJ1ZSxcbiAgICByZWdleDogJ1xcXFwuKCcgKyB0b2tlbnMuY2xhc3NOYW1lICsgJyknLFxuICAgIHBvcHVsYXRlOiBmdW5jdGlvbiBwb3B1bGF0ZShzZWxlY3RvciwgcXVlcnksIF9yZWY3KSB7XG4gICAgICB2YXIgX3JlZjggPSBfc2xpY2VkVG9BcnJheShfcmVmNywgMSksXG4gICAgICAgICAgY2xhc3NOYW1lID0gX3JlZjhbMF07XG5cbiAgICAgIHF1ZXJ5LmNoZWNrcy5wdXNoKHtcbiAgICAgICAgdHlwZTogVHlwZS5DTEFTUyxcbiAgICAgICAgdmFsdWU6IGNsZWFuTWV0YUNoYXJzKGNsYXNzTmFtZSlcbiAgICAgIH0pO1xuICAgIH1cbiAgfSwge1xuICAgIG5hbWU6ICdkYXRhRXhpc3RzJyxcbiAgICBxdWVyeTogdHJ1ZSxcbiAgICByZWdleDogJ1xcXFxbXFxcXHMqKCcgKyB0b2tlbnMudmFyaWFibGUgKyAnKVxcXFxzKlxcXFxdJyxcbiAgICBwb3B1bGF0ZTogZnVuY3Rpb24gcG9wdWxhdGUoc2VsZWN0b3IsIHF1ZXJ5LCBfcmVmOSkge1xuICAgICAgdmFyIF9yZWYxMCA9IF9zbGljZWRUb0FycmF5KF9yZWY5LCAxKSxcbiAgICAgICAgICB2YXJpYWJsZSA9IF9yZWYxMFswXTtcblxuICAgICAgcXVlcnkuY2hlY2tzLnB1c2goe1xuICAgICAgICB0eXBlOiBUeXBlLkRBVEFfRVhJU1QsXG4gICAgICAgIGZpZWxkOiBjbGVhbk1ldGFDaGFycyh2YXJpYWJsZSlcbiAgICAgIH0pO1xuICAgIH1cbiAgfSwge1xuICAgIG5hbWU6ICdkYXRhQ29tcGFyZScsXG4gICAgcXVlcnk6IHRydWUsXG4gICAgcmVnZXg6ICdcXFxcW1xcXFxzKignICsgdG9rZW5zLnZhcmlhYmxlICsgJylcXFxccyooJyArIHRva2Vucy5jb21wYXJhdG9yT3AgKyAnKVxcXFxzKignICsgdG9rZW5zLnZhbHVlICsgJylcXFxccypcXFxcXScsXG4gICAgcG9wdWxhdGU6IGZ1bmN0aW9uIHBvcHVsYXRlKHNlbGVjdG9yLCBxdWVyeSwgX3JlZjExKSB7XG4gICAgICB2YXIgX3JlZjEyID0gX3NsaWNlZFRvQXJyYXkoX3JlZjExLCAzKSxcbiAgICAgICAgICB2YXJpYWJsZSA9IF9yZWYxMlswXSxcbiAgICAgICAgICBjb21wYXJhdG9yT3AgPSBfcmVmMTJbMV0sXG4gICAgICAgICAgdmFsdWUgPSBfcmVmMTJbMl07XG5cbiAgICAgIHZhciB2YWx1ZUlzU3RyaW5nID0gbmV3IFJlZ0V4cCgnXicgKyB0b2tlbnMuc3RyaW5nICsgJyQnKS5leGVjKHZhbHVlKSAhPSBudWxsO1xuXG4gICAgICBpZiAodmFsdWVJc1N0cmluZykge1xuICAgICAgICB2YWx1ZSA9IHZhbHVlLnN1YnN0cmluZygxLCB2YWx1ZS5sZW5ndGggLSAxKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhbHVlID0gcGFyc2VGbG9hdCh2YWx1ZSk7XG4gICAgICB9XG5cbiAgICAgIHF1ZXJ5LmNoZWNrcy5wdXNoKHtcbiAgICAgICAgdHlwZTogVHlwZS5EQVRBX0NPTVBBUkUsXG4gICAgICAgIGZpZWxkOiBjbGVhbk1ldGFDaGFycyh2YXJpYWJsZSksXG4gICAgICAgIG9wZXJhdG9yOiBjb21wYXJhdG9yT3AsXG4gICAgICAgIHZhbHVlOiB2YWx1ZVxuICAgICAgfSk7XG4gICAgfVxuICB9LCB7XG4gICAgbmFtZTogJ2RhdGFCb29sJyxcbiAgICBxdWVyeTogdHJ1ZSxcbiAgICByZWdleDogJ1xcXFxbXFxcXHMqKCcgKyB0b2tlbnMuYm9vbE9wICsgJylcXFxccyooJyArIHRva2Vucy52YXJpYWJsZSArICcpXFxcXHMqXFxcXF0nLFxuICAgIHBvcHVsYXRlOiBmdW5jdGlvbiBwb3B1bGF0ZShzZWxlY3RvciwgcXVlcnksIF9yZWYxMykge1xuICAgICAgdmFyIF9yZWYxNCA9IF9zbGljZWRUb0FycmF5KF9yZWYxMywgMiksXG4gICAgICAgICAgYm9vbE9wID0gX3JlZjE0WzBdLFxuICAgICAgICAgIHZhcmlhYmxlID0gX3JlZjE0WzFdO1xuXG4gICAgICBxdWVyeS5jaGVja3MucHVzaCh7XG4gICAgICAgIHR5cGU6IFR5cGUuREFUQV9CT09MLFxuICAgICAgICBmaWVsZDogY2xlYW5NZXRhQ2hhcnModmFyaWFibGUpLFxuICAgICAgICBvcGVyYXRvcjogYm9vbE9wXG4gICAgICB9KTtcbiAgICB9XG4gIH0sIHtcbiAgICBuYW1lOiAnbWV0YUNvbXBhcmUnLFxuICAgIHF1ZXJ5OiB0cnVlLFxuICAgIHJlZ2V4OiAnXFxcXFtcXFxcW1xcXFxzKignICsgdG9rZW5zLm1ldGEgKyAnKVxcXFxzKignICsgdG9rZW5zLmNvbXBhcmF0b3JPcCArICcpXFxcXHMqKCcgKyB0b2tlbnMubnVtYmVyICsgJylcXFxccypcXFxcXVxcXFxdJyxcbiAgICBwb3B1bGF0ZTogZnVuY3Rpb24gcG9wdWxhdGUoc2VsZWN0b3IsIHF1ZXJ5LCBfcmVmMTUpIHtcbiAgICAgIHZhciBfcmVmMTYgPSBfc2xpY2VkVG9BcnJheShfcmVmMTUsIDMpLFxuICAgICAgICAgIG1ldGEgPSBfcmVmMTZbMF0sXG4gICAgICAgICAgY29tcGFyYXRvck9wID0gX3JlZjE2WzFdLFxuICAgICAgICAgIG51bWJlciA9IF9yZWYxNlsyXTtcblxuICAgICAgcXVlcnkuY2hlY2tzLnB1c2goe1xuICAgICAgICB0eXBlOiBUeXBlLk1FVEFfQ09NUEFSRSxcbiAgICAgICAgZmllbGQ6IGNsZWFuTWV0YUNoYXJzKG1ldGEpLFxuICAgICAgICBvcGVyYXRvcjogY29tcGFyYXRvck9wLFxuICAgICAgICB2YWx1ZTogcGFyc2VGbG9hdChudW1iZXIpXG4gICAgICB9KTtcbiAgICB9XG4gIH0sIHtcbiAgICBuYW1lOiAnbmV4dFF1ZXJ5JyxcbiAgICBzZXBhcmF0b3I6IHRydWUsXG4gICAgcmVnZXg6IHRva2Vucy5zZXBhcmF0b3IsXG4gICAgcG9wdWxhdGU6IGZ1bmN0aW9uIHBvcHVsYXRlKHNlbGVjdG9yLCBxdWVyeSkge1xuICAgICAgdmFyIGN1cnJlbnRTdWJqZWN0ID0gc2VsZWN0b3IuY3VycmVudFN1YmplY3Q7XG4gICAgICB2YXIgZWRnZUNvdW50ID0gc2VsZWN0b3IuZWRnZUNvdW50O1xuICAgICAgdmFyIGNvbXBvdW5kQ291bnQgPSBzZWxlY3Rvci5jb21wb3VuZENvdW50O1xuICAgICAgdmFyIGxhc3RRID0gc2VsZWN0b3Jbc2VsZWN0b3IubGVuZ3RoIC0gMV07XG5cbiAgICAgIGlmIChjdXJyZW50U3ViamVjdCAhPSBudWxsKSB7XG4gICAgICAgIGxhc3RRLnN1YmplY3QgPSBjdXJyZW50U3ViamVjdDtcbiAgICAgICAgc2VsZWN0b3IuY3VycmVudFN1YmplY3QgPSBudWxsO1xuICAgICAgfVxuXG4gICAgICBsYXN0US5lZGdlQ291bnQgPSBlZGdlQ291bnQ7XG4gICAgICBsYXN0US5jb21wb3VuZENvdW50ID0gY29tcG91bmRDb3VudDtcbiAgICAgIHNlbGVjdG9yLmVkZ2VDb3VudCA9IDA7XG4gICAgICBzZWxlY3Rvci5jb21wb3VuZENvdW50ID0gMDsgLy8gZ28gb24gdG8gbmV4dCBxdWVyeVxuXG4gICAgICB2YXIgbmV4dFF1ZXJ5ID0gc2VsZWN0b3Jbc2VsZWN0b3IubGVuZ3RoKytdID0gbmV3UXVlcnkoKTtcbiAgICAgIHJldHVybiBuZXh0UXVlcnk7IC8vIHRoaXMgaXMgdGhlIG5ldyBxdWVyeSB0byBiZSBmaWxsZWQgYnkgdGhlIGZvbGxvd2luZyBleHByc1xuICAgIH1cbiAgfSwge1xuICAgIG5hbWU6ICdkaXJlY3RlZEVkZ2UnLFxuICAgIHNlcGFyYXRvcjogdHJ1ZSxcbiAgICByZWdleDogdG9rZW5zLmRpcmVjdGVkRWRnZSxcbiAgICBwb3B1bGF0ZTogZnVuY3Rpb24gcG9wdWxhdGUoc2VsZWN0b3IsIHF1ZXJ5KSB7XG4gICAgICBpZiAoc2VsZWN0b3IuY3VycmVudFN1YmplY3QgPT0gbnVsbCkge1xuICAgICAgICAvLyB1bmRpcmVjdGVkIGVkZ2VcbiAgICAgICAgdmFyIGVkZ2VRdWVyeSA9IG5ld1F1ZXJ5KCk7XG4gICAgICAgIHZhciBzb3VyY2UgPSBxdWVyeTtcbiAgICAgICAgdmFyIHRhcmdldCA9IG5ld1F1ZXJ5KCk7XG4gICAgICAgIGVkZ2VRdWVyeS5jaGVja3MucHVzaCh7XG4gICAgICAgICAgdHlwZTogVHlwZS5ESVJFQ1RFRF9FREdFLFxuICAgICAgICAgIHNvdXJjZTogc291cmNlLFxuICAgICAgICAgIHRhcmdldDogdGFyZ2V0XG4gICAgICAgIH0pOyAvLyB0aGUgcXVlcnkgaW4gdGhlIHNlbGVjdG9yIHNob3VsZCBiZSB0aGUgZWRnZSByYXRoZXIgdGhhbiB0aGUgc291cmNlXG5cbiAgICAgICAgcmVwbGFjZUxhc3RRdWVyeShzZWxlY3RvciwgcXVlcnksIGVkZ2VRdWVyeSk7XG4gICAgICAgIHNlbGVjdG9yLmVkZ2VDb3VudCsrOyAvLyB3ZSdyZSBub3cgcG9wdWxhdGluZyB0aGUgdGFyZ2V0IHF1ZXJ5IHdpdGggZXhwcmVzc2lvbnMgdGhhdCBmb2xsb3dcblxuICAgICAgICByZXR1cm4gdGFyZ2V0O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gc291cmNlL3RhcmdldFxuICAgICAgICB2YXIgc3JjVGd0USA9IG5ld1F1ZXJ5KCk7XG4gICAgICAgIHZhciBfc291cmNlID0gcXVlcnk7XG5cbiAgICAgICAgdmFyIF90YXJnZXQgPSBuZXdRdWVyeSgpO1xuXG4gICAgICAgIHNyY1RndFEuY2hlY2tzLnB1c2goe1xuICAgICAgICAgIHR5cGU6IFR5cGUuTk9ERV9TT1VSQ0UsXG4gICAgICAgICAgc291cmNlOiBfc291cmNlLFxuICAgICAgICAgIHRhcmdldDogX3RhcmdldFxuICAgICAgICB9KTsgLy8gdGhlIHF1ZXJ5IGluIHRoZSBzZWxlY3RvciBzaG91bGQgYmUgdGhlIG5laWdoYm91cmhvb2QgcmF0aGVyIHRoYW4gdGhlIG5vZGVcblxuICAgICAgICByZXBsYWNlTGFzdFF1ZXJ5KHNlbGVjdG9yLCBxdWVyeSwgc3JjVGd0USk7XG4gICAgICAgIHNlbGVjdG9yLmVkZ2VDb3VudCsrO1xuICAgICAgICByZXR1cm4gX3RhcmdldDsgLy8gbm93IHBvcHVsYXRpbmcgdGhlIHRhcmdldCB3aXRoIHRoZSBmb2xsb3dpbmcgZXhwcmVzc2lvbnNcbiAgICAgIH1cbiAgICB9XG4gIH0sIHtcbiAgICBuYW1lOiAndW5kaXJlY3RlZEVkZ2UnLFxuICAgIHNlcGFyYXRvcjogdHJ1ZSxcbiAgICByZWdleDogdG9rZW5zLnVuZGlyZWN0ZWRFZGdlLFxuICAgIHBvcHVsYXRlOiBmdW5jdGlvbiBwb3B1bGF0ZShzZWxlY3RvciwgcXVlcnkpIHtcbiAgICAgIGlmIChzZWxlY3Rvci5jdXJyZW50U3ViamVjdCA9PSBudWxsKSB7XG4gICAgICAgIC8vIHVuZGlyZWN0ZWQgZWRnZVxuICAgICAgICB2YXIgZWRnZVF1ZXJ5ID0gbmV3UXVlcnkoKTtcbiAgICAgICAgdmFyIHNvdXJjZSA9IHF1ZXJ5O1xuICAgICAgICB2YXIgdGFyZ2V0ID0gbmV3UXVlcnkoKTtcbiAgICAgICAgZWRnZVF1ZXJ5LmNoZWNrcy5wdXNoKHtcbiAgICAgICAgICB0eXBlOiBUeXBlLlVORElSRUNURURfRURHRSxcbiAgICAgICAgICBub2RlczogW3NvdXJjZSwgdGFyZ2V0XVxuICAgICAgICB9KTsgLy8gdGhlIHF1ZXJ5IGluIHRoZSBzZWxlY3RvciBzaG91bGQgYmUgdGhlIGVkZ2UgcmF0aGVyIHRoYW4gdGhlIHNvdXJjZVxuXG4gICAgICAgIHJlcGxhY2VMYXN0UXVlcnkoc2VsZWN0b3IsIHF1ZXJ5LCBlZGdlUXVlcnkpO1xuICAgICAgICBzZWxlY3Rvci5lZGdlQ291bnQrKzsgLy8gd2UncmUgbm93IHBvcHVsYXRpbmcgdGhlIHRhcmdldCBxdWVyeSB3aXRoIGV4cHJlc3Npb25zIHRoYXQgZm9sbG93XG5cbiAgICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIG5laWdoYm91cmhvb2RcbiAgICAgICAgdmFyIG5ob29kUSA9IG5ld1F1ZXJ5KCk7XG4gICAgICAgIHZhciBub2RlID0gcXVlcnk7XG4gICAgICAgIHZhciBuZWlnaGJvciA9IG5ld1F1ZXJ5KCk7XG4gICAgICAgIG5ob29kUS5jaGVja3MucHVzaCh7XG4gICAgICAgICAgdHlwZTogVHlwZS5OT0RFX05FSUdIQk9SLFxuICAgICAgICAgIG5vZGU6IG5vZGUsXG4gICAgICAgICAgbmVpZ2hib3I6IG5laWdoYm9yXG4gICAgICAgIH0pOyAvLyB0aGUgcXVlcnkgaW4gdGhlIHNlbGVjdG9yIHNob3VsZCBiZSB0aGUgbmVpZ2hib3VyaG9vZCByYXRoZXIgdGhhbiB0aGUgbm9kZVxuXG4gICAgICAgIHJlcGxhY2VMYXN0UXVlcnkoc2VsZWN0b3IsIHF1ZXJ5LCBuaG9vZFEpO1xuICAgICAgICByZXR1cm4gbmVpZ2hib3I7IC8vIG5vdyBwb3B1bGF0aW5nIHRoZSBuZWlnaGJvciB3aXRoIGZvbGxvd2luZyBleHByZXNzaW9uc1xuICAgICAgfVxuICAgIH1cbiAgfSwge1xuICAgIG5hbWU6ICdjaGlsZCcsXG4gICAgc2VwYXJhdG9yOiB0cnVlLFxuICAgIHJlZ2V4OiB0b2tlbnMuY2hpbGQsXG4gICAgcG9wdWxhdGU6IGZ1bmN0aW9uIHBvcHVsYXRlKHNlbGVjdG9yLCBxdWVyeSkge1xuICAgICAgaWYgKHNlbGVjdG9yLmN1cnJlbnRTdWJqZWN0ID09IG51bGwpIHtcbiAgICAgICAgLy8gZGVmYXVsdDogY2hpbGQgcXVlcnlcbiAgICAgICAgdmFyIHBhcmVudENoaWxkUXVlcnkgPSBuZXdRdWVyeSgpO1xuICAgICAgICB2YXIgY2hpbGQgPSBuZXdRdWVyeSgpO1xuICAgICAgICB2YXIgcGFyZW50ID0gc2VsZWN0b3Jbc2VsZWN0b3IubGVuZ3RoIC0gMV07XG4gICAgICAgIHBhcmVudENoaWxkUXVlcnkuY2hlY2tzLnB1c2goe1xuICAgICAgICAgIHR5cGU6IFR5cGUuQ0hJTEQsXG4gICAgICAgICAgcGFyZW50OiBwYXJlbnQsXG4gICAgICAgICAgY2hpbGQ6IGNoaWxkXG4gICAgICAgIH0pOyAvLyB0aGUgcXVlcnkgaW4gdGhlIHNlbGVjdG9yIHNob3VsZCBiZSB0aGUgJz4nIGl0c2VsZlxuXG4gICAgICAgIHJlcGxhY2VMYXN0UXVlcnkoc2VsZWN0b3IsIHF1ZXJ5LCBwYXJlbnRDaGlsZFF1ZXJ5KTtcbiAgICAgICAgc2VsZWN0b3IuY29tcG91bmRDb3VudCsrOyAvLyB3ZSdyZSBub3cgcG9wdWxhdGluZyB0aGUgY2hpbGQgcXVlcnkgd2l0aCBleHByZXNzaW9ucyB0aGF0IGZvbGxvd1xuXG4gICAgICAgIHJldHVybiBjaGlsZDtcbiAgICAgIH0gZWxzZSBpZiAoc2VsZWN0b3IuY3VycmVudFN1YmplY3QgPT09IHF1ZXJ5KSB7XG4gICAgICAgIC8vIGNvbXBvdW5kIHNwbGl0IHF1ZXJ5XG4gICAgICAgIHZhciBjb21wb3VuZCA9IG5ld1F1ZXJ5KCk7XG4gICAgICAgIHZhciBsZWZ0ID0gc2VsZWN0b3Jbc2VsZWN0b3IubGVuZ3RoIC0gMV07XG4gICAgICAgIHZhciByaWdodCA9IG5ld1F1ZXJ5KCk7XG4gICAgICAgIHZhciBzdWJqZWN0ID0gbmV3UXVlcnkoKTtcblxuICAgICAgICB2YXIgX2NoaWxkID0gbmV3UXVlcnkoKTtcblxuICAgICAgICB2YXIgX3BhcmVudCA9IG5ld1F1ZXJ5KCk7IC8vIHNldCB1cCB0aGUgcm9vdCBjb21wb3VuZCBxXG5cblxuICAgICAgICBjb21wb3VuZC5jaGVja3MucHVzaCh7XG4gICAgICAgICAgdHlwZTogVHlwZS5DT01QT1VORF9TUExJVCxcbiAgICAgICAgICBsZWZ0OiBsZWZ0LFxuICAgICAgICAgIHJpZ2h0OiByaWdodCxcbiAgICAgICAgICBzdWJqZWN0OiBzdWJqZWN0XG4gICAgICAgIH0pOyAvLyBwb3B1bGF0ZSB0aGUgc3ViamVjdCBhbmQgcmVwbGFjZSB0aGUgcSBhdCB0aGUgb2xkIHNwb3QgKHdpdGhpbiBsZWZ0KSB3aXRoIFRSVUVcblxuICAgICAgICBzdWJqZWN0LmNoZWNrcyA9IHF1ZXJ5LmNoZWNrczsgLy8gdGFrZSB0aGUgY2hlY2tzIGZyb20gdGhlIGxlZnRcblxuICAgICAgICBxdWVyeS5jaGVja3MgPSBbe1xuICAgICAgICAgIHR5cGU6IFR5cGUuVFJVRVxuICAgICAgICB9XTsgLy8gY2hlY2tzIHVuZGVyIGxlZnQgcmVmcyB0aGUgc3ViamVjdCBpbXBsaWNpdGx5XG4gICAgICAgIC8vIHNldCB1cCB0aGUgcmlnaHQgcVxuXG4gICAgICAgIF9wYXJlbnQuY2hlY2tzLnB1c2goe1xuICAgICAgICAgIHR5cGU6IFR5cGUuVFJVRVxuICAgICAgICB9KTsgLy8gcGFyZW50IGltcGxpY2l0bHkgcmVmcyB0aGUgc3ViamVjdFxuXG5cbiAgICAgICAgcmlnaHQuY2hlY2tzLnB1c2goe1xuICAgICAgICAgIHR5cGU6IFR5cGUuUEFSRU5ULFxuICAgICAgICAgIC8vIHR5cGUgaXMgc3dhcHBlZCBvbiByaWdodCBzaWRlIHF1ZXJpZXNcbiAgICAgICAgICBwYXJlbnQ6IF9wYXJlbnQsXG4gICAgICAgICAgY2hpbGQ6IF9jaGlsZCAvLyBlbXB0eSBmb3Igbm93XG5cbiAgICAgICAgfSk7XG4gICAgICAgIHJlcGxhY2VMYXN0UXVlcnkoc2VsZWN0b3IsIGxlZnQsIGNvbXBvdW5kKTsgLy8gdXBkYXRlIHRoZSByZWYgc2luY2Ugd2UgbW92ZWQgdGhpbmdzIGFyb3VuZCBmb3IgYHF1ZXJ5YFxuXG4gICAgICAgIHNlbGVjdG9yLmN1cnJlbnRTdWJqZWN0ID0gc3ViamVjdDtcbiAgICAgICAgc2VsZWN0b3IuY29tcG91bmRDb3VudCsrO1xuICAgICAgICByZXR1cm4gX2NoaWxkOyAvLyBub3cgcG9wdWxhdGluZyB0aGUgcmlnaHQgc2lkZSdzIGNoaWxkXG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBwYXJlbnQgcXVlcnlcbiAgICAgICAgLy8gaW5mbyBmb3IgcGFyZW50IHF1ZXJ5XG4gICAgICAgIHZhciBfcGFyZW50MiA9IG5ld1F1ZXJ5KCk7XG5cbiAgICAgICAgdmFyIF9jaGlsZDIgPSBuZXdRdWVyeSgpO1xuXG4gICAgICAgIHZhciBwY1FDaGVja3MgPSBbe1xuICAgICAgICAgIHR5cGU6IFR5cGUuUEFSRU5ULFxuICAgICAgICAgIHBhcmVudDogX3BhcmVudDIsXG4gICAgICAgICAgY2hpbGQ6IF9jaGlsZDJcbiAgICAgICAgfV07IC8vIHRoZSBwYXJlbnQtY2hpbGQgcXVlcnkgdGFrZXMgdGhlIHBsYWNlIG9mIHRoZSBxdWVyeSBwcmV2aW91c2x5IGJlaW5nIHBvcHVsYXRlZFxuXG4gICAgICAgIF9wYXJlbnQyLmNoZWNrcyA9IHF1ZXJ5LmNoZWNrczsgLy8gdGhlIHByZXZpb3VzIHF1ZXJ5IGNvbnRhaW5zIHRoZSBjaGVja3MgZm9yIHRoZSBwYXJlbnRcblxuICAgICAgICBxdWVyeS5jaGVja3MgPSBwY1FDaGVja3M7IC8vIHBjIHF1ZXJ5IHRha2VzIG92ZXJcblxuICAgICAgICBzZWxlY3Rvci5jb21wb3VuZENvdW50Kys7XG4gICAgICAgIHJldHVybiBfY2hpbGQyOyAvLyB3ZSdyZSBub3cgcG9wdWxhdGluZyB0aGUgY2hpbGRcbiAgICAgIH1cbiAgICB9XG4gIH0sIHtcbiAgICBuYW1lOiAnZGVzY2VuZGFudCcsXG4gICAgc2VwYXJhdG9yOiB0cnVlLFxuICAgIHJlZ2V4OiB0b2tlbnMuZGVzY2VuZGFudCxcbiAgICBwb3B1bGF0ZTogZnVuY3Rpb24gcG9wdWxhdGUoc2VsZWN0b3IsIHF1ZXJ5KSB7XG4gICAgICBpZiAoc2VsZWN0b3IuY3VycmVudFN1YmplY3QgPT0gbnVsbCkge1xuICAgICAgICAvLyBkZWZhdWx0OiBkZXNjZW5kYW50IHF1ZXJ5XG4gICAgICAgIHZhciBhbmNDaFF1ZXJ5ID0gbmV3UXVlcnkoKTtcbiAgICAgICAgdmFyIGRlc2NlbmRhbnQgPSBuZXdRdWVyeSgpO1xuICAgICAgICB2YXIgYW5jZXN0b3IgPSBzZWxlY3RvcltzZWxlY3Rvci5sZW5ndGggLSAxXTtcbiAgICAgICAgYW5jQ2hRdWVyeS5jaGVja3MucHVzaCh7XG4gICAgICAgICAgdHlwZTogVHlwZS5ERVNDRU5EQU5ULFxuICAgICAgICAgIGFuY2VzdG9yOiBhbmNlc3RvcixcbiAgICAgICAgICBkZXNjZW5kYW50OiBkZXNjZW5kYW50XG4gICAgICAgIH0pOyAvLyB0aGUgcXVlcnkgaW4gdGhlIHNlbGVjdG9yIHNob3VsZCBiZSB0aGUgJz4nIGl0c2VsZlxuXG4gICAgICAgIHJlcGxhY2VMYXN0UXVlcnkoc2VsZWN0b3IsIHF1ZXJ5LCBhbmNDaFF1ZXJ5KTtcbiAgICAgICAgc2VsZWN0b3IuY29tcG91bmRDb3VudCsrOyAvLyB3ZSdyZSBub3cgcG9wdWxhdGluZyB0aGUgZGVzY2VuZGFudCBxdWVyeSB3aXRoIGV4cHJlc3Npb25zIHRoYXQgZm9sbG93XG5cbiAgICAgICAgcmV0dXJuIGRlc2NlbmRhbnQ7XG4gICAgICB9IGVsc2UgaWYgKHNlbGVjdG9yLmN1cnJlbnRTdWJqZWN0ID09PSBxdWVyeSkge1xuICAgICAgICAvLyBjb21wb3VuZCBzcGxpdCBxdWVyeVxuICAgICAgICB2YXIgY29tcG91bmQgPSBuZXdRdWVyeSgpO1xuICAgICAgICB2YXIgbGVmdCA9IHNlbGVjdG9yW3NlbGVjdG9yLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgcmlnaHQgPSBuZXdRdWVyeSgpO1xuICAgICAgICB2YXIgc3ViamVjdCA9IG5ld1F1ZXJ5KCk7XG5cbiAgICAgICAgdmFyIF9kZXNjZW5kYW50ID0gbmV3UXVlcnkoKTtcblxuICAgICAgICB2YXIgX2FuY2VzdG9yID0gbmV3UXVlcnkoKTsgLy8gc2V0IHVwIHRoZSByb290IGNvbXBvdW5kIHFcblxuXG4gICAgICAgIGNvbXBvdW5kLmNoZWNrcy5wdXNoKHtcbiAgICAgICAgICB0eXBlOiBUeXBlLkNPTVBPVU5EX1NQTElULFxuICAgICAgICAgIGxlZnQ6IGxlZnQsXG4gICAgICAgICAgcmlnaHQ6IHJpZ2h0LFxuICAgICAgICAgIHN1YmplY3Q6IHN1YmplY3RcbiAgICAgICAgfSk7IC8vIHBvcHVsYXRlIHRoZSBzdWJqZWN0IGFuZCByZXBsYWNlIHRoZSBxIGF0IHRoZSBvbGQgc3BvdCAod2l0aGluIGxlZnQpIHdpdGggVFJVRVxuXG4gICAgICAgIHN1YmplY3QuY2hlY2tzID0gcXVlcnkuY2hlY2tzOyAvLyB0YWtlIHRoZSBjaGVja3MgZnJvbSB0aGUgbGVmdFxuXG4gICAgICAgIHF1ZXJ5LmNoZWNrcyA9IFt7XG4gICAgICAgICAgdHlwZTogVHlwZS5UUlVFXG4gICAgICAgIH1dOyAvLyBjaGVja3MgdW5kZXIgbGVmdCByZWZzIHRoZSBzdWJqZWN0IGltcGxpY2l0bHlcbiAgICAgICAgLy8gc2V0IHVwIHRoZSByaWdodCBxXG5cbiAgICAgICAgX2FuY2VzdG9yLmNoZWNrcy5wdXNoKHtcbiAgICAgICAgICB0eXBlOiBUeXBlLlRSVUVcbiAgICAgICAgfSk7IC8vIGFuY2VzdG9yIGltcGxpY2l0bHkgcmVmcyB0aGUgc3ViamVjdFxuXG5cbiAgICAgICAgcmlnaHQuY2hlY2tzLnB1c2goe1xuICAgICAgICAgIHR5cGU6IFR5cGUuQU5DRVNUT1IsXG4gICAgICAgICAgLy8gdHlwZSBpcyBzd2FwcGVkIG9uIHJpZ2h0IHNpZGUgcXVlcmllc1xuICAgICAgICAgIGFuY2VzdG9yOiBfYW5jZXN0b3IsXG4gICAgICAgICAgZGVzY2VuZGFudDogX2Rlc2NlbmRhbnQgLy8gZW1wdHkgZm9yIG5vd1xuXG4gICAgICAgIH0pO1xuICAgICAgICByZXBsYWNlTGFzdFF1ZXJ5KHNlbGVjdG9yLCBsZWZ0LCBjb21wb3VuZCk7IC8vIHVwZGF0ZSB0aGUgcmVmIHNpbmNlIHdlIG1vdmVkIHRoaW5ncyBhcm91bmQgZm9yIGBxdWVyeWBcblxuICAgICAgICBzZWxlY3Rvci5jdXJyZW50U3ViamVjdCA9IHN1YmplY3Q7XG4gICAgICAgIHNlbGVjdG9yLmNvbXBvdW5kQ291bnQrKztcbiAgICAgICAgcmV0dXJuIF9kZXNjZW5kYW50OyAvLyBub3cgcG9wdWxhdGluZyB0aGUgcmlnaHQgc2lkZSdzIGRlc2NlbmRhbnRcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGFuY2VzdG9yIHF1ZXJ5XG4gICAgICAgIC8vIGluZm8gZm9yIHBhcmVudCBxdWVyeVxuICAgICAgICB2YXIgX2FuY2VzdG9yMiA9IG5ld1F1ZXJ5KCk7XG5cbiAgICAgICAgdmFyIF9kZXNjZW5kYW50MiA9IG5ld1F1ZXJ5KCk7XG5cbiAgICAgICAgdmFyIGFkUUNoZWNrcyA9IFt7XG4gICAgICAgICAgdHlwZTogVHlwZS5BTkNFU1RPUixcbiAgICAgICAgICBhbmNlc3RvcjogX2FuY2VzdG9yMixcbiAgICAgICAgICBkZXNjZW5kYW50OiBfZGVzY2VuZGFudDJcbiAgICAgICAgfV07IC8vIHRoZSBwYXJlbnQtY2hpbGQgcXVlcnkgdGFrZXMgdGhlIHBsYWNlIG9mIHRoZSBxdWVyeSBwcmV2aW91c2x5IGJlaW5nIHBvcHVsYXRlZFxuXG4gICAgICAgIF9hbmNlc3RvcjIuY2hlY2tzID0gcXVlcnkuY2hlY2tzOyAvLyB0aGUgcHJldmlvdXMgcXVlcnkgY29udGFpbnMgdGhlIGNoZWNrcyBmb3IgdGhlIHBhcmVudFxuXG4gICAgICAgIHF1ZXJ5LmNoZWNrcyA9IGFkUUNoZWNrczsgLy8gcGMgcXVlcnkgdGFrZXMgb3ZlclxuXG4gICAgICAgIHNlbGVjdG9yLmNvbXBvdW5kQ291bnQrKztcbiAgICAgICAgcmV0dXJuIF9kZXNjZW5kYW50MjsgLy8gd2UncmUgbm93IHBvcHVsYXRpbmcgdGhlIGNoaWxkXG4gICAgICB9XG4gICAgfVxuICB9LCB7XG4gICAgbmFtZTogJ3N1YmplY3QnLFxuICAgIG1vZGlmaWVyOiB0cnVlLFxuICAgIHJlZ2V4OiB0b2tlbnMuc3ViamVjdCxcbiAgICBwb3B1bGF0ZTogZnVuY3Rpb24gcG9wdWxhdGUoc2VsZWN0b3IsIHF1ZXJ5KSB7XG4gICAgICBpZiAoc2VsZWN0b3IuY3VycmVudFN1YmplY3QgIT0gbnVsbCAmJiBzZWxlY3Rvci5jdXJyZW50U3ViamVjdCAhPT0gcXVlcnkpIHtcbiAgICAgICAgd2FybignUmVkZWZpbml0aW9uIG9mIHN1YmplY3QgaW4gc2VsZWN0b3IgYCcgKyBzZWxlY3Rvci50b1N0cmluZygpICsgJ2AnKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBzZWxlY3Rvci5jdXJyZW50U3ViamVjdCA9IHF1ZXJ5O1xuICAgICAgdmFyIHRvcFEgPSBzZWxlY3RvcltzZWxlY3Rvci5sZW5ndGggLSAxXTtcbiAgICAgIHZhciB0b3BDaGsgPSB0b3BRLmNoZWNrc1swXTtcbiAgICAgIHZhciB0b3BUeXBlID0gdG9wQ2hrID09IG51bGwgPyBudWxsIDogdG9wQ2hrLnR5cGU7XG5cbiAgICAgIGlmICh0b3BUeXBlID09PSBUeXBlLkRJUkVDVEVEX0VER0UpIHtcbiAgICAgICAgLy8gZGlyZWN0ZWQgZWRnZSB3aXRoIHN1YmplY3Qgb24gdGhlIHRhcmdldFxuICAgICAgICAvLyBjaGFuZ2UgdG8gdGFyZ2V0IG5vZGUgY2hlY2tcbiAgICAgICAgdG9wQ2hrLnR5cGUgPSBUeXBlLk5PREVfVEFSR0VUO1xuICAgICAgfSBlbHNlIGlmICh0b3BUeXBlID09PSBUeXBlLlVORElSRUNURURfRURHRSkge1xuICAgICAgICAvLyB1bmRpcmVjdGVkIGVkZ2Ugd2l0aCBzdWJqZWN0IG9uIHRoZSBzZWNvbmQgbm9kZVxuICAgICAgICAvLyBjaGFuZ2UgdG8gbmVpZ2hib3IgY2hlY2tcbiAgICAgICAgdG9wQ2hrLnR5cGUgPSBUeXBlLk5PREVfTkVJR0hCT1I7XG4gICAgICAgIHRvcENoay5ub2RlID0gdG9wQ2hrLm5vZGVzWzFdOyAvLyBzZWNvbmQgbm9kZSBpcyBzdWJqZWN0XG5cbiAgICAgICAgdG9wQ2hrLm5laWdoYm9yID0gdG9wQ2hrLm5vZGVzWzBdOyAvLyBjbGVhbiB1cCB1bnVzZWQgZmllbGRzIGZvciBuZXcgdHlwZVxuXG4gICAgICAgIHRvcENoay5ub2RlcyA9IG51bGw7XG4gICAgICB9XG4gICAgfVxuICB9XTtcbiAgZXhwcnMuZm9yRWFjaChmdW5jdGlvbiAoZSkge1xuICAgIHJldHVybiBlLnJlZ2V4T2JqID0gbmV3IFJlZ0V4cCgnXicgKyBlLnJlZ2V4KTtcbiAgfSk7XG5cbiAgLyoqXG4gICAqIE9mIGFsbCB0aGUgZXhwcmVzc2lvbnMsIGZpbmQgdGhlIGZpcnN0IG1hdGNoIGluIHRoZSByZW1haW5pbmcgdGV4dC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlbWFpbmluZyBUaGUgcmVtYWluaW5nIHRleHQgdG8gcGFyc2VcbiAgICogQHJldHVybnMgVGhlIG1hdGNoZWQgZXhwcmVzc2lvbiBhbmQgdGhlIG5ld2x5IHJlbWFpbmluZyB0ZXh0IGB7IGV4cHIsIG1hdGNoLCBuYW1lLCByZW1haW5pbmcgfWBcbiAgICovXG5cbiAgdmFyIGNvbnN1bWVFeHByID0gZnVuY3Rpb24gY29uc3VtZUV4cHIocmVtYWluaW5nKSB7XG4gICAgdmFyIGV4cHI7XG4gICAgdmFyIG1hdGNoO1xuICAgIHZhciBuYW1lO1xuXG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCBleHBycy5sZW5ndGg7IGorKykge1xuICAgICAgdmFyIGUgPSBleHByc1tqXTtcbiAgICAgIHZhciBuID0gZS5uYW1lO1xuICAgICAgdmFyIG0gPSByZW1haW5pbmcubWF0Y2goZS5yZWdleE9iaik7XG5cbiAgICAgIGlmIChtICE9IG51bGwpIHtcbiAgICAgICAgbWF0Y2ggPSBtO1xuICAgICAgICBleHByID0gZTtcbiAgICAgICAgbmFtZSA9IG47XG4gICAgICAgIHZhciBjb25zdW1lZCA9IG1bMF07XG4gICAgICAgIHJlbWFpbmluZyA9IHJlbWFpbmluZy5zdWJzdHJpbmcoY29uc3VtZWQubGVuZ3RoKTtcbiAgICAgICAgYnJlYWs7IC8vIHdlJ3ZlIGNvbnN1bWVkIG9uZSBleHByLCBzbyB3ZSBjYW4gcmV0dXJuIG5vd1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBleHByOiBleHByLFxuICAgICAgbWF0Y2g6IG1hdGNoLFxuICAgICAgbmFtZTogbmFtZSxcbiAgICAgIHJlbWFpbmluZzogcmVtYWluaW5nXG4gICAgfTtcbiAgfTtcbiAgLyoqXG4gICAqIENvbnN1bWUgYWxsIHRoZSBsZWFkaW5nIHdoaXRlc3BhY2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlbWFpbmluZyBUaGUgdGV4dCB0byBjb25zdW1lXG4gICAqIEByZXR1cm5zIFRoZSB0ZXh0IHdpdGggdGhlIGxlYWRpbmcgd2hpdGVzcGFjZSByZW1vdmVkXG4gICAqL1xuXG5cbiAgdmFyIGNvbnN1bWVXaGl0ZXNwYWNlID0gZnVuY3Rpb24gY29uc3VtZVdoaXRlc3BhY2UocmVtYWluaW5nKSB7XG4gICAgdmFyIG1hdGNoID0gcmVtYWluaW5nLm1hdGNoKC9eXFxzKy8pO1xuXG4gICAgaWYgKG1hdGNoKSB7XG4gICAgICB2YXIgY29uc3VtZWQgPSBtYXRjaFswXTtcbiAgICAgIHJlbWFpbmluZyA9IHJlbWFpbmluZy5zdWJzdHJpbmcoY29uc3VtZWQubGVuZ3RoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVtYWluaW5nO1xuICB9O1xuICAvKipcbiAgICogUGFyc2UgdGhlIHN0cmluZyBhbmQgc3RvcmUgdGhlIHBhcnNlZCByZXByZXNlbnRhdGlvbiBpbiB0aGUgU2VsZWN0b3IuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzZWxlY3RvciBUaGUgc2VsZWN0b3Igc3RyaW5nXG4gICAqIEByZXR1cm5zIGB0cnVlYCBpZiB0aGUgc2VsZWN0b3Igd2FzIHN1Y2Nlc3NmdWxseSBwYXJzZWQsIGBmYWxzZWAgb3RoZXJ3aXNlXG4gICAqL1xuXG5cbiAgdmFyIHBhcnNlID0gZnVuY3Rpb24gcGFyc2Uoc2VsZWN0b3IpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHJlbWFpbmluZyA9IHNlbGYuaW5wdXRUZXh0ID0gc2VsZWN0b3I7XG4gICAgdmFyIGN1cnJlbnRRdWVyeSA9IHNlbGZbMF0gPSBuZXdRdWVyeSgpO1xuICAgIHNlbGYubGVuZ3RoID0gMTtcbiAgICByZW1haW5pbmcgPSBjb25zdW1lV2hpdGVzcGFjZShyZW1haW5pbmcpOyAvLyBnZXQgcmlkIG9mIGxlYWRpbmcgd2hpdGVzcGFjZVxuXG4gICAgZm9yICg7Oykge1xuICAgICAgdmFyIGV4cHJJbmZvID0gY29uc3VtZUV4cHIocmVtYWluaW5nKTtcblxuICAgICAgaWYgKGV4cHJJbmZvLmV4cHIgPT0gbnVsbCkge1xuICAgICAgICB3YXJuKCdUaGUgc2VsZWN0b3IgYCcgKyBzZWxlY3RvciArICdgaXMgaW52YWxpZCcpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgYXJncyA9IGV4cHJJbmZvLm1hdGNoLnNsaWNlKDEpOyAvLyBsZXQgdGhlIHRva2VuIHBvcHVsYXRlIHRoZSBzZWxlY3RvciBvYmplY3QgaW4gY3VycmVudFF1ZXJ5XG5cbiAgICAgICAgdmFyIHJldCA9IGV4cHJJbmZvLmV4cHIucG9wdWxhdGUoc2VsZiwgY3VycmVudFF1ZXJ5LCBhcmdzKTtcblxuICAgICAgICBpZiAocmV0ID09PSBmYWxzZSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTsgLy8gZXhpdCBpZiBwb3B1bGF0aW9uIGZhaWxlZFxuICAgICAgICB9IGVsc2UgaWYgKHJldCAhPSBudWxsKSB7XG4gICAgICAgICAgY3VycmVudFF1ZXJ5ID0gcmV0OyAvLyBjaGFuZ2UgdGhlIGN1cnJlbnQgcXVlcnkgdG8gYmUgZmlsbGVkIGlmIHRoZSBleHByIHNwZWNpZmllc1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJlbWFpbmluZyA9IGV4cHJJbmZvLnJlbWFpbmluZzsgLy8gd2UncmUgZG9uZSB3aGVuIHRoZXJlJ3Mgbm90aGluZyBsZWZ0IHRvIHBhcnNlXG5cbiAgICAgIGlmIChyZW1haW5pbmcubWF0Y2goL15cXHMqJC8pKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBsYXN0USA9IHNlbGZbc2VsZi5sZW5ndGggLSAxXTtcblxuICAgIGlmIChzZWxmLmN1cnJlbnRTdWJqZWN0ICE9IG51bGwpIHtcbiAgICAgIGxhc3RRLnN1YmplY3QgPSBzZWxmLmN1cnJlbnRTdWJqZWN0O1xuICAgIH1cblxuICAgIGxhc3RRLmVkZ2VDb3VudCA9IHNlbGYuZWRnZUNvdW50O1xuICAgIGxhc3RRLmNvbXBvdW5kQ291bnQgPSBzZWxmLmNvbXBvdW5kQ291bnQ7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGYubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBxID0gc2VsZltpXTsgLy8gaW4gZnV0dXJlLCB0aGlzIGNvdWxkIHBvdGVudGlhbGx5IGJlIGFsbG93ZWQgaWYgdGhlcmUgd2VyZSBvcGVyYXRvciBwcmVjZWRlbmNlIGFuZCBkZXRlY3Rpb24gb2YgaW52YWxpZCBjb21iaW5hdGlvbnNcblxuICAgICAgaWYgKHEuY29tcG91bmRDb3VudCA+IDAgJiYgcS5lZGdlQ291bnQgPiAwKSB7XG4gICAgICAgIHdhcm4oJ1RoZSBzZWxlY3RvciBgJyArIHNlbGVjdG9yICsgJ2AgaXMgaW52YWxpZCBiZWNhdXNlIGl0IHVzZXMgYm90aCBhIGNvbXBvdW5kIHNlbGVjdG9yIGFuZCBhbiBlZGdlIHNlbGVjdG9yJyk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgaWYgKHEuZWRnZUNvdW50ID4gMSkge1xuICAgICAgICB3YXJuKCdUaGUgc2VsZWN0b3IgYCcgKyBzZWxlY3RvciArICdgIGlzIGludmFsaWQgYmVjYXVzZSBpdCB1c2VzIG11bHRpcGxlIGVkZ2Ugc2VsZWN0b3JzJyk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0gZWxzZSBpZiAocS5lZGdlQ291bnQgPT09IDEpIHtcbiAgICAgICAgd2FybignVGhlIHNlbGVjdG9yIGAnICsgc2VsZWN0b3IgKyAnYCBpcyBkZXByZWNhdGVkLiAgRWRnZSBzZWxlY3RvcnMgZG8gbm90IHRha2UgZWZmZWN0IG9uIGNoYW5nZXMgdG8gc291cmNlIGFuZCB0YXJnZXQgbm9kZXMgYWZ0ZXIgYW4gZWRnZSBpcyBhZGRlZCwgZm9yIHBlcmZvcm1hbmNlIHJlYXNvbnMuICBVc2UgYSBjbGFzcyBvciBkYXRhIHNlbGVjdG9yIG9uIGVkZ2VzIGluc3RlYWQsIHVwZGF0aW5nIHRoZSBjbGFzcyBvciBkYXRhIG9mIGFuIGVkZ2Ugd2hlbiB5b3VyIGFwcCBkZXRlY3RzIGEgY2hhbmdlIGluIHNvdXJjZSBvciB0YXJnZXQgbm9kZXMuJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7IC8vIHN1Y2Nlc3NcbiAgfTtcbiAgLyoqXG4gICAqIEdldCB0aGUgc2VsZWN0b3IgcmVwcmVzZW50ZWQgYXMgYSBzdHJpbmcuICBUaGlzIHZhbHVlIHVzZXMgZGVmYXVsdCBmb3JtYXR0aW5nLFxuICAgKiBzbyB0aGluZ3MgbGlrZSBzcGFjaW5nIG1heSBkaWZmZXIgZnJvbSB0aGUgaW5wdXQgdGV4dCBwYXNzZWQgdG8gdGhlIGNvbnN0cnVjdG9yLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc2VsZWN0b3Igc3RyaW5nXG4gICAqL1xuXG5cbiAgdmFyIHRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcoKSB7XG4gICAgaWYgKHRoaXMudG9TdHJpbmdDYWNoZSAhPSBudWxsKSB7XG4gICAgICByZXR1cm4gdGhpcy50b1N0cmluZ0NhY2hlO1xuICAgIH1cblxuICAgIHZhciBjbGVhbiA9IGZ1bmN0aW9uIGNsZWFuKG9iaikge1xuICAgICAgaWYgKG9iaiA9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiAnJztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBvYmo7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHZhciBjbGVhblZhbCA9IGZ1bmN0aW9uIGNsZWFuVmFsKHZhbCkge1xuICAgICAgaWYgKHN0cmluZyh2YWwpKSB7XG4gICAgICAgIHJldHVybiAnXCInICsgdmFsICsgJ1wiJztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBjbGVhbih2YWwpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgc3BhY2UgPSBmdW5jdGlvbiBzcGFjZSh2YWwpIHtcbiAgICAgIHJldHVybiAnICcgKyB2YWwgKyAnICc7XG4gICAgfTtcblxuICAgIHZhciBjaGVja1RvU3RyaW5nID0gZnVuY3Rpb24gY2hlY2tUb1N0cmluZyhjaGVjaywgc3ViamVjdCkge1xuICAgICAgdmFyIHR5cGUgPSBjaGVjay50eXBlLFxuICAgICAgICAgIHZhbHVlID0gY2hlY2sudmFsdWU7XG5cbiAgICAgIHN3aXRjaCAodHlwZSkge1xuICAgICAgICBjYXNlIFR5cGUuR1JPVVA6XG4gICAgICAgICAge1xuICAgICAgICAgICAgdmFyIGdyb3VwID0gY2xlYW4odmFsdWUpO1xuICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnN1YnN0cmluZygwLCBncm91cC5sZW5ndGggLSAxKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgY2FzZSBUeXBlLkRBVEFfQ09NUEFSRTpcbiAgICAgICAgICB7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBjaGVjay5maWVsZCxcbiAgICAgICAgICAgICAgICBvcGVyYXRvciA9IGNoZWNrLm9wZXJhdG9yO1xuICAgICAgICAgICAgcmV0dXJuICdbJyArIGZpZWxkICsgc3BhY2UoY2xlYW4ob3BlcmF0b3IpKSArIGNsZWFuVmFsKHZhbHVlKSArICddJztcbiAgICAgICAgICB9XG5cbiAgICAgICAgY2FzZSBUeXBlLkRBVEFfQk9PTDpcbiAgICAgICAgICB7XG4gICAgICAgICAgICB2YXIgX29wZXJhdG9yID0gY2hlY2sub3BlcmF0b3IsXG4gICAgICAgICAgICAgICAgX2ZpZWxkID0gY2hlY2suZmllbGQ7XG4gICAgICAgICAgICByZXR1cm4gJ1snICsgY2xlYW4oX29wZXJhdG9yKSArIF9maWVsZCArICddJztcbiAgICAgICAgICB9XG5cbiAgICAgICAgY2FzZSBUeXBlLkRBVEFfRVhJU1Q6XG4gICAgICAgICAge1xuICAgICAgICAgICAgdmFyIF9maWVsZDIgPSBjaGVjay5maWVsZDtcbiAgICAgICAgICAgIHJldHVybiAnWycgKyBfZmllbGQyICsgJ10nO1xuICAgICAgICAgIH1cblxuICAgICAgICBjYXNlIFR5cGUuTUVUQV9DT01QQVJFOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHZhciBfb3BlcmF0b3IyID0gY2hlY2sub3BlcmF0b3IsXG4gICAgICAgICAgICAgICAgX2ZpZWxkMyA9IGNoZWNrLmZpZWxkO1xuICAgICAgICAgICAgcmV0dXJuICdbWycgKyBfZmllbGQzICsgc3BhY2UoY2xlYW4oX29wZXJhdG9yMikpICsgY2xlYW5WYWwodmFsdWUpICsgJ11dJztcbiAgICAgICAgICB9XG5cbiAgICAgICAgY2FzZSBUeXBlLlNUQVRFOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgY2FzZSBUeXBlLklEOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHJldHVybiAnIycgKyB2YWx1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgY2FzZSBUeXBlLkNMQVNTOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHJldHVybiAnLicgKyB2YWx1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgY2FzZSBUeXBlLlBBUkVOVDpcbiAgICAgICAgY2FzZSBUeXBlLkNISUxEOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHJldHVybiBxdWVyeVRvU3RyaW5nKGNoZWNrLnBhcmVudCwgc3ViamVjdCkgKyBzcGFjZSgnPicpICsgcXVlcnlUb1N0cmluZyhjaGVjay5jaGlsZCwgc3ViamVjdCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgIGNhc2UgVHlwZS5BTkNFU1RPUjpcbiAgICAgICAgY2FzZSBUeXBlLkRFU0NFTkRBTlQ6XG4gICAgICAgICAge1xuICAgICAgICAgICAgcmV0dXJuIHF1ZXJ5VG9TdHJpbmcoY2hlY2suYW5jZXN0b3IsIHN1YmplY3QpICsgJyAnICsgcXVlcnlUb1N0cmluZyhjaGVjay5kZXNjZW5kYW50LCBzdWJqZWN0KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgY2FzZSBUeXBlLkNPTVBPVU5EX1NQTElUOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHZhciBsaHMgPSBxdWVyeVRvU3RyaW5nKGNoZWNrLmxlZnQsIHN1YmplY3QpO1xuICAgICAgICAgICAgdmFyIHN1YiA9IHF1ZXJ5VG9TdHJpbmcoY2hlY2suc3ViamVjdCwgc3ViamVjdCk7XG4gICAgICAgICAgICB2YXIgcmhzID0gcXVlcnlUb1N0cmluZyhjaGVjay5yaWdodCwgc3ViamVjdCk7XG4gICAgICAgICAgICByZXR1cm4gbGhzICsgKGxocy5sZW5ndGggPiAwID8gJyAnIDogJycpICsgc3ViICsgcmhzO1xuICAgICAgICAgIH1cblxuICAgICAgICBjYXNlIFR5cGUuVFJVRTpcbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcXVlcnlUb1N0cmluZyA9IGZ1bmN0aW9uIHF1ZXJ5VG9TdHJpbmcocXVlcnksIHN1YmplY3QpIHtcbiAgICAgIHJldHVybiBxdWVyeS5jaGVja3MucmVkdWNlKGZ1bmN0aW9uIChzdHIsIGNoaywgaSkge1xuICAgICAgICByZXR1cm4gc3RyICsgKHN1YmplY3QgPT09IHF1ZXJ5ICYmIGkgPT09IDAgPyAnJCcgOiAnJykgKyBjaGVja1RvU3RyaW5nKGNoaywgc3ViamVjdCk7XG4gICAgICB9LCAnJyk7XG4gICAgfTtcblxuICAgIHZhciBzdHIgPSAnJztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHF1ZXJ5ID0gdGhpc1tpXTtcbiAgICAgIHN0ciArPSBxdWVyeVRvU3RyaW5nKHF1ZXJ5LCBxdWVyeS5zdWJqZWN0KTtcblxuICAgICAgaWYgKHRoaXMubGVuZ3RoID4gMSAmJiBpIDwgdGhpcy5sZW5ndGggLSAxKSB7XG4gICAgICAgIHN0ciArPSAnLCAnO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMudG9TdHJpbmdDYWNoZSA9IHN0cjtcbiAgICByZXR1cm4gc3RyO1xuICB9O1xuICB2YXIgcGFyc2UkMSA9IHtcbiAgICBwYXJzZTogcGFyc2UsXG4gICAgdG9TdHJpbmc6IHRvU3RyaW5nXG4gIH07XG5cbiAgdmFyIHZhbENtcCA9IGZ1bmN0aW9uIHZhbENtcChmaWVsZFZhbCwgb3BlcmF0b3IsIHZhbHVlKSB7XG4gICAgdmFyIG1hdGNoZXM7XG4gICAgdmFyIGlzRmllbGRTdHIgPSBzdHJpbmcoZmllbGRWYWwpO1xuICAgIHZhciBpc0ZpZWxkTnVtID0gbnVtYmVyJDEoZmllbGRWYWwpO1xuICAgIHZhciBpc1ZhbFN0ciA9IHN0cmluZyh2YWx1ZSk7XG4gICAgdmFyIGZpZWxkU3RyLCB2YWxTdHI7XG4gICAgdmFyIGNhc2VJbnNlbnNpdGl2ZSA9IGZhbHNlO1xuICAgIHZhciBub3RFeHByID0gZmFsc2U7XG4gICAgdmFyIGlzSW5lcUNtcCA9IGZhbHNlO1xuXG4gICAgaWYgKG9wZXJhdG9yLmluZGV4T2YoJyEnKSA+PSAwKSB7XG4gICAgICBvcGVyYXRvciA9IG9wZXJhdG9yLnJlcGxhY2UoJyEnLCAnJyk7XG4gICAgICBub3RFeHByID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAob3BlcmF0b3IuaW5kZXhPZignQCcpID49IDApIHtcbiAgICAgIG9wZXJhdG9yID0gb3BlcmF0b3IucmVwbGFjZSgnQCcsICcnKTtcbiAgICAgIGNhc2VJbnNlbnNpdGl2ZSA9IHRydWU7XG4gICAgfVxuXG4gICAgaWYgKGlzRmllbGRTdHIgfHwgaXNWYWxTdHIgfHwgY2FzZUluc2Vuc2l0aXZlKSB7XG4gICAgICBmaWVsZFN0ciA9ICFpc0ZpZWxkU3RyICYmICFpc0ZpZWxkTnVtID8gJycgOiAnJyArIGZpZWxkVmFsO1xuICAgICAgdmFsU3RyID0gJycgKyB2YWx1ZTtcbiAgICB9IC8vIGlmIHdlJ3JlIGRvaW5nIGEgY2FzZSBpbnNlbnNpdGl2ZSBjb21wYXJpc29uLCB0aGVuIHdlJ3JlIHVzaW5nIGEgU1RSSU5HIGNvbXBhcmlzb25cbiAgICAvLyBldmVuIGlmIHdlJ3JlIGNvbXBhcmluZyBudW1iZXJzXG5cblxuICAgIGlmIChjYXNlSW5zZW5zaXRpdmUpIHtcbiAgICAgIGZpZWxkVmFsID0gZmllbGRTdHIgPSBmaWVsZFN0ci50b0xvd2VyQ2FzZSgpO1xuICAgICAgdmFsdWUgPSB2YWxTdHIgPSB2YWxTdHIudG9Mb3dlckNhc2UoKTtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKG9wZXJhdG9yKSB7XG4gICAgICBjYXNlICcqPSc6XG4gICAgICAgIG1hdGNoZXMgPSBmaWVsZFN0ci5pbmRleE9mKHZhbFN0cikgPj0gMDtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJyQ9JzpcbiAgICAgICAgbWF0Y2hlcyA9IGZpZWxkU3RyLmluZGV4T2YodmFsU3RyLCBmaWVsZFN0ci5sZW5ndGggLSB2YWxTdHIubGVuZ3RoKSA+PSAwO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnXj0nOlxuICAgICAgICBtYXRjaGVzID0gZmllbGRTdHIuaW5kZXhPZih2YWxTdHIpID09PSAwO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnPSc6XG4gICAgICAgIG1hdGNoZXMgPSBmaWVsZFZhbCA9PT0gdmFsdWU7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICc+JzpcbiAgICAgICAgaXNJbmVxQ21wID0gdHJ1ZTtcbiAgICAgICAgbWF0Y2hlcyA9IGZpZWxkVmFsID4gdmFsdWU7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICc+PSc6XG4gICAgICAgIGlzSW5lcUNtcCA9IHRydWU7XG4gICAgICAgIG1hdGNoZXMgPSBmaWVsZFZhbCA+PSB2YWx1ZTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJzwnOlxuICAgICAgICBpc0luZXFDbXAgPSB0cnVlO1xuICAgICAgICBtYXRjaGVzID0gZmllbGRWYWwgPCB2YWx1ZTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJzw9JzpcbiAgICAgICAgaXNJbmVxQ21wID0gdHJ1ZTtcbiAgICAgICAgbWF0Y2hlcyA9IGZpZWxkVmFsIDw9IHZhbHVlO1xuICAgICAgICBicmVhaztcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgbWF0Y2hlcyA9IGZhbHNlO1xuICAgICAgICBicmVhaztcbiAgICB9IC8vIGFwcGx5IHRoZSBub3Qgb3AsIGJ1dCBudWxsIHZhbHMgZm9yIGluZXF1YWxpdGllcyBzaG91bGQgYWx3YXlzIHN0YXkgbm9uLW1hdGNoaW5nXG5cblxuICAgIGlmIChub3RFeHByICYmIChmaWVsZFZhbCAhPSBudWxsIHx8ICFpc0luZXFDbXApKSB7XG4gICAgICBtYXRjaGVzID0gIW1hdGNoZXM7XG4gICAgfVxuXG4gICAgcmV0dXJuIG1hdGNoZXM7XG4gIH07XG4gIHZhciBib29sQ21wID0gZnVuY3Rpb24gYm9vbENtcChmaWVsZFZhbCwgb3BlcmF0b3IpIHtcbiAgICBzd2l0Y2ggKG9wZXJhdG9yKSB7XG4gICAgICBjYXNlICc/JzpcbiAgICAgICAgcmV0dXJuIGZpZWxkVmFsID8gdHJ1ZSA6IGZhbHNlO1xuXG4gICAgICBjYXNlICchJzpcbiAgICAgICAgcmV0dXJuIGZpZWxkVmFsID8gZmFsc2UgOiB0cnVlO1xuXG4gICAgICBjYXNlICdeJzpcbiAgICAgICAgcmV0dXJuIGZpZWxkVmFsID09PSB1bmRlZmluZWQ7XG4gICAgfVxuICB9O1xuICB2YXIgZXhpc3RDbXAgPSBmdW5jdGlvbiBleGlzdENtcChmaWVsZFZhbCkge1xuICAgIHJldHVybiBmaWVsZFZhbCAhPT0gdW5kZWZpbmVkO1xuICB9O1xuICB2YXIgZGF0YSQxID0gZnVuY3Rpb24gZGF0YShlbGUsIGZpZWxkKSB7XG4gICAgcmV0dXJuIGVsZS5kYXRhKGZpZWxkKTtcbiAgfTtcbiAgdmFyIG1ldGEgPSBmdW5jdGlvbiBtZXRhKGVsZSwgZmllbGQpIHtcbiAgICByZXR1cm4gZWxlW2ZpZWxkXSgpO1xuICB9O1xuXG4gIC8qKiBBIGxvb2t1cCBvZiBgbWF0Y2goY2hlY2ssIGVsZSlgIGZ1bmN0aW9ucyBieSBgVHlwZWAgaW50ICovXG5cbiAgdmFyIG1hdGNoID0gW107XG4gIC8qKlxuICAgKiBSZXR1cm5zIHdoZXRoZXIgdGhlIHF1ZXJ5IG1hdGNoZXMgZm9yIHRoZSBlbGVtZW50XG4gICAqIEBwYXJhbSBxdWVyeSBUaGUgYHsgdHlwZSwgdmFsdWUsIC4uLiB9YCBxdWVyeSBvYmplY3RcbiAgICogQHBhcmFtIGVsZSBUaGUgZWxlbWVudCB0byBjb21wYXJlIGFnYWluc3RcbiAgKi9cblxuICB2YXIgbWF0Y2hlcyQxID0gZnVuY3Rpb24gbWF0Y2hlcyhxdWVyeSwgZWxlKSB7XG4gICAgcmV0dXJuIHF1ZXJ5LmNoZWNrcy5ldmVyeShmdW5jdGlvbiAoY2hrKSB7XG4gICAgICByZXR1cm4gbWF0Y2hbY2hrLnR5cGVdKGNoaywgZWxlKTtcbiAgICB9KTtcbiAgfTtcblxuICBtYXRjaFtUeXBlLkdST1VQXSA9IGZ1bmN0aW9uIChjaGVjaywgZWxlKSB7XG4gICAgdmFyIGdyb3VwID0gY2hlY2sudmFsdWU7XG4gICAgcmV0dXJuIGdyb3VwID09PSAnKicgfHwgZ3JvdXAgPT09IGVsZS5ncm91cCgpO1xuICB9O1xuXG4gIG1hdGNoW1R5cGUuU1RBVEVdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICB2YXIgc3RhdGVTZWxlY3RvciA9IGNoZWNrLnZhbHVlO1xuICAgIHJldHVybiBzdGF0ZVNlbGVjdG9yTWF0Y2hlcyhzdGF0ZVNlbGVjdG9yLCBlbGUpO1xuICB9O1xuXG4gIG1hdGNoW1R5cGUuSURdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICB2YXIgaWQgPSBjaGVjay52YWx1ZTtcbiAgICByZXR1cm4gZWxlLmlkKCkgPT09IGlkO1xuICB9O1xuXG4gIG1hdGNoW1R5cGUuQ0xBU1NdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICB2YXIgY2xzID0gY2hlY2sudmFsdWU7XG4gICAgcmV0dXJuIGVsZS5oYXNDbGFzcyhjbHMpO1xuICB9O1xuXG4gIG1hdGNoW1R5cGUuTUVUQV9DT01QQVJFXSA9IGZ1bmN0aW9uIChjaGVjaywgZWxlKSB7XG4gICAgdmFyIGZpZWxkID0gY2hlY2suZmllbGQsXG4gICAgICAgIG9wZXJhdG9yID0gY2hlY2sub3BlcmF0b3IsXG4gICAgICAgIHZhbHVlID0gY2hlY2sudmFsdWU7XG4gICAgcmV0dXJuIHZhbENtcChtZXRhKGVsZSwgZmllbGQpLCBvcGVyYXRvciwgdmFsdWUpO1xuICB9O1xuXG4gIG1hdGNoW1R5cGUuREFUQV9DT01QQVJFXSA9IGZ1bmN0aW9uIChjaGVjaywgZWxlKSB7XG4gICAgdmFyIGZpZWxkID0gY2hlY2suZmllbGQsXG4gICAgICAgIG9wZXJhdG9yID0gY2hlY2sub3BlcmF0b3IsXG4gICAgICAgIHZhbHVlID0gY2hlY2sudmFsdWU7XG4gICAgcmV0dXJuIHZhbENtcChkYXRhJDEoZWxlLCBmaWVsZCksIG9wZXJhdG9yLCB2YWx1ZSk7XG4gIH07XG5cbiAgbWF0Y2hbVHlwZS5EQVRBX0JPT0xdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICB2YXIgZmllbGQgPSBjaGVjay5maWVsZCxcbiAgICAgICAgb3BlcmF0b3IgPSBjaGVjay5vcGVyYXRvcjtcbiAgICByZXR1cm4gYm9vbENtcChkYXRhJDEoZWxlLCBmaWVsZCksIG9wZXJhdG9yKTtcbiAgfTtcblxuICBtYXRjaFtUeXBlLkRBVEFfRVhJU1RdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICB2YXIgZmllbGQgPSBjaGVjay5maWVsZDtcbiAgICAgICAgY2hlY2sub3BlcmF0b3I7XG4gICAgcmV0dXJuIGV4aXN0Q21wKGRhdGEkMShlbGUsIGZpZWxkKSk7XG4gIH07XG5cbiAgbWF0Y2hbVHlwZS5VTkRJUkVDVEVEX0VER0VdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICB2YXIgcUEgPSBjaGVjay5ub2Rlc1swXTtcbiAgICB2YXIgcUIgPSBjaGVjay5ub2Rlc1sxXTtcbiAgICB2YXIgc3JjID0gZWxlLnNvdXJjZSgpO1xuICAgIHZhciB0Z3QgPSBlbGUudGFyZ2V0KCk7XG4gICAgcmV0dXJuIG1hdGNoZXMkMShxQSwgc3JjKSAmJiBtYXRjaGVzJDEocUIsIHRndCkgfHwgbWF0Y2hlcyQxKHFCLCBzcmMpICYmIG1hdGNoZXMkMShxQSwgdGd0KTtcbiAgfTtcblxuICBtYXRjaFtUeXBlLk5PREVfTkVJR0hCT1JdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICByZXR1cm4gbWF0Y2hlcyQxKGNoZWNrLm5vZGUsIGVsZSkgJiYgZWxlLm5laWdoYm9yaG9vZCgpLnNvbWUoZnVuY3Rpb24gKG4pIHtcbiAgICAgIHJldHVybiBuLmlzTm9kZSgpICYmIG1hdGNoZXMkMShjaGVjay5uZWlnaGJvciwgbik7XG4gICAgfSk7XG4gIH07XG5cbiAgbWF0Y2hbVHlwZS5ESVJFQ1RFRF9FREdFXSA9IGZ1bmN0aW9uIChjaGVjaywgZWxlKSB7XG4gICAgcmV0dXJuIG1hdGNoZXMkMShjaGVjay5zb3VyY2UsIGVsZS5zb3VyY2UoKSkgJiYgbWF0Y2hlcyQxKGNoZWNrLnRhcmdldCwgZWxlLnRhcmdldCgpKTtcbiAgfTtcblxuICBtYXRjaFtUeXBlLk5PREVfU09VUkNFXSA9IGZ1bmN0aW9uIChjaGVjaywgZWxlKSB7XG4gICAgcmV0dXJuIG1hdGNoZXMkMShjaGVjay5zb3VyY2UsIGVsZSkgJiYgZWxlLm91dGdvZXJzKCkuc29tZShmdW5jdGlvbiAobikge1xuICAgICAgcmV0dXJuIG4uaXNOb2RlKCkgJiYgbWF0Y2hlcyQxKGNoZWNrLnRhcmdldCwgbik7XG4gICAgfSk7XG4gIH07XG5cbiAgbWF0Y2hbVHlwZS5OT0RFX1RBUkdFVF0gPSBmdW5jdGlvbiAoY2hlY2ssIGVsZSkge1xuICAgIHJldHVybiBtYXRjaGVzJDEoY2hlY2sudGFyZ2V0LCBlbGUpICYmIGVsZS5pbmNvbWVycygpLnNvbWUoZnVuY3Rpb24gKG4pIHtcbiAgICAgIHJldHVybiBuLmlzTm9kZSgpICYmIG1hdGNoZXMkMShjaGVjay5zb3VyY2UsIG4pO1xuICAgIH0pO1xuICB9O1xuXG4gIG1hdGNoW1R5cGUuQ0hJTERdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICByZXR1cm4gbWF0Y2hlcyQxKGNoZWNrLmNoaWxkLCBlbGUpICYmIG1hdGNoZXMkMShjaGVjay5wYXJlbnQsIGVsZS5wYXJlbnQoKSk7XG4gIH07XG5cbiAgbWF0Y2hbVHlwZS5QQVJFTlRdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICByZXR1cm4gbWF0Y2hlcyQxKGNoZWNrLnBhcmVudCwgZWxlKSAmJiBlbGUuY2hpbGRyZW4oKS5zb21lKGZ1bmN0aW9uIChjKSB7XG4gICAgICByZXR1cm4gbWF0Y2hlcyQxKGNoZWNrLmNoaWxkLCBjKTtcbiAgICB9KTtcbiAgfTtcblxuICBtYXRjaFtUeXBlLkRFU0NFTkRBTlRdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICByZXR1cm4gbWF0Y2hlcyQxKGNoZWNrLmRlc2NlbmRhbnQsIGVsZSkgJiYgZWxlLmFuY2VzdG9ycygpLnNvbWUoZnVuY3Rpb24gKGEpIHtcbiAgICAgIHJldHVybiBtYXRjaGVzJDEoY2hlY2suYW5jZXN0b3IsIGEpO1xuICAgIH0pO1xuICB9O1xuXG4gIG1hdGNoW1R5cGUuQU5DRVNUT1JdID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICByZXR1cm4gbWF0Y2hlcyQxKGNoZWNrLmFuY2VzdG9yLCBlbGUpICYmIGVsZS5kZXNjZW5kYW50cygpLnNvbWUoZnVuY3Rpb24gKGQpIHtcbiAgICAgIHJldHVybiBtYXRjaGVzJDEoY2hlY2suZGVzY2VuZGFudCwgZCk7XG4gICAgfSk7XG4gIH07XG5cbiAgbWF0Y2hbVHlwZS5DT01QT1VORF9TUExJVF0gPSBmdW5jdGlvbiAoY2hlY2ssIGVsZSkge1xuICAgIHJldHVybiBtYXRjaGVzJDEoY2hlY2suc3ViamVjdCwgZWxlKSAmJiBtYXRjaGVzJDEoY2hlY2subGVmdCwgZWxlKSAmJiBtYXRjaGVzJDEoY2hlY2sucmlnaHQsIGVsZSk7XG4gIH07XG5cbiAgbWF0Y2hbVHlwZS5UUlVFXSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfTtcblxuICBtYXRjaFtUeXBlLkNPTExFQ1RJT05dID0gZnVuY3Rpb24gKGNoZWNrLCBlbGUpIHtcbiAgICB2YXIgY29sbGVjdGlvbiA9IGNoZWNrLnZhbHVlO1xuICAgIHJldHVybiBjb2xsZWN0aW9uLmhhcyhlbGUpO1xuICB9O1xuXG4gIG1hdGNoW1R5cGUuRklMVEVSXSA9IGZ1bmN0aW9uIChjaGVjaywgZWxlKSB7XG4gICAgdmFyIGZpbHRlciA9IGNoZWNrLnZhbHVlO1xuICAgIHJldHVybiBmaWx0ZXIoZWxlKTtcbiAgfTtcblxuICB2YXIgZmlsdGVyID0gZnVuY3Rpb24gZmlsdGVyKGNvbGxlY3Rpb24pIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7IC8vIGZvciAxIGlkICNmb28gcXVlcmllcywganVzdCBnZXQgdGhlIGVsZW1lbnRcblxuICAgIGlmIChzZWxmLmxlbmd0aCA9PT0gMSAmJiBzZWxmWzBdLmNoZWNrcy5sZW5ndGggPT09IDEgJiYgc2VsZlswXS5jaGVja3NbMF0udHlwZSA9PT0gVHlwZS5JRCkge1xuICAgICAgcmV0dXJuIGNvbGxlY3Rpb24uZ2V0RWxlbWVudEJ5SWQoc2VsZlswXS5jaGVja3NbMF0udmFsdWUpLmNvbGxlY3Rpb24oKTtcbiAgICB9XG5cbiAgICB2YXIgc2VsZWN0b3JGdW5jdGlvbiA9IGZ1bmN0aW9uIHNlbGVjdG9yRnVuY3Rpb24oZWxlbWVudCkge1xuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBzZWxmLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHZhciBxdWVyeSA9IHNlbGZbal07XG5cbiAgICAgICAgaWYgKG1hdGNoZXMkMShxdWVyeSwgZWxlbWVudCkpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIGlmIChzZWxmLnRleHQoKSA9PSBudWxsKSB7XG4gICAgICBzZWxlY3RvckZ1bmN0aW9uID0gZnVuY3Rpb24gc2VsZWN0b3JGdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBjb2xsZWN0aW9uLmZpbHRlcihzZWxlY3RvckZ1bmN0aW9uKTtcbiAgfTsgLy8gZmlsdGVyXG4gIC8vIGRvZXMgc2VsZWN0b3IgbWF0Y2ggYSBzaW5nbGUgZWxlbWVudD9cblxuXG4gIHZhciBtYXRjaGVzID0gZnVuY3Rpb24gbWF0Y2hlcyhlbGUpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IHNlbGYubGVuZ3RoOyBqKyspIHtcbiAgICAgIHZhciBxdWVyeSA9IHNlbGZbal07XG5cbiAgICAgIGlmIChtYXRjaGVzJDEocXVlcnksIGVsZSkpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9OyAvLyBtYXRjaGVzXG5cblxuICB2YXIgbWF0Y2hpbmcgPSB7XG4gICAgbWF0Y2hlczogbWF0Y2hlcyxcbiAgICBmaWx0ZXI6IGZpbHRlclxuICB9O1xuXG4gIHZhciBTZWxlY3RvciA9IGZ1bmN0aW9uIFNlbGVjdG9yKHNlbGVjdG9yKSB7XG4gICAgdGhpcy5pbnB1dFRleHQgPSBzZWxlY3RvcjtcbiAgICB0aGlzLmN1cnJlbnRTdWJqZWN0ID0gbnVsbDtcbiAgICB0aGlzLmNvbXBvdW5kQ291bnQgPSAwO1xuICAgIHRoaXMuZWRnZUNvdW50ID0gMDtcbiAgICB0aGlzLmxlbmd0aCA9IDA7XG5cbiAgICBpZiAoc2VsZWN0b3IgPT0gbnVsbCB8fCBzdHJpbmcoc2VsZWN0b3IpICYmIHNlbGVjdG9yLm1hdGNoKC9eXFxzKiQvKSkgOyBlbHNlIGlmIChlbGVtZW50T3JDb2xsZWN0aW9uKHNlbGVjdG9yKSkge1xuICAgICAgdGhpcy5hZGRRdWVyeSh7XG4gICAgICAgIGNoZWNrczogW3tcbiAgICAgICAgICB0eXBlOiBUeXBlLkNPTExFQ1RJT04sXG4gICAgICAgICAgdmFsdWU6IHNlbGVjdG9yLmNvbGxlY3Rpb24oKVxuICAgICAgICB9XVxuICAgICAgfSk7XG4gICAgfSBlbHNlIGlmIChmbiQ2KHNlbGVjdG9yKSkge1xuICAgICAgdGhpcy5hZGRRdWVyeSh7XG4gICAgICAgIGNoZWNrczogW3tcbiAgICAgICAgICB0eXBlOiBUeXBlLkZJTFRFUixcbiAgICAgICAgICB2YWx1ZTogc2VsZWN0b3JcbiAgICAgICAgfV1cbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoc3RyaW5nKHNlbGVjdG9yKSkge1xuICAgICAgaWYgKCF0aGlzLnBhcnNlKHNlbGVjdG9yKSkge1xuICAgICAgICB0aGlzLmludmFsaWQgPSB0cnVlO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBlcnJvcignQSBzZWxlY3RvciBtdXN0IGJlIGNyZWF0ZWQgZnJvbSBhIHN0cmluZzsgZm91bmQgJyk7XG4gICAgfVxuICB9O1xuXG4gIHZhciBzZWxmbiA9IFNlbGVjdG9yLnByb3RvdHlwZTtcbiAgW3BhcnNlJDEsIG1hdGNoaW5nXS5mb3JFYWNoKGZ1bmN0aW9uIChwKSB7XG4gICAgcmV0dXJuIGV4dGVuZChzZWxmbiwgcCk7XG4gIH0pO1xuXG4gIHNlbGZuLnRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW5wdXRUZXh0O1xuICB9O1xuXG4gIHNlbGZuLnNpemUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMubGVuZ3RoO1xuICB9O1xuXG4gIHNlbGZuLmVxID0gZnVuY3Rpb24gKGkpIHtcbiAgICByZXR1cm4gdGhpc1tpXTtcbiAgfTtcblxuICBzZWxmbi5zYW1lVGV4dCA9IGZ1bmN0aW9uIChvdGhlclNlbCkge1xuICAgIHJldHVybiAhdGhpcy5pbnZhbGlkICYmICFvdGhlclNlbC5pbnZhbGlkICYmIHRoaXMudGV4dCgpID09PSBvdGhlclNlbC50ZXh0KCk7XG4gIH07XG5cbiAgc2VsZm4uYWRkUXVlcnkgPSBmdW5jdGlvbiAocSkge1xuICAgIHRoaXNbdGhpcy5sZW5ndGgrK10gPSBxO1xuICB9O1xuXG4gIHNlbGZuLnNlbGVjdG9yID0gc2VsZm4udG9TdHJpbmc7XG5cbiAgdmFyIGVsZXNmbiRnID0ge1xuICAgIGFsbEFyZTogZnVuY3Rpb24gYWxsQXJlKHNlbGVjdG9yKSB7XG4gICAgICB2YXIgc2VsT2JqID0gbmV3IFNlbGVjdG9yKHNlbGVjdG9yKTtcbiAgICAgIHJldHVybiB0aGlzLmV2ZXJ5KGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgICAgcmV0dXJuIHNlbE9iai5tYXRjaGVzKGVsZSk7XG4gICAgICB9KTtcbiAgICB9LFxuICAgIGlzOiBmdW5jdGlvbiBpcyhzZWxlY3Rvcikge1xuICAgICAgdmFyIHNlbE9iaiA9IG5ldyBTZWxlY3RvcihzZWxlY3Rvcik7XG4gICAgICByZXR1cm4gdGhpcy5zb21lKGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgICAgcmV0dXJuIHNlbE9iai5tYXRjaGVzKGVsZSk7XG4gICAgICB9KTtcbiAgICB9LFxuICAgIHNvbWU6IGZ1bmN0aW9uIHNvbWUoZm4sIHRoaXNBcmcpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgcmV0ID0gIXRoaXNBcmcgPyBmbih0aGlzW2ldLCBpLCB0aGlzKSA6IGZuLmFwcGx5KHRoaXNBcmcsIFt0aGlzW2ldLCBpLCB0aGlzXSk7XG5cbiAgICAgICAgaWYgKHJldCkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9LFxuICAgIGV2ZXJ5OiBmdW5jdGlvbiBldmVyeShmbiwgdGhpc0FyZykge1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciByZXQgPSAhdGhpc0FyZyA/IGZuKHRoaXNbaV0sIGksIHRoaXMpIDogZm4uYXBwbHkodGhpc0FyZywgW3RoaXNbaV0sIGksIHRoaXNdKTtcblxuICAgICAgICBpZiAoIXJldCkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuICAgIHNhbWU6IGZ1bmN0aW9uIHNhbWUoY29sbGVjdGlvbikge1xuICAgICAgLy8gY2hlYXAgY29sbGVjdGlvbiByZWYgY2hlY2tcbiAgICAgIGlmICh0aGlzID09PSBjb2xsZWN0aW9uKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICBjb2xsZWN0aW9uID0gdGhpcy5jeSgpLmNvbGxlY3Rpb24oY29sbGVjdGlvbik7XG4gICAgICB2YXIgdGhpc0xlbmd0aCA9IHRoaXMubGVuZ3RoO1xuICAgICAgdmFyIGNvbGxlY3Rpb25MZW5ndGggPSBjb2xsZWN0aW9uLmxlbmd0aDsgLy8gY2hlYXAgbGVuZ3RoIGNoZWNrXG5cbiAgICAgIGlmICh0aGlzTGVuZ3RoICE9PSBjb2xsZWN0aW9uTGVuZ3RoKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0gLy8gY2hlYXAgZWxlbWVudCByZWYgY2hlY2tcblxuXG4gICAgICBpZiAodGhpc0xlbmd0aCA9PT0gMSkge1xuICAgICAgICByZXR1cm4gdGhpc1swXSA9PT0gY29sbGVjdGlvblswXTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXMuZXZlcnkoZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICByZXR1cm4gY29sbGVjdGlvbi5oYXNFbGVtZW50V2l0aElkKGVsZS5pZCgpKTtcbiAgICAgIH0pO1xuICAgIH0sXG4gICAgYW55U2FtZTogZnVuY3Rpb24gYW55U2FtZShjb2xsZWN0aW9uKSB7XG4gICAgICBjb2xsZWN0aW9uID0gdGhpcy5jeSgpLmNvbGxlY3Rpb24oY29sbGVjdGlvbik7XG4gICAgICByZXR1cm4gdGhpcy5zb21lKGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgICAgcmV0dXJuIGNvbGxlY3Rpb24uaGFzRWxlbWVudFdpdGhJZChlbGUuaWQoKSk7XG4gICAgICB9KTtcbiAgICB9LFxuICAgIGFsbEFyZU5laWdoYm9yczogZnVuY3Rpb24gYWxsQXJlTmVpZ2hib3JzKGNvbGxlY3Rpb24pIHtcbiAgICAgIGNvbGxlY3Rpb24gPSB0aGlzLmN5KCkuY29sbGVjdGlvbihjb2xsZWN0aW9uKTtcbiAgICAgIHZhciBuaG9vZCA9IHRoaXMubmVpZ2hib3Job29kKCk7XG4gICAgICByZXR1cm4gY29sbGVjdGlvbi5ldmVyeShmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgIHJldHVybiBuaG9vZC5oYXNFbGVtZW50V2l0aElkKGVsZS5pZCgpKTtcbiAgICAgIH0pO1xuICAgIH0sXG4gICAgY29udGFpbnM6IGZ1bmN0aW9uIGNvbnRhaW5zKGNvbGxlY3Rpb24pIHtcbiAgICAgIGNvbGxlY3Rpb24gPSB0aGlzLmN5KCkuY29sbGVjdGlvbihjb2xsZWN0aW9uKTtcbiAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgIHJldHVybiBjb2xsZWN0aW9uLmV2ZXJ5KGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgICAgcmV0dXJuIHNlbGYuaGFzRWxlbWVudFdpdGhJZChlbGUuaWQoKSk7XG4gICAgICB9KTtcbiAgICB9XG4gIH07XG4gIGVsZXNmbiRnLmFsbEFyZU5laWdoYm91cnMgPSBlbGVzZm4kZy5hbGxBcmVOZWlnaGJvcnM7XG4gIGVsZXNmbiRnLmhhcyA9IGVsZXNmbiRnLmNvbnRhaW5zO1xuICBlbGVzZm4kZy5lcXVhbCA9IGVsZXNmbiRnLmVxdWFscyA9IGVsZXNmbiRnLnNhbWU7XG5cbiAgdmFyIGNhY2hlID0gZnVuY3Rpb24gY2FjaGUoZm4sIG5hbWUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gdHJhdmVyc2FsQ2FjaGUoYXJnMSwgYXJnMiwgYXJnMywgYXJnNCkge1xuICAgICAgdmFyIHNlbGVjdG9yT3JFbGVzID0gYXJnMTtcbiAgICAgIHZhciBlbGVzID0gdGhpcztcbiAgICAgIHZhciBrZXk7XG5cbiAgICAgIGlmIChzZWxlY3Rvck9yRWxlcyA9PSBudWxsKSB7XG4gICAgICAgIGtleSA9ICcnO1xuICAgICAgfSBlbHNlIGlmIChlbGVtZW50T3JDb2xsZWN0aW9uKHNlbGVjdG9yT3JFbGVzKSAmJiBzZWxlY3Rvck9yRWxlcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAga2V5ID0gc2VsZWN0b3JPckVsZXMuaWQoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGVsZXMubGVuZ3RoID09PSAxICYmIGtleSkge1xuICAgICAgICB2YXIgX3AgPSBlbGVzWzBdLl9wcml2YXRlO1xuICAgICAgICB2YXIgdGNoID0gX3AudHJhdmVyc2FsQ2FjaGUgPSBfcC50cmF2ZXJzYWxDYWNoZSB8fCB7fTtcbiAgICAgICAgdmFyIGNoID0gdGNoW25hbWVdID0gdGNoW25hbWVdIHx8IFtdO1xuICAgICAgICB2YXIgaGFzaCA9IGhhc2hTdHJpbmcoa2V5KTtcbiAgICAgICAgdmFyIGNhY2hlSGl0ID0gY2hbaGFzaF07XG5cbiAgICAgICAgaWYgKGNhY2hlSGl0KSB7XG4gICAgICAgICAgcmV0dXJuIGNhY2hlSGl0O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBjaFtoYXNoXSA9IGZuLmNhbGwoZWxlcywgYXJnMSwgYXJnMiwgYXJnMywgYXJnNCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBmbi5jYWxsKGVsZXMsIGFyZzEsIGFyZzIsIGFyZzMsIGFyZzQpO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgdmFyIGVsZXNmbiRmID0ge1xuICAgIHBhcmVudDogZnVuY3Rpb24gcGFyZW50KHNlbGVjdG9yKSB7XG4gICAgICB2YXIgcGFyZW50cyA9IFtdOyAvLyBvcHRpbWlzYXRpb24gZm9yIHNpbmdsZSBlbGUgY2FsbFxuXG4gICAgICBpZiAodGhpcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgdmFyIHBhcmVudCA9IHRoaXNbMF0uX3ByaXZhdGUucGFyZW50O1xuXG4gICAgICAgIGlmIChwYXJlbnQpIHtcbiAgICAgICAgICByZXR1cm4gcGFyZW50O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWxlID0gdGhpc1tpXTtcbiAgICAgICAgdmFyIF9wYXJlbnQgPSBlbGUuX3ByaXZhdGUucGFyZW50O1xuXG4gICAgICAgIGlmIChfcGFyZW50KSB7XG4gICAgICAgICAgcGFyZW50cy5wdXNoKF9wYXJlbnQpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzLnNwYXduKHBhcmVudHMsIHRydWUpLmZpbHRlcihzZWxlY3Rvcik7XG4gICAgfSxcbiAgICBwYXJlbnRzOiBmdW5jdGlvbiBwYXJlbnRzKHNlbGVjdG9yKSB7XG4gICAgICB2YXIgcGFyZW50cyA9IFtdO1xuICAgICAgdmFyIGVsZXMgPSB0aGlzLnBhcmVudCgpO1xuXG4gICAgICB3aGlsZSAoZWxlcy5ub25lbXB0eSgpKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBlbGUgPSBlbGVzW2ldO1xuICAgICAgICAgIHBhcmVudHMucHVzaChlbGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgZWxlcyA9IGVsZXMucGFyZW50KCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzLnNwYXduKHBhcmVudHMsIHRydWUpLmZpbHRlcihzZWxlY3Rvcik7XG4gICAgfSxcbiAgICBjb21tb25BbmNlc3RvcnM6IGZ1bmN0aW9uIGNvbW1vbkFuY2VzdG9ycyhzZWxlY3Rvcikge1xuICAgICAgdmFyIGFuY2VzdG9ycztcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBlbGUgPSB0aGlzW2ldO1xuICAgICAgICB2YXIgcGFyZW50cyA9IGVsZS5wYXJlbnRzKCk7XG4gICAgICAgIGFuY2VzdG9ycyA9IGFuY2VzdG9ycyB8fCBwYXJlbnRzO1xuICAgICAgICBhbmNlc3RvcnMgPSBhbmNlc3RvcnMuaW50ZXJzZWN0KHBhcmVudHMpOyAvLyBjdXJyZW50IGxpc3QgbXVzdCBiZSBjb21tb24gd2l0aCBjdXJyZW50IGVsZSBwYXJlbnRzIHNldFxuICAgICAgfVxuXG4gICAgICByZXR1cm4gYW5jZXN0b3JzLmZpbHRlcihzZWxlY3Rvcik7XG4gICAgfSxcbiAgICBvcnBoYW5zOiBmdW5jdGlvbiBvcnBoYW5zKHNlbGVjdG9yKSB7XG4gICAgICByZXR1cm4gdGhpcy5zdGRGaWx0ZXIoZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICByZXR1cm4gZWxlLmlzT3JwaGFuKCk7XG4gICAgICB9KS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgIH0sXG4gICAgbm9ub3JwaGFuczogZnVuY3Rpb24gbm9ub3JwaGFucyhzZWxlY3Rvcikge1xuICAgICAgcmV0dXJuIHRoaXMuc3RkRmlsdGVyKGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgICAgcmV0dXJuIGVsZS5pc0NoaWxkKCk7XG4gICAgICB9KS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgIH0sXG4gICAgY2hpbGRyZW46IGNhY2hlKGZ1bmN0aW9uIChzZWxlY3Rvcikge1xuICAgICAgdmFyIGNoaWxkcmVuID0gW107XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWxlID0gdGhpc1tpXTtcbiAgICAgICAgdmFyIGVsZUNoaWxkcmVuID0gZWxlLl9wcml2YXRlLmNoaWxkcmVuO1xuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgZWxlQ2hpbGRyZW4ubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICBjaGlsZHJlbi5wdXNoKGVsZUNoaWxkcmVuW2pdKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcy5zcGF3bihjaGlsZHJlbiwgdHJ1ZSkuZmlsdGVyKHNlbGVjdG9yKTtcbiAgICB9LCAnY2hpbGRyZW4nKSxcbiAgICBzaWJsaW5nczogZnVuY3Rpb24gc2libGluZ3Moc2VsZWN0b3IpIHtcbiAgICAgIHJldHVybiB0aGlzLnBhcmVudCgpLmNoaWxkcmVuKCkubm90KHRoaXMpLmZpbHRlcihzZWxlY3Rvcik7XG4gICAgfSxcbiAgICBpc1BhcmVudDogZnVuY3Rpb24gaXNQYXJlbnQoKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1swXTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICByZXR1cm4gZWxlLmlzTm9kZSgpICYmIGVsZS5fcHJpdmF0ZS5jaGlsZHJlbi5sZW5ndGggIT09IDA7XG4gICAgICB9XG4gICAgfSxcbiAgICBpc0NoaWxkbGVzczogZnVuY3Rpb24gaXNDaGlsZGxlc3MoKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1swXTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICByZXR1cm4gZWxlLmlzTm9kZSgpICYmIGVsZS5fcHJpdmF0ZS5jaGlsZHJlbi5sZW5ndGggPT09IDA7XG4gICAgICB9XG4gICAgfSxcbiAgICBpc0NoaWxkOiBmdW5jdGlvbiBpc0NoaWxkKCkge1xuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICAgIGlmIChlbGUpIHtcbiAgICAgICAgcmV0dXJuIGVsZS5pc05vZGUoKSAmJiBlbGUuX3ByaXZhdGUucGFyZW50ICE9IG51bGw7XG4gICAgICB9XG4gICAgfSxcbiAgICBpc09ycGhhbjogZnVuY3Rpb24gaXNPcnBoYW4oKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1swXTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICByZXR1cm4gZWxlLmlzTm9kZSgpICYmIGVsZS5fcHJpdmF0ZS5wYXJlbnQgPT0gbnVsbDtcbiAgICAgIH1cbiAgICB9LFxuICAgIGRlc2NlbmRhbnRzOiBmdW5jdGlvbiBkZXNjZW5kYW50cyhzZWxlY3Rvcikge1xuICAgICAgdmFyIGVsZW1lbnRzID0gW107XG5cbiAgICAgIGZ1bmN0aW9uIGFkZChlbGVzKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBlbGUgPSBlbGVzW2ldO1xuICAgICAgICAgIGVsZW1lbnRzLnB1c2goZWxlKTtcblxuICAgICAgICAgIGlmIChlbGUuY2hpbGRyZW4oKS5ub25lbXB0eSgpKSB7XG4gICAgICAgICAgICBhZGQoZWxlLmNoaWxkcmVuKCkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBhZGQodGhpcy5jaGlsZHJlbigpKTtcbiAgICAgIHJldHVybiB0aGlzLnNwYXduKGVsZW1lbnRzLCB0cnVlKS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgIH1cbiAgfTtcblxuICBmdW5jdGlvbiBmb3JFYWNoQ29tcG91bmQoZWxlcywgZm4sIGluY2x1ZGVTZWxmLCByZWN1cnNpdmVTdGVwKSB7XG4gICAgdmFyIHEgPSBbXTtcbiAgICB2YXIgZGlkID0gbmV3IFNldCQxKCk7XG4gICAgdmFyIGN5ID0gZWxlcy5jeSgpO1xuICAgIHZhciBoYXNDb21wb3VuZHMgPSBjeS5oYXNDb21wb3VuZE5vZGVzKCk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBlbGUgPSBlbGVzW2ldO1xuXG4gICAgICBpZiAoaW5jbHVkZVNlbGYpIHtcbiAgICAgICAgcS5wdXNoKGVsZSk7XG4gICAgICB9IGVsc2UgaWYgKGhhc0NvbXBvdW5kcykge1xuICAgICAgICByZWN1cnNpdmVTdGVwKHEsIGRpZCwgZWxlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB3aGlsZSAocS5sZW5ndGggPiAwKSB7XG4gICAgICB2YXIgX2VsZSA9IHEuc2hpZnQoKTtcblxuICAgICAgZm4oX2VsZSk7XG4gICAgICBkaWQuYWRkKF9lbGUuaWQoKSk7XG5cbiAgICAgIGlmIChoYXNDb21wb3VuZHMpIHtcbiAgICAgICAgcmVjdXJzaXZlU3RlcChxLCBkaWQsIF9lbGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBlbGVzO1xuICB9XG5cbiAgZnVuY3Rpb24gYWRkQ2hpbGRyZW4ocSwgZGlkLCBlbGUpIHtcbiAgICBpZiAoZWxlLmlzUGFyZW50KCkpIHtcbiAgICAgIHZhciBjaGlsZHJlbiA9IGVsZS5fcHJpdmF0ZS5jaGlsZHJlbjtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgY2hpbGQgPSBjaGlsZHJlbltpXTtcblxuICAgICAgICBpZiAoIWRpZC5oYXMoY2hpbGQuaWQoKSkpIHtcbiAgICAgICAgICBxLnB1c2goY2hpbGQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9IC8vIHZlcnkgZWZmaWNpZW50IHZlcnNpb24gb2YgZWxlcy5hZGQoIGVsZXMuZGVzY2VuZGFudHMoKSApLmZvckVhY2goKVxuICAvLyBmb3IgaW50ZXJuYWwgdXNlXG5cblxuICBlbGVzZm4kZi5mb3JFYWNoRG93biA9IGZ1bmN0aW9uIChmbikge1xuICAgIHZhciBpbmNsdWRlU2VsZiA9IGFyZ3VtZW50cy5sZW5ndGggPiAxICYmIGFyZ3VtZW50c1sxXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzFdIDogdHJ1ZTtcbiAgICByZXR1cm4gZm9yRWFjaENvbXBvdW5kKHRoaXMsIGZuLCBpbmNsdWRlU2VsZiwgYWRkQ2hpbGRyZW4pO1xuICB9O1xuXG4gIGZ1bmN0aW9uIGFkZFBhcmVudChxLCBkaWQsIGVsZSkge1xuICAgIGlmIChlbGUuaXNDaGlsZCgpKSB7XG4gICAgICB2YXIgcGFyZW50ID0gZWxlLl9wcml2YXRlLnBhcmVudDtcblxuICAgICAgaWYgKCFkaWQuaGFzKHBhcmVudC5pZCgpKSkge1xuICAgICAgICBxLnB1c2gocGFyZW50KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBlbGVzZm4kZi5mb3JFYWNoVXAgPSBmdW5jdGlvbiAoZm4pIHtcbiAgICB2YXIgaW5jbHVkZVNlbGYgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IHRydWU7XG4gICAgcmV0dXJuIGZvckVhY2hDb21wb3VuZCh0aGlzLCBmbiwgaW5jbHVkZVNlbGYsIGFkZFBhcmVudCk7XG4gIH07XG5cbiAgZnVuY3Rpb24gYWRkUGFyZW50QW5kQ2hpbGRyZW4ocSwgZGlkLCBlbGUpIHtcbiAgICBhZGRQYXJlbnQocSwgZGlkLCBlbGUpO1xuICAgIGFkZENoaWxkcmVuKHEsIGRpZCwgZWxlKTtcbiAgfVxuXG4gIGVsZXNmbiRmLmZvckVhY2hVcEFuZERvd24gPSBmdW5jdGlvbiAoZm4pIHtcbiAgICB2YXIgaW5jbHVkZVNlbGYgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IHRydWU7XG4gICAgcmV0dXJuIGZvckVhY2hDb21wb3VuZCh0aGlzLCBmbiwgaW5jbHVkZVNlbGYsIGFkZFBhcmVudEFuZENoaWxkcmVuKTtcbiAgfTsgLy8gYWxpYXNlc1xuXG5cbiAgZWxlc2ZuJGYuYW5jZXN0b3JzID0gZWxlc2ZuJGYucGFyZW50cztcblxuICB2YXIgZm4kNSwgZWxlc2ZuJGU7XG4gIGZuJDUgPSBlbGVzZm4kZSA9IHtcbiAgICBkYXRhOiBkZWZpbmUuZGF0YSh7XG4gICAgICBmaWVsZDogJ2RhdGEnLFxuICAgICAgYmluZGluZ0V2ZW50OiAnZGF0YScsXG4gICAgICBhbGxvd0JpbmRpbmc6IHRydWUsXG4gICAgICBhbGxvd1NldHRpbmc6IHRydWUsXG4gICAgICBzZXR0aW5nRXZlbnQ6ICdkYXRhJyxcbiAgICAgIHNldHRpbmdUcmlnZ2Vyc0V2ZW50OiB0cnVlLFxuICAgICAgdHJpZ2dlckZuTmFtZTogJ3RyaWdnZXInLFxuICAgICAgYWxsb3dHZXR0aW5nOiB0cnVlLFxuICAgICAgaW1tdXRhYmxlS2V5czoge1xuICAgICAgICAnaWQnOiB0cnVlLFxuICAgICAgICAnc291cmNlJzogdHJ1ZSxcbiAgICAgICAgJ3RhcmdldCc6IHRydWUsXG4gICAgICAgICdwYXJlbnQnOiB0cnVlXG4gICAgICB9LFxuICAgICAgdXBkYXRlU3R5bGU6IHRydWVcbiAgICB9KSxcbiAgICByZW1vdmVEYXRhOiBkZWZpbmUucmVtb3ZlRGF0YSh7XG4gICAgICBmaWVsZDogJ2RhdGEnLFxuICAgICAgZXZlbnQ6ICdkYXRhJyxcbiAgICAgIHRyaWdnZXJGbk5hbWU6ICd0cmlnZ2VyJyxcbiAgICAgIHRyaWdnZXJFdmVudDogdHJ1ZSxcbiAgICAgIGltbXV0YWJsZUtleXM6IHtcbiAgICAgICAgJ2lkJzogdHJ1ZSxcbiAgICAgICAgJ3NvdXJjZSc6IHRydWUsXG4gICAgICAgICd0YXJnZXQnOiB0cnVlLFxuICAgICAgICAncGFyZW50JzogdHJ1ZVxuICAgICAgfSxcbiAgICAgIHVwZGF0ZVN0eWxlOiB0cnVlXG4gICAgfSksXG4gICAgc2NyYXRjaDogZGVmaW5lLmRhdGEoe1xuICAgICAgZmllbGQ6ICdzY3JhdGNoJyxcbiAgICAgIGJpbmRpbmdFdmVudDogJ3NjcmF0Y2gnLFxuICAgICAgYWxsb3dCaW5kaW5nOiB0cnVlLFxuICAgICAgYWxsb3dTZXR0aW5nOiB0cnVlLFxuICAgICAgc2V0dGluZ0V2ZW50OiAnc2NyYXRjaCcsXG4gICAgICBzZXR0aW5nVHJpZ2dlcnNFdmVudDogdHJ1ZSxcbiAgICAgIHRyaWdnZXJGbk5hbWU6ICd0cmlnZ2VyJyxcbiAgICAgIGFsbG93R2V0dGluZzogdHJ1ZSxcbiAgICAgIHVwZGF0ZVN0eWxlOiB0cnVlXG4gICAgfSksXG4gICAgcmVtb3ZlU2NyYXRjaDogZGVmaW5lLnJlbW92ZURhdGEoe1xuICAgICAgZmllbGQ6ICdzY3JhdGNoJyxcbiAgICAgIGV2ZW50OiAnc2NyYXRjaCcsXG4gICAgICB0cmlnZ2VyRm5OYW1lOiAndHJpZ2dlcicsXG4gICAgICB0cmlnZ2VyRXZlbnQ6IHRydWUsXG4gICAgICB1cGRhdGVTdHlsZTogdHJ1ZVxuICAgIH0pLFxuICAgIHJzY3JhdGNoOiBkZWZpbmUuZGF0YSh7XG4gICAgICBmaWVsZDogJ3JzY3JhdGNoJyxcbiAgICAgIGFsbG93QmluZGluZzogZmFsc2UsXG4gICAgICBhbGxvd1NldHRpbmc6IHRydWUsXG4gICAgICBzZXR0aW5nVHJpZ2dlcnNFdmVudDogZmFsc2UsXG4gICAgICBhbGxvd0dldHRpbmc6IHRydWVcbiAgICB9KSxcbiAgICByZW1vdmVSc2NyYXRjaDogZGVmaW5lLnJlbW92ZURhdGEoe1xuICAgICAgZmllbGQ6ICdyc2NyYXRjaCcsXG4gICAgICB0cmlnZ2VyRXZlbnQ6IGZhbHNlXG4gICAgfSksXG4gICAgaWQ6IGZ1bmN0aW9uIGlkKCkge1xuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICAgIGlmIChlbGUpIHtcbiAgICAgICAgcmV0dXJuIGVsZS5fcHJpdmF0ZS5kYXRhLmlkO1xuICAgICAgfVxuICAgIH1cbiAgfTsgLy8gYWxpYXNlc1xuXG4gIGZuJDUuYXR0ciA9IGZuJDUuZGF0YTtcbiAgZm4kNS5yZW1vdmVBdHRyID0gZm4kNS5yZW1vdmVEYXRhO1xuICB2YXIgZGF0YSA9IGVsZXNmbiRlO1xuXG4gIHZhciBlbGVzZm4kZCA9IHt9O1xuXG4gIGZ1bmN0aW9uIGRlZmluZURlZ3JlZUZ1bmN0aW9uKGNhbGxiYWNrKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIChpbmNsdWRlTG9vcHMpIHtcbiAgICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgICAgaWYgKGluY2x1ZGVMb29wcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGluY2x1ZGVMb29wcyA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIGlmIChzZWxmLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChzZWxmLmlzTm9kZSgpICYmICFzZWxmLnJlbW92ZWQoKSkge1xuICAgICAgICB2YXIgZGVncmVlID0gMDtcbiAgICAgICAgdmFyIG5vZGUgPSBzZWxmWzBdO1xuICAgICAgICB2YXIgY29ubmVjdGVkRWRnZXMgPSBub2RlLl9wcml2YXRlLmVkZ2VzO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY29ubmVjdGVkRWRnZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWRnZSA9IGNvbm5lY3RlZEVkZ2VzW2ldO1xuXG4gICAgICAgICAgaWYgKCFpbmNsdWRlTG9vcHMgJiYgZWRnZS5pc0xvb3AoKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZGVncmVlICs9IGNhbGxiYWNrKG5vZGUsIGVkZ2UpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGRlZ3JlZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgZXh0ZW5kKGVsZXNmbiRkLCB7XG4gICAgZGVncmVlOiBkZWZpbmVEZWdyZWVGdW5jdGlvbihmdW5jdGlvbiAobm9kZSwgZWRnZSkge1xuICAgICAgaWYgKGVkZ2Uuc291cmNlKCkuc2FtZShlZGdlLnRhcmdldCgpKSkge1xuICAgICAgICByZXR1cm4gMjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfVxuICAgIH0pLFxuICAgIGluZGVncmVlOiBkZWZpbmVEZWdyZWVGdW5jdGlvbihmdW5jdGlvbiAobm9kZSwgZWRnZSkge1xuICAgICAgaWYgKGVkZ2UudGFyZ2V0KCkuc2FtZShub2RlKSkge1xuICAgICAgICByZXR1cm4gMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH0pLFxuICAgIG91dGRlZ3JlZTogZGVmaW5lRGVncmVlRnVuY3Rpb24oZnVuY3Rpb24gKG5vZGUsIGVkZ2UpIHtcbiAgICAgIGlmIChlZGdlLnNvdXJjZSgpLnNhbWUobm9kZSkpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gMDtcbiAgICAgIH1cbiAgICB9KVxuICB9KTtcblxuICBmdW5jdGlvbiBkZWZpbmVEZWdyZWVCb3VuZHNGdW5jdGlvbihkZWdyZWVGbiwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKGluY2x1ZGVMb29wcykge1xuICAgICAgdmFyIHJldDtcbiAgICAgIHZhciBub2RlcyA9IHRoaXMubm9kZXMoKTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWxlID0gbm9kZXNbaV07XG4gICAgICAgIHZhciBkZWdyZWUgPSBlbGVbZGVncmVlRm5dKGluY2x1ZGVMb29wcyk7XG5cbiAgICAgICAgaWYgKGRlZ3JlZSAhPT0gdW5kZWZpbmVkICYmIChyZXQgPT09IHVuZGVmaW5lZCB8fCBjYWxsYmFjayhkZWdyZWUsIHJldCkpKSB7XG4gICAgICAgICAgcmV0ID0gZGVncmVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZXQ7XG4gICAgfTtcbiAgfVxuXG4gIGV4dGVuZChlbGVzZm4kZCwge1xuICAgIG1pbkRlZ3JlZTogZGVmaW5lRGVncmVlQm91bmRzRnVuY3Rpb24oJ2RlZ3JlZScsIGZ1bmN0aW9uIChkZWdyZWUsIG1pbikge1xuICAgICAgcmV0dXJuIGRlZ3JlZSA8IG1pbjtcbiAgICB9KSxcbiAgICBtYXhEZWdyZWU6IGRlZmluZURlZ3JlZUJvdW5kc0Z1bmN0aW9uKCdkZWdyZWUnLCBmdW5jdGlvbiAoZGVncmVlLCBtYXgpIHtcbiAgICAgIHJldHVybiBkZWdyZWUgPiBtYXg7XG4gICAgfSksXG4gICAgbWluSW5kZWdyZWU6IGRlZmluZURlZ3JlZUJvdW5kc0Z1bmN0aW9uKCdpbmRlZ3JlZScsIGZ1bmN0aW9uIChkZWdyZWUsIG1pbikge1xuICAgICAgcmV0dXJuIGRlZ3JlZSA8IG1pbjtcbiAgICB9KSxcbiAgICBtYXhJbmRlZ3JlZTogZGVmaW5lRGVncmVlQm91bmRzRnVuY3Rpb24oJ2luZGVncmVlJywgZnVuY3Rpb24gKGRlZ3JlZSwgbWF4KSB7XG4gICAgICByZXR1cm4gZGVncmVlID4gbWF4O1xuICAgIH0pLFxuICAgIG1pbk91dGRlZ3JlZTogZGVmaW5lRGVncmVlQm91bmRzRnVuY3Rpb24oJ291dGRlZ3JlZScsIGZ1bmN0aW9uIChkZWdyZWUsIG1pbikge1xuICAgICAgcmV0dXJuIGRlZ3JlZSA8IG1pbjtcbiAgICB9KSxcbiAgICBtYXhPdXRkZWdyZWU6IGRlZmluZURlZ3JlZUJvdW5kc0Z1bmN0aW9uKCdvdXRkZWdyZWUnLCBmdW5jdGlvbiAoZGVncmVlLCBtYXgpIHtcbiAgICAgIHJldHVybiBkZWdyZWUgPiBtYXg7XG4gICAgfSlcbiAgfSk7XG4gIGV4dGVuZChlbGVzZm4kZCwge1xuICAgIHRvdGFsRGVncmVlOiBmdW5jdGlvbiB0b3RhbERlZ3JlZShpbmNsdWRlTG9vcHMpIHtcbiAgICAgIHZhciB0b3RhbCA9IDA7XG4gICAgICB2YXIgbm9kZXMgPSB0aGlzLm5vZGVzKCk7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdG90YWwgKz0gbm9kZXNbaV0uZGVncmVlKGluY2x1ZGVMb29wcyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0b3RhbDtcbiAgICB9XG4gIH0pO1xuXG4gIHZhciBmbiQ0LCBlbGVzZm4kYztcblxuICB2YXIgYmVmb3JlUG9zaXRpb25TZXQgPSBmdW5jdGlvbiBiZWZvcmVQb3NpdGlvblNldChlbGVzLCBuZXdQb3MsIHNpbGVudCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG5cbiAgICAgIGlmICghZWxlLmxvY2tlZCgpKSB7XG4gICAgICAgIHZhciBvbGRQb3MgPSBlbGUuX3ByaXZhdGUucG9zaXRpb247XG4gICAgICAgIHZhciBkZWx0YSA9IHtcbiAgICAgICAgICB4OiBuZXdQb3MueCAhPSBudWxsID8gbmV3UG9zLnggLSBvbGRQb3MueCA6IDAsXG4gICAgICAgICAgeTogbmV3UG9zLnkgIT0gbnVsbCA/IG5ld1Bvcy55IC0gb2xkUG9zLnkgOiAwXG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKGVsZS5pc1BhcmVudCgpICYmICEoZGVsdGEueCA9PT0gMCAmJiBkZWx0YS55ID09PSAwKSkge1xuICAgICAgICAgIGVsZS5jaGlsZHJlbigpLnNoaWZ0KGRlbHRhLCBzaWxlbnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgZWxlLmRpcnR5Qm91bmRpbmdCb3hDYWNoZSgpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICB2YXIgcG9zaXRpb25EZWYgPSB7XG4gICAgZmllbGQ6ICdwb3NpdGlvbicsXG4gICAgYmluZGluZ0V2ZW50OiAncG9zaXRpb24nLFxuICAgIGFsbG93QmluZGluZzogdHJ1ZSxcbiAgICBhbGxvd1NldHRpbmc6IHRydWUsXG4gICAgc2V0dGluZ0V2ZW50OiAncG9zaXRpb24nLFxuICAgIHNldHRpbmdUcmlnZ2Vyc0V2ZW50OiB0cnVlLFxuICAgIHRyaWdnZXJGbk5hbWU6ICdlbWl0QW5kTm90aWZ5JyxcbiAgICBhbGxvd0dldHRpbmc6IHRydWUsXG4gICAgdmFsaWRLZXlzOiBbJ3gnLCAneSddLFxuICAgIGJlZm9yZUdldDogZnVuY3Rpb24gYmVmb3JlR2V0KGVsZSkge1xuICAgICAgZWxlLnVwZGF0ZUNvbXBvdW5kQm91bmRzKCk7XG4gICAgfSxcbiAgICBiZWZvcmVTZXQ6IGZ1bmN0aW9uIGJlZm9yZVNldChlbGVzLCBuZXdQb3MpIHtcbiAgICAgIGJlZm9yZVBvc2l0aW9uU2V0KGVsZXMsIG5ld1BvcywgZmFsc2UpO1xuICAgIH0sXG4gICAgb25TZXQ6IGZ1bmN0aW9uIG9uU2V0KGVsZXMpIHtcbiAgICAgIGVsZXMuZGlydHlDb21wb3VuZEJvdW5kc0NhY2hlKCk7XG4gICAgfSxcbiAgICBjYW5TZXQ6IGZ1bmN0aW9uIGNhblNldChlbGUpIHtcbiAgICAgIHJldHVybiAhZWxlLmxvY2tlZCgpO1xuICAgIH1cbiAgfTtcbiAgZm4kNCA9IGVsZXNmbiRjID0ge1xuICAgIHBvc2l0aW9uOiBkZWZpbmUuZGF0YShwb3NpdGlvbkRlZiksXG4gICAgLy8gcG9zaXRpb24gYnV0IG5vIG5vdGlmaWNhdGlvbiB0byByZW5kZXJlclxuICAgIHNpbGVudFBvc2l0aW9uOiBkZWZpbmUuZGF0YShleHRlbmQoe30sIHBvc2l0aW9uRGVmLCB7XG4gICAgICBhbGxvd0JpbmRpbmc6IGZhbHNlLFxuICAgICAgYWxsb3dTZXR0aW5nOiB0cnVlLFxuICAgICAgc2V0dGluZ1RyaWdnZXJzRXZlbnQ6IGZhbHNlLFxuICAgICAgYWxsb3dHZXR0aW5nOiBmYWxzZSxcbiAgICAgIGJlZm9yZVNldDogZnVuY3Rpb24gYmVmb3JlU2V0KGVsZXMsIG5ld1Bvcykge1xuICAgICAgICBiZWZvcmVQb3NpdGlvblNldChlbGVzLCBuZXdQb3MsIHRydWUpO1xuICAgICAgfSxcbiAgICAgIG9uU2V0OiBmdW5jdGlvbiBvblNldChlbGVzKSB7XG4gICAgICAgIGVsZXMuZGlydHlDb21wb3VuZEJvdW5kc0NhY2hlKCk7XG4gICAgICB9XG4gICAgfSkpLFxuICAgIHBvc2l0aW9uczogZnVuY3Rpb24gcG9zaXRpb25zKHBvcywgc2lsZW50KSB7XG4gICAgICBpZiAocGxhaW5PYmplY3QocG9zKSkge1xuICAgICAgICBpZiAoc2lsZW50KSB7XG4gICAgICAgICAgdGhpcy5zaWxlbnRQb3NpdGlvbihwb3MpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMucG9zaXRpb24ocG9zKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChmbiQ2KHBvcykpIHtcbiAgICAgICAgdmFyIF9mbiA9IHBvcztcbiAgICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuICAgICAgICBjeS5zdGFydEJhdGNoKCk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG5cbiAgICAgICAgICB2YXIgX3BvcyA9IHZvaWQgMDtcblxuICAgICAgICAgIGlmIChfcG9zID0gX2ZuKGVsZSwgaSkpIHtcbiAgICAgICAgICAgIGlmIChzaWxlbnQpIHtcbiAgICAgICAgICAgICAgZWxlLnNpbGVudFBvc2l0aW9uKF9wb3MpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgZWxlLnBvc2l0aW9uKF9wb3MpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGN5LmVuZEJhdGNoKCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICAgIH0sXG4gICAgc2lsZW50UG9zaXRpb25zOiBmdW5jdGlvbiBzaWxlbnRQb3NpdGlvbnMocG9zKSB7XG4gICAgICByZXR1cm4gdGhpcy5wb3NpdGlvbnMocG9zLCB0cnVlKTtcbiAgICB9LFxuICAgIHNoaWZ0OiBmdW5jdGlvbiBzaGlmdChkaW0sIHZhbCwgc2lsZW50KSB7XG4gICAgICB2YXIgZGVsdGE7XG5cbiAgICAgIGlmIChwbGFpbk9iamVjdChkaW0pKSB7XG4gICAgICAgIGRlbHRhID0ge1xuICAgICAgICAgIHg6IG51bWJlciQxKGRpbS54KSA/IGRpbS54IDogMCxcbiAgICAgICAgICB5OiBudW1iZXIkMShkaW0ueSkgPyBkaW0ueSA6IDBcbiAgICAgICAgfTtcbiAgICAgICAgc2lsZW50ID0gdmFsO1xuICAgICAgfSBlbHNlIGlmIChzdHJpbmcoZGltKSAmJiBudW1iZXIkMSh2YWwpKSB7XG4gICAgICAgIGRlbHRhID0ge1xuICAgICAgICAgIHg6IDAsXG4gICAgICAgICAgeTogMFxuICAgICAgICB9O1xuICAgICAgICBkZWx0YVtkaW1dID0gdmFsO1xuICAgICAgfVxuXG4gICAgICBpZiAoZGVsdGEgIT0gbnVsbCkge1xuICAgICAgICB2YXIgY3kgPSB0aGlzLmN5KCk7XG4gICAgICAgIGN5LnN0YXJ0QmF0Y2goKTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWxlID0gdGhpc1tpXTsgLy8gZXhjbHVkZSBhbnkgbm9kZSB0aGF0IGlzIGEgZGVzY2VuZGFudCBvZiB0aGUgY2FsbGluZyBjb2xsZWN0aW9uXG5cbiAgICAgICAgICBpZiAoY3kuaGFzQ29tcG91bmROb2RlcygpICYmIGVsZS5pc0NoaWxkKCkgJiYgZWxlLmFuY2VzdG9ycygpLmFueVNhbWUodGhpcykpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHZhciBwb3MgPSBlbGUucG9zaXRpb24oKTtcbiAgICAgICAgICB2YXIgbmV3UG9zID0ge1xuICAgICAgICAgICAgeDogcG9zLnggKyBkZWx0YS54LFxuICAgICAgICAgICAgeTogcG9zLnkgKyBkZWx0YS55XG4gICAgICAgICAgfTtcblxuICAgICAgICAgIGlmIChzaWxlbnQpIHtcbiAgICAgICAgICAgIGVsZS5zaWxlbnRQb3NpdGlvbihuZXdQb3MpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBlbGUucG9zaXRpb24obmV3UG9zKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjeS5lbmRCYXRjaCgpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIHNpbGVudFNoaWZ0OiBmdW5jdGlvbiBzaWxlbnRTaGlmdChkaW0sIHZhbCkge1xuICAgICAgaWYgKHBsYWluT2JqZWN0KGRpbSkpIHtcbiAgICAgICAgdGhpcy5zaGlmdChkaW0sIHRydWUpO1xuICAgICAgfSBlbHNlIGlmIChzdHJpbmcoZGltKSAmJiBudW1iZXIkMSh2YWwpKSB7XG4gICAgICAgIHRoaXMuc2hpZnQoZGltLCB2YWwsIHRydWUpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIC8vIGdldC9zZXQgdGhlIHJlbmRlcmVkIChpLmUuIG9uIHNjcmVlbikgcG9zaXRvbiBvZiB0aGUgZWxlbWVudFxuICAgIHJlbmRlcmVkUG9zaXRpb246IGZ1bmN0aW9uIHJlbmRlcmVkUG9zaXRpb24oZGltLCB2YWwpIHtcbiAgICAgIHZhciBlbGUgPSB0aGlzWzBdO1xuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuICAgICAgdmFyIHpvb20gPSBjeS56b29tKCk7XG4gICAgICB2YXIgcGFuID0gY3kucGFuKCk7XG4gICAgICB2YXIgcnBvcyA9IHBsYWluT2JqZWN0KGRpbSkgPyBkaW0gOiB1bmRlZmluZWQ7XG4gICAgICB2YXIgc2V0dGluZyA9IHJwb3MgIT09IHVuZGVmaW5lZCB8fCB2YWwgIT09IHVuZGVmaW5lZCAmJiBzdHJpbmcoZGltKTtcblxuICAgICAgaWYgKGVsZSAmJiBlbGUuaXNOb2RlKCkpIHtcbiAgICAgICAgLy8gbXVzdCBoYXZlIGFuIGVsZW1lbnQgYW5kIG11c3QgYmUgYSBub2RlIHRvIHJldHVybiBwb3NpdGlvblxuICAgICAgICBpZiAoc2V0dGluZykge1xuICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIF9lbGUgPSB0aGlzW2ldO1xuXG4gICAgICAgICAgICBpZiAodmFsICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgLy8gc2V0IG9uZSBkaW1lbnNpb25cbiAgICAgICAgICAgICAgX2VsZS5wb3NpdGlvbihkaW0sICh2YWwgLSBwYW5bZGltXSkgLyB6b29tKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAocnBvcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIC8vIHNldCB3aG9sZSBwb3NpdGlvblxuICAgICAgICAgICAgICBfZWxlLnBvc2l0aW9uKHJlbmRlcmVkVG9Nb2RlbFBvc2l0aW9uKHJwb3MsIHpvb20sIHBhbikpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBnZXR0aW5nXG4gICAgICAgICAgdmFyIHBvcyA9IGVsZS5wb3NpdGlvbigpO1xuICAgICAgICAgIHJwb3MgPSBtb2RlbFRvUmVuZGVyZWRQb3NpdGlvbihwb3MsIHpvb20sIHBhbik7XG5cbiAgICAgICAgICBpZiAoZGltID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIHRoZW4gcmV0dXJuIHRoZSB3aG9sZSByZW5kZXJlZCBwb3NpdGlvblxuICAgICAgICAgICAgcmV0dXJuIHJwb3M7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIHRoZW4gcmV0dXJuIHRoZSBzcGVjaWZpZWQgZGltZW5zaW9uXG4gICAgICAgICAgICByZXR1cm4gcnBvc1tkaW1dO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICghc2V0dGluZykge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkOyAvLyBmb3IgZW1wdHkgY29sbGVjdGlvbiBjYXNlXG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICAgIH0sXG4gICAgLy8gZ2V0L3NldCB0aGUgcG9zaXRpb24gcmVsYXRpdmUgdG8gdGhlIHBhcmVudFxuICAgIHJlbGF0aXZlUG9zaXRpb246IGZ1bmN0aW9uIHJlbGF0aXZlUG9zaXRpb24oZGltLCB2YWwpIHtcbiAgICAgIHZhciBlbGUgPSB0aGlzWzBdO1xuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuICAgICAgdmFyIHBwb3MgPSBwbGFpbk9iamVjdChkaW0pID8gZGltIDogdW5kZWZpbmVkO1xuICAgICAgdmFyIHNldHRpbmcgPSBwcG9zICE9PSB1bmRlZmluZWQgfHwgdmFsICE9PSB1bmRlZmluZWQgJiYgc3RyaW5nKGRpbSk7XG4gICAgICB2YXIgaGFzQ29tcG91bmROb2RlcyA9IGN5Lmhhc0NvbXBvdW5kTm9kZXMoKTtcblxuICAgICAgaWYgKGVsZSAmJiBlbGUuaXNOb2RlKCkpIHtcbiAgICAgICAgLy8gbXVzdCBoYXZlIGFuIGVsZW1lbnQgYW5kIG11c3QgYmUgYSBub2RlIHRvIHJldHVybiBwb3NpdGlvblxuICAgICAgICBpZiAoc2V0dGluZykge1xuICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIF9lbGUyID0gdGhpc1tpXTtcbiAgICAgICAgICAgIHZhciBwYXJlbnQgPSBoYXNDb21wb3VuZE5vZGVzID8gX2VsZTIucGFyZW50KCkgOiBudWxsO1xuICAgICAgICAgICAgdmFyIGhhc1BhcmVudCA9IHBhcmVudCAmJiBwYXJlbnQubGVuZ3RoID4gMDtcbiAgICAgICAgICAgIHZhciByZWxhdGl2ZVRvUGFyZW50ID0gaGFzUGFyZW50O1xuXG4gICAgICAgICAgICBpZiAoaGFzUGFyZW50KSB7XG4gICAgICAgICAgICAgIHBhcmVudCA9IHBhcmVudFswXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9yaWdpbiA9IHJlbGF0aXZlVG9QYXJlbnQgPyBwYXJlbnQucG9zaXRpb24oKSA6IHtcbiAgICAgICAgICAgICAgeDogMCxcbiAgICAgICAgICAgICAgeTogMFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKHZhbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIC8vIHNldCBvbmUgZGltZW5zaW9uXG4gICAgICAgICAgICAgIF9lbGUyLnBvc2l0aW9uKGRpbSwgdmFsICsgb3JpZ2luW2RpbV0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChwcG9zICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgLy8gc2V0IHdob2xlIHBvc2l0aW9uXG4gICAgICAgICAgICAgIF9lbGUyLnBvc2l0aW9uKHtcbiAgICAgICAgICAgICAgICB4OiBwcG9zLnggKyBvcmlnaW4ueCxcbiAgICAgICAgICAgICAgICB5OiBwcG9zLnkgKyBvcmlnaW4ueVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gZ2V0dGluZ1xuICAgICAgICAgIHZhciBwb3MgPSBlbGUucG9zaXRpb24oKTtcblxuICAgICAgICAgIHZhciBfcGFyZW50ID0gaGFzQ29tcG91bmROb2RlcyA/IGVsZS5wYXJlbnQoKSA6IG51bGw7XG5cbiAgICAgICAgICB2YXIgX2hhc1BhcmVudCA9IF9wYXJlbnQgJiYgX3BhcmVudC5sZW5ndGggPiAwO1xuXG4gICAgICAgICAgdmFyIF9yZWxhdGl2ZVRvUGFyZW50ID0gX2hhc1BhcmVudDtcblxuICAgICAgICAgIGlmIChfaGFzUGFyZW50KSB7XG4gICAgICAgICAgICBfcGFyZW50ID0gX3BhcmVudFswXTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB2YXIgX29yaWdpbiA9IF9yZWxhdGl2ZVRvUGFyZW50ID8gX3BhcmVudC5wb3NpdGlvbigpIDoge1xuICAgICAgICAgICAgeDogMCxcbiAgICAgICAgICAgIHk6IDBcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgcHBvcyA9IHtcbiAgICAgICAgICAgIHg6IHBvcy54IC0gX29yaWdpbi54LFxuICAgICAgICAgICAgeTogcG9zLnkgLSBfb3JpZ2luLnlcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgaWYgKGRpbSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAvLyB0aGVuIHJldHVybiB0aGUgd2hvbGUgcmVuZGVyZWQgcG9zaXRpb25cbiAgICAgICAgICAgIHJldHVybiBwcG9zO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyB0aGVuIHJldHVybiB0aGUgc3BlY2lmaWVkIGRpbWVuc2lvblxuICAgICAgICAgICAgcmV0dXJuIHBwb3NbZGltXTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoIXNldHRpbmcpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDsgLy8gZm9yIGVtcHR5IGNvbGxlY3Rpb24gY2FzZVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgICB9XG4gIH07IC8vIGFsaWFzZXNcblxuICBmbiQ0Lm1vZGVsUG9zaXRpb24gPSBmbiQ0LnBvaW50ID0gZm4kNC5wb3NpdGlvbjtcbiAgZm4kNC5tb2RlbFBvc2l0aW9ucyA9IGZuJDQucG9pbnRzID0gZm4kNC5wb3NpdGlvbnM7XG4gIGZuJDQucmVuZGVyZWRQb2ludCA9IGZuJDQucmVuZGVyZWRQb3NpdGlvbjtcbiAgZm4kNC5yZWxhdGl2ZVBvaW50ID0gZm4kNC5yZWxhdGl2ZVBvc2l0aW9uO1xuICB2YXIgcG9zaXRpb24gPSBlbGVzZm4kYztcblxuICB2YXIgZm4kMywgZWxlc2ZuJGI7XG4gIGZuJDMgPSBlbGVzZm4kYiA9IHt9O1xuXG4gIGVsZXNmbiRiLnJlbmRlcmVkQm91bmRpbmdCb3ggPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHZhciBiYiA9IHRoaXMuYm91bmRpbmdCb3gob3B0aW9ucyk7XG4gICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuICAgIHZhciB6b29tID0gY3kuem9vbSgpO1xuICAgIHZhciBwYW4gPSBjeS5wYW4oKTtcbiAgICB2YXIgeDEgPSBiYi54MSAqIHpvb20gKyBwYW4ueDtcbiAgICB2YXIgeDIgPSBiYi54MiAqIHpvb20gKyBwYW4ueDtcbiAgICB2YXIgeTEgPSBiYi55MSAqIHpvb20gKyBwYW4ueTtcbiAgICB2YXIgeTIgPSBiYi55MiAqIHpvb20gKyBwYW4ueTtcbiAgICByZXR1cm4ge1xuICAgICAgeDE6IHgxLFxuICAgICAgeDI6IHgyLFxuICAgICAgeTE6IHkxLFxuICAgICAgeTI6IHkyLFxuICAgICAgdzogeDIgLSB4MSxcbiAgICAgIGg6IHkyIC0geTFcbiAgICB9O1xuICB9O1xuXG4gIGVsZXNmbiRiLmRpcnR5Q29tcG91bmRCb3VuZHNDYWNoZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2lsZW50ID0gYXJndW1lbnRzLmxlbmd0aCA+IDAgJiYgYXJndW1lbnRzWzBdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMF0gOiBmYWxzZTtcbiAgICB2YXIgY3kgPSB0aGlzLmN5KCk7XG5cbiAgICBpZiAoIWN5LnN0eWxlRW5hYmxlZCgpIHx8ICFjeS5oYXNDb21wb3VuZE5vZGVzKCkpIHtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHRoaXMuZm9yRWFjaFVwKGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgIGlmIChlbGUuaXNQYXJlbnQoKSkge1xuICAgICAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG4gICAgICAgIF9wLmNvbXBvdW5kQm91bmRzQ2xlYW4gPSBmYWxzZTtcbiAgICAgICAgX3AuYmJDYWNoZSA9IG51bGw7XG5cbiAgICAgICAgaWYgKCFzaWxlbnQpIHtcbiAgICAgICAgICBlbGUuZW1pdEFuZE5vdGlmeSgnYm91bmRzJyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfTtcblxuICBlbGVzZm4kYi51cGRhdGVDb21wb3VuZEJvdW5kcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZm9yY2UgPSBhcmd1bWVudHMubGVuZ3RoID4gMCAmJiBhcmd1bWVudHNbMF0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1swXSA6IGZhbHNlO1xuICAgIHZhciBjeSA9IHRoaXMuY3koKTsgLy8gbm90IHBvc3NpYmxlIHRvIGRvIG9uIG5vbi1jb21wb3VuZCBncmFwaHMgb3Igd2l0aCB0aGUgc3R5bGUgZGlzYWJsZWRcblxuICAgIGlmICghY3kuc3R5bGVFbmFibGVkKCkgfHwgIWN5Lmhhc0NvbXBvdW5kTm9kZXMoKSkge1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSAvLyBzYXZlIGN5Y2xlcyB3aGVuIGJhdGNoaW5nIC0tIGJ1dCBib3VuZHMgd2lsbCBiZSBzdGFsZSAob3Igbm90IGV4aXN0IHlldClcblxuXG4gICAgaWYgKCFmb3JjZSAmJiBjeS5iYXRjaGluZygpKSB7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB1cGRhdGUocGFyZW50KSB7XG4gICAgICBpZiAoIXBhcmVudC5pc1BhcmVudCgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIF9wID0gcGFyZW50Ll9wcml2YXRlO1xuICAgICAgdmFyIGNoaWxkcmVuID0gcGFyZW50LmNoaWxkcmVuKCk7XG4gICAgICB2YXIgaW5jbHVkZUxhYmVscyA9IHBhcmVudC5wc3R5bGUoJ2NvbXBvdW5kLXNpemluZy13cnQtbGFiZWxzJykudmFsdWUgPT09ICdpbmNsdWRlJztcbiAgICAgIHZhciBtaW4gPSB7XG4gICAgICAgIHdpZHRoOiB7XG4gICAgICAgICAgdmFsOiBwYXJlbnQucHN0eWxlKCdtaW4td2lkdGgnKS5wZlZhbHVlLFxuICAgICAgICAgIGxlZnQ6IHBhcmVudC5wc3R5bGUoJ21pbi13aWR0aC1iaWFzLWxlZnQnKSxcbiAgICAgICAgICByaWdodDogcGFyZW50LnBzdHlsZSgnbWluLXdpZHRoLWJpYXMtcmlnaHQnKVxuICAgICAgICB9LFxuICAgICAgICBoZWlnaHQ6IHtcbiAgICAgICAgICB2YWw6IHBhcmVudC5wc3R5bGUoJ21pbi1oZWlnaHQnKS5wZlZhbHVlLFxuICAgICAgICAgIHRvcDogcGFyZW50LnBzdHlsZSgnbWluLWhlaWdodC1iaWFzLXRvcCcpLFxuICAgICAgICAgIGJvdHRvbTogcGFyZW50LnBzdHlsZSgnbWluLWhlaWdodC1iaWFzLWJvdHRvbScpXG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICB2YXIgYmIgPSBjaGlsZHJlbi5ib3VuZGluZ0JveCh7XG4gICAgICAgIGluY2x1ZGVMYWJlbHM6IGluY2x1ZGVMYWJlbHMsXG4gICAgICAgIGluY2x1ZGVPdmVybGF5czogZmFsc2UsXG4gICAgICAgIC8vIHVwZGF0aW5nIHRoZSBjb21wb3VuZCBib3VuZHMgaGFwcGVucyBvdXRzaWRlIG9mIHRoZSByZWd1bGFyXG4gICAgICAgIC8vIGNhY2hlIGN5Y2xlIChpLmUuIGJlZm9yZSBmaXJlZCBldmVudHMpXG4gICAgICAgIHVzZUNhY2hlOiBmYWxzZVxuICAgICAgfSk7XG4gICAgICB2YXIgcG9zID0gX3AucG9zaXRpb247IC8vIGlmIGNoaWxkcmVuIHRha2UgdXAgemVybyBhcmVhIHRoZW4ga2VlcCBwb3NpdGlvbiBhbmQgZmFsbCBiYWNrIG9uIHN0eWxlc2hlZXQgdy9oXG5cbiAgICAgIGlmIChiYi53ID09PSAwIHx8IGJiLmggPT09IDApIHtcbiAgICAgICAgYmIgPSB7XG4gICAgICAgICAgdzogcGFyZW50LnBzdHlsZSgnd2lkdGgnKS5wZlZhbHVlLFxuICAgICAgICAgIGg6IHBhcmVudC5wc3R5bGUoJ2hlaWdodCcpLnBmVmFsdWVcbiAgICAgICAgfTtcbiAgICAgICAgYmIueDEgPSBwb3MueCAtIGJiLncgLyAyO1xuICAgICAgICBiYi54MiA9IHBvcy54ICsgYmIudyAvIDI7XG4gICAgICAgIGJiLnkxID0gcG9zLnkgLSBiYi5oIC8gMjtcbiAgICAgICAgYmIueTIgPSBwb3MueSArIGJiLmggLyAyO1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBjb21wdXRlQmlhc1ZhbHVlcyhwcm9wRGlmZiwgcHJvcEJpYXMsIHByb3BCaWFzQ29tcGxlbWVudCkge1xuICAgICAgICB2YXIgYmlhc0RpZmYgPSAwO1xuICAgICAgICB2YXIgYmlhc0NvbXBsZW1lbnREaWZmID0gMDtcbiAgICAgICAgdmFyIGJpYXNUb3RhbCA9IHByb3BCaWFzICsgcHJvcEJpYXNDb21wbGVtZW50O1xuXG4gICAgICAgIGlmIChwcm9wRGlmZiA+IDAgJiYgYmlhc1RvdGFsID4gMCkge1xuICAgICAgICAgIGJpYXNEaWZmID0gcHJvcEJpYXMgLyBiaWFzVG90YWwgKiBwcm9wRGlmZjtcbiAgICAgICAgICBiaWFzQ29tcGxlbWVudERpZmYgPSBwcm9wQmlhc0NvbXBsZW1lbnQgLyBiaWFzVG90YWwgKiBwcm9wRGlmZjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgYmlhc0RpZmY6IGJpYXNEaWZmLFxuICAgICAgICAgIGJpYXNDb21wbGVtZW50RGlmZjogYmlhc0NvbXBsZW1lbnREaWZmXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIGNvbXB1dGVQYWRkaW5nVmFsdWVzKHdpZHRoLCBoZWlnaHQsIHBhZGRpbmdPYmplY3QsIHJlbGF0aXZlVG8pIHtcbiAgICAgICAgLy8gQXNzdW1pbmcgcGVyY2VudGFnZSBpcyBudW1iZXIgZnJvbSAwIHRvIDFcbiAgICAgICAgaWYgKHBhZGRpbmdPYmplY3QudW5pdHMgPT09ICclJykge1xuICAgICAgICAgIHN3aXRjaCAocmVsYXRpdmVUbykge1xuICAgICAgICAgICAgY2FzZSAnd2lkdGgnOlxuICAgICAgICAgICAgICByZXR1cm4gd2lkdGggPiAwID8gcGFkZGluZ09iamVjdC5wZlZhbHVlICogd2lkdGggOiAwO1xuXG4gICAgICAgICAgICBjYXNlICdoZWlnaHQnOlxuICAgICAgICAgICAgICByZXR1cm4gaGVpZ2h0ID4gMCA/IHBhZGRpbmdPYmplY3QucGZWYWx1ZSAqIGhlaWdodCA6IDA7XG5cbiAgICAgICAgICAgIGNhc2UgJ2F2ZXJhZ2UnOlxuICAgICAgICAgICAgICByZXR1cm4gd2lkdGggPiAwICYmIGhlaWdodCA+IDAgPyBwYWRkaW5nT2JqZWN0LnBmVmFsdWUgKiAod2lkdGggKyBoZWlnaHQpIC8gMiA6IDA7XG5cbiAgICAgICAgICAgIGNhc2UgJ21pbic6XG4gICAgICAgICAgICAgIHJldHVybiB3aWR0aCA+IDAgJiYgaGVpZ2h0ID4gMCA/IHdpZHRoID4gaGVpZ2h0ID8gcGFkZGluZ09iamVjdC5wZlZhbHVlICogaGVpZ2h0IDogcGFkZGluZ09iamVjdC5wZlZhbHVlICogd2lkdGggOiAwO1xuXG4gICAgICAgICAgICBjYXNlICdtYXgnOlxuICAgICAgICAgICAgICByZXR1cm4gd2lkdGggPiAwICYmIGhlaWdodCA+IDAgPyB3aWR0aCA+IGhlaWdodCA/IHBhZGRpbmdPYmplY3QucGZWYWx1ZSAqIHdpZHRoIDogcGFkZGluZ09iamVjdC5wZlZhbHVlICogaGVpZ2h0IDogMDtcblxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHBhZGRpbmdPYmplY3QudW5pdHMgPT09ICdweCcpIHtcbiAgICAgICAgICByZXR1cm4gcGFkZGluZ09iamVjdC5wZlZhbHVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHZhciBsZWZ0VmFsID0gbWluLndpZHRoLmxlZnQudmFsdWU7XG5cbiAgICAgIGlmIChtaW4ud2lkdGgubGVmdC51bml0cyA9PT0gJ3B4JyAmJiBtaW4ud2lkdGgudmFsID4gMCkge1xuICAgICAgICBsZWZ0VmFsID0gbGVmdFZhbCAqIDEwMCAvIG1pbi53aWR0aC52YWw7XG4gICAgICB9XG5cbiAgICAgIHZhciByaWdodFZhbCA9IG1pbi53aWR0aC5yaWdodC52YWx1ZTtcblxuICAgICAgaWYgKG1pbi53aWR0aC5yaWdodC51bml0cyA9PT0gJ3B4JyAmJiBtaW4ud2lkdGgudmFsID4gMCkge1xuICAgICAgICByaWdodFZhbCA9IHJpZ2h0VmFsICogMTAwIC8gbWluLndpZHRoLnZhbDtcbiAgICAgIH1cblxuICAgICAgdmFyIHRvcFZhbCA9IG1pbi5oZWlnaHQudG9wLnZhbHVlO1xuXG4gICAgICBpZiAobWluLmhlaWdodC50b3AudW5pdHMgPT09ICdweCcgJiYgbWluLmhlaWdodC52YWwgPiAwKSB7XG4gICAgICAgIHRvcFZhbCA9IHRvcFZhbCAqIDEwMCAvIG1pbi5oZWlnaHQudmFsO1xuICAgICAgfVxuXG4gICAgICB2YXIgYm90dG9tVmFsID0gbWluLmhlaWdodC5ib3R0b20udmFsdWU7XG5cbiAgICAgIGlmIChtaW4uaGVpZ2h0LmJvdHRvbS51bml0cyA9PT0gJ3B4JyAmJiBtaW4uaGVpZ2h0LnZhbCA+IDApIHtcbiAgICAgICAgYm90dG9tVmFsID0gYm90dG9tVmFsICogMTAwIC8gbWluLmhlaWdodC52YWw7XG4gICAgICB9XG5cbiAgICAgIHZhciB3aWR0aEJpYXNEaWZmcyA9IGNvbXB1dGVCaWFzVmFsdWVzKG1pbi53aWR0aC52YWwgLSBiYi53LCBsZWZ0VmFsLCByaWdodFZhbCk7XG4gICAgICB2YXIgZGlmZkxlZnQgPSB3aWR0aEJpYXNEaWZmcy5iaWFzRGlmZjtcbiAgICAgIHZhciBkaWZmUmlnaHQgPSB3aWR0aEJpYXNEaWZmcy5iaWFzQ29tcGxlbWVudERpZmY7XG4gICAgICB2YXIgaGVpZ2h0Qmlhc0RpZmZzID0gY29tcHV0ZUJpYXNWYWx1ZXMobWluLmhlaWdodC52YWwgLSBiYi5oLCB0b3BWYWwsIGJvdHRvbVZhbCk7XG4gICAgICB2YXIgZGlmZlRvcCA9IGhlaWdodEJpYXNEaWZmcy5iaWFzRGlmZjtcbiAgICAgIHZhciBkaWZmQm90dG9tID0gaGVpZ2h0Qmlhc0RpZmZzLmJpYXNDb21wbGVtZW50RGlmZjtcbiAgICAgIF9wLmF1dG9QYWRkaW5nID0gY29tcHV0ZVBhZGRpbmdWYWx1ZXMoYmIudywgYmIuaCwgcGFyZW50LnBzdHlsZSgncGFkZGluZycpLCBwYXJlbnQucHN0eWxlKCdwYWRkaW5nLXJlbGF0aXZlLXRvJykudmFsdWUpO1xuICAgICAgX3AuYXV0b1dpZHRoID0gTWF0aC5tYXgoYmIudywgbWluLndpZHRoLnZhbCk7XG4gICAgICBwb3MueCA9ICgtZGlmZkxlZnQgKyBiYi54MSArIGJiLngyICsgZGlmZlJpZ2h0KSAvIDI7XG4gICAgICBfcC5hdXRvSGVpZ2h0ID0gTWF0aC5tYXgoYmIuaCwgbWluLmhlaWdodC52YWwpO1xuICAgICAgcG9zLnkgPSAoLWRpZmZUb3AgKyBiYi55MSArIGJiLnkyICsgZGlmZkJvdHRvbSkgLyAyO1xuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG4gICAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG5cbiAgICAgIGlmICghX3AuY29tcG91bmRCb3VuZHNDbGVhbiB8fCBmb3JjZSkge1xuICAgICAgICB1cGRhdGUoZWxlKTtcblxuICAgICAgICBpZiAoIWN5LmJhdGNoaW5nKCkpIHtcbiAgICAgICAgICBfcC5jb21wb3VuZEJvdW5kc0NsZWFuID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIHZhciBub25pbmYgPSBmdW5jdGlvbiBub25pbmYoeCkge1xuICAgIGlmICh4ID09PSBJbmZpbml0eSB8fCB4ID09PSAtSW5maW5pdHkpIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIHJldHVybiB4O1xuICB9O1xuXG4gIHZhciB1cGRhdGVCb3VuZHMgPSBmdW5jdGlvbiB1cGRhdGVCb3VuZHMoYiwgeDEsIHkxLCB4MiwgeTIpIHtcbiAgICAvLyBkb24ndCB1cGRhdGUgd2l0aCB6ZXJvIGFyZWEgYm94ZXNcbiAgICBpZiAoeDIgLSB4MSA9PT0gMCB8fCB5MiAtIHkxID09PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfSAvLyBkb24ndCB1cGRhdGUgd2l0aCBudWxsIGRpbVxuXG5cbiAgICBpZiAoeDEgPT0gbnVsbCB8fCB5MSA9PSBudWxsIHx8IHgyID09IG51bGwgfHwgeTIgPT0gbnVsbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGIueDEgPSB4MSA8IGIueDEgPyB4MSA6IGIueDE7XG4gICAgYi54MiA9IHgyID4gYi54MiA/IHgyIDogYi54MjtcbiAgICBiLnkxID0geTEgPCBiLnkxID8geTEgOiBiLnkxO1xuICAgIGIueTIgPSB5MiA+IGIueTIgPyB5MiA6IGIueTI7XG4gICAgYi53ID0gYi54MiAtIGIueDE7XG4gICAgYi5oID0gYi55MiAtIGIueTE7XG4gIH07XG5cbiAgdmFyIHVwZGF0ZUJvdW5kc0Zyb21Cb3ggPSBmdW5jdGlvbiB1cGRhdGVCb3VuZHNGcm9tQm94KGIsIGIyKSB7XG4gICAgaWYgKGIyID09IG51bGwpIHtcbiAgICAgIHJldHVybiBiO1xuICAgIH1cblxuICAgIHJldHVybiB1cGRhdGVCb3VuZHMoYiwgYjIueDEsIGIyLnkxLCBiMi54MiwgYjIueTIpO1xuICB9O1xuXG4gIHZhciBwcmVmaXhlZFByb3BlcnR5ID0gZnVuY3Rpb24gcHJlZml4ZWRQcm9wZXJ0eShvYmosIGZpZWxkLCBwcmVmaXgpIHtcbiAgICByZXR1cm4gZ2V0UHJlZml4ZWRQcm9wZXJ0eShvYmosIGZpZWxkLCBwcmVmaXgpO1xuICB9O1xuXG4gIHZhciB1cGRhdGVCb3VuZHNGcm9tQXJyb3cgPSBmdW5jdGlvbiB1cGRhdGVCb3VuZHNGcm9tQXJyb3coYm91bmRzLCBlbGUsIHByZWZpeCkge1xuICAgIGlmIChlbGUuY3koKS5oZWFkbGVzcygpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgIHZhciByc3R5bGUgPSBfcC5yc3R5bGU7XG4gICAgdmFyIGhhbGZBclcgPSByc3R5bGUuYXJyb3dXaWR0aCAvIDI7XG4gICAgdmFyIGFycm93VHlwZSA9IGVsZS5wc3R5bGUocHJlZml4ICsgJy1hcnJvdy1zaGFwZScpLnZhbHVlO1xuICAgIHZhciB4O1xuICAgIHZhciB5O1xuXG4gICAgaWYgKGFycm93VHlwZSAhPT0gJ25vbmUnKSB7XG4gICAgICBpZiAocHJlZml4ID09PSAnc291cmNlJykge1xuICAgICAgICB4ID0gcnN0eWxlLnNyY1g7XG4gICAgICAgIHkgPSByc3R5bGUuc3JjWTtcbiAgICAgIH0gZWxzZSBpZiAocHJlZml4ID09PSAndGFyZ2V0Jykge1xuICAgICAgICB4ID0gcnN0eWxlLnRndFg7XG4gICAgICAgIHkgPSByc3R5bGUudGd0WTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHggPSByc3R5bGUubWlkWDtcbiAgICAgICAgeSA9IHJzdHlsZS5taWRZO1xuICAgICAgfSAvLyBhbHdheXMgc3RvcmUgdGhlIGluZGl2aWR1YWwgYXJyb3cgYm91bmRzXG5cblxuICAgICAgdmFyIGJicyA9IF9wLmFycm93Qm91bmRzID0gX3AuYXJyb3dCb3VuZHMgfHwge307XG4gICAgICB2YXIgYmIgPSBiYnNbcHJlZml4XSA9IGJic1twcmVmaXhdIHx8IHt9O1xuICAgICAgYmIueDEgPSB4IC0gaGFsZkFyVztcbiAgICAgIGJiLnkxID0geSAtIGhhbGZBclc7XG4gICAgICBiYi54MiA9IHggKyBoYWxmQXJXO1xuICAgICAgYmIueTIgPSB5ICsgaGFsZkFyVztcbiAgICAgIGJiLncgPSBiYi54MiAtIGJiLngxO1xuICAgICAgYmIuaCA9IGJiLnkyIC0gYmIueTE7XG4gICAgICBleHBhbmRCb3VuZGluZ0JveChiYiwgMSk7XG4gICAgICB1cGRhdGVCb3VuZHMoYm91bmRzLCBiYi54MSwgYmIueTEsIGJiLngyLCBiYi55Mik7XG4gICAgfVxuICB9O1xuXG4gIHZhciB1cGRhdGVCb3VuZHNGcm9tTGFiZWwgPSBmdW5jdGlvbiB1cGRhdGVCb3VuZHNGcm9tTGFiZWwoYm91bmRzLCBlbGUsIHByZWZpeCkge1xuICAgIGlmIChlbGUuY3koKS5oZWFkbGVzcygpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIHByZWZpeERhc2g7XG5cbiAgICBpZiAocHJlZml4KSB7XG4gICAgICBwcmVmaXhEYXNoID0gcHJlZml4ICsgJy0nO1xuICAgIH0gZWxzZSB7XG4gICAgICBwcmVmaXhEYXNoID0gJyc7XG4gICAgfVxuXG4gICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgIHZhciByc3R5bGUgPSBfcC5yc3R5bGU7XG4gICAgdmFyIGxhYmVsID0gZWxlLnBzdHlsZShwcmVmaXhEYXNoICsgJ2xhYmVsJykuc3RyVmFsdWU7XG5cbiAgICBpZiAobGFiZWwpIHtcbiAgICAgIHZhciBoYWxpZ24gPSBlbGUucHN0eWxlKCd0ZXh0LWhhbGlnbicpO1xuICAgICAgdmFyIHZhbGlnbiA9IGVsZS5wc3R5bGUoJ3RleHQtdmFsaWduJyk7XG4gICAgICB2YXIgbGFiZWxXaWR0aCA9IHByZWZpeGVkUHJvcGVydHkocnN0eWxlLCAnbGFiZWxXaWR0aCcsIHByZWZpeCk7XG4gICAgICB2YXIgbGFiZWxIZWlnaHQgPSBwcmVmaXhlZFByb3BlcnR5KHJzdHlsZSwgJ2xhYmVsSGVpZ2h0JywgcHJlZml4KTtcbiAgICAgIHZhciBsYWJlbFggPSBwcmVmaXhlZFByb3BlcnR5KHJzdHlsZSwgJ2xhYmVsWCcsIHByZWZpeCk7XG4gICAgICB2YXIgbGFiZWxZID0gcHJlZml4ZWRQcm9wZXJ0eShyc3R5bGUsICdsYWJlbFknLCBwcmVmaXgpO1xuICAgICAgdmFyIG1hcmdpblggPSBlbGUucHN0eWxlKHByZWZpeERhc2ggKyAndGV4dC1tYXJnaW4teCcpLnBmVmFsdWU7XG4gICAgICB2YXIgbWFyZ2luWSA9IGVsZS5wc3R5bGUocHJlZml4RGFzaCArICd0ZXh0LW1hcmdpbi15JykucGZWYWx1ZTtcbiAgICAgIHZhciBpc0VkZ2UgPSBlbGUuaXNFZGdlKCk7XG4gICAgICB2YXIgcm90YXRpb24gPSBlbGUucHN0eWxlKHByZWZpeERhc2ggKyAndGV4dC1yb3RhdGlvbicpO1xuICAgICAgdmFyIG91dGxpbmVXaWR0aCA9IGVsZS5wc3R5bGUoJ3RleHQtb3V0bGluZS13aWR0aCcpLnBmVmFsdWU7XG4gICAgICB2YXIgYm9yZGVyV2lkdGggPSBlbGUucHN0eWxlKCd0ZXh0LWJvcmRlci13aWR0aCcpLnBmVmFsdWU7XG4gICAgICB2YXIgaGFsZkJvcmRlcldpZHRoID0gYm9yZGVyV2lkdGggLyAyO1xuICAgICAgdmFyIHBhZGRpbmcgPSBlbGUucHN0eWxlKCd0ZXh0LWJhY2tncm91bmQtcGFkZGluZycpLnBmVmFsdWU7XG4gICAgICB2YXIgbWFyZ2luT2ZFcnJvciA9IDI7IC8vIGV4cGFuZCB0byB3b3JrIGFyb3VuZCBicm93c2VyIGRpbWVuc2lvbiBpbmFjY3VyYWNpZXNcblxuICAgICAgdmFyIGxoID0gbGFiZWxIZWlnaHQ7XG4gICAgICB2YXIgbHcgPSBsYWJlbFdpZHRoO1xuICAgICAgdmFyIGx3XzIgPSBsdyAvIDI7XG4gICAgICB2YXIgbGhfMiA9IGxoIC8gMjtcbiAgICAgIHZhciBseDEsIGx4MiwgbHkxLCBseTI7XG5cbiAgICAgIGlmIChpc0VkZ2UpIHtcbiAgICAgICAgbHgxID0gbGFiZWxYIC0gbHdfMjtcbiAgICAgICAgbHgyID0gbGFiZWxYICsgbHdfMjtcbiAgICAgICAgbHkxID0gbGFiZWxZIC0gbGhfMjtcbiAgICAgICAgbHkyID0gbGFiZWxZICsgbGhfMjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHN3aXRjaCAoaGFsaWduLnZhbHVlKSB7XG4gICAgICAgICAgY2FzZSAnbGVmdCc6XG4gICAgICAgICAgICBseDEgPSBsYWJlbFggLSBsdztcbiAgICAgICAgICAgIGx4MiA9IGxhYmVsWDtcbiAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgY2FzZSAnY2VudGVyJzpcbiAgICAgICAgICAgIGx4MSA9IGxhYmVsWCAtIGx3XzI7XG4gICAgICAgICAgICBseDIgPSBsYWJlbFggKyBsd18yO1xuICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICBjYXNlICdyaWdodCc6XG4gICAgICAgICAgICBseDEgPSBsYWJlbFg7XG4gICAgICAgICAgICBseDIgPSBsYWJlbFggKyBsdztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgc3dpdGNoICh2YWxpZ24udmFsdWUpIHtcbiAgICAgICAgICBjYXNlICd0b3AnOlxuICAgICAgICAgICAgbHkxID0gbGFiZWxZIC0gbGg7XG4gICAgICAgICAgICBseTIgPSBsYWJlbFk7XG4gICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgIGNhc2UgJ2NlbnRlcic6XG4gICAgICAgICAgICBseTEgPSBsYWJlbFkgLSBsaF8yO1xuICAgICAgICAgICAgbHkyID0gbGFiZWxZICsgbGhfMjtcbiAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgY2FzZSAnYm90dG9tJzpcbiAgICAgICAgICAgIGx5MSA9IGxhYmVsWTtcbiAgICAgICAgICAgIGx5MiA9IGxhYmVsWSArIGxoO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gc2hpZnQgYnkgbWFyZ2luIGFuZCBleHBhbmQgYnkgb3V0bGluZSBhbmQgYm9yZGVyXG5cblxuICAgICAgbHgxICs9IG1hcmdpblggLSBNYXRoLm1heChvdXRsaW5lV2lkdGgsIGhhbGZCb3JkZXJXaWR0aCkgLSBwYWRkaW5nIC0gbWFyZ2luT2ZFcnJvcjtcbiAgICAgIGx4MiArPSBtYXJnaW5YICsgTWF0aC5tYXgob3V0bGluZVdpZHRoLCBoYWxmQm9yZGVyV2lkdGgpICsgcGFkZGluZyArIG1hcmdpbk9mRXJyb3I7XG4gICAgICBseTEgKz0gbWFyZ2luWSAtIE1hdGgubWF4KG91dGxpbmVXaWR0aCwgaGFsZkJvcmRlcldpZHRoKSAtIHBhZGRpbmcgLSBtYXJnaW5PZkVycm9yO1xuICAgICAgbHkyICs9IG1hcmdpblkgKyBNYXRoLm1heChvdXRsaW5lV2lkdGgsIGhhbGZCb3JkZXJXaWR0aCkgKyBwYWRkaW5nICsgbWFyZ2luT2ZFcnJvcjsgLy8gYWx3YXlzIHN0b3JlIHRoZSB1bnJvdGF0ZWQgbGFiZWwgYm91bmRzIHNlcGFyYXRlbHlcblxuICAgICAgdmFyIGJiUHJlZml4ID0gcHJlZml4IHx8ICdtYWluJztcbiAgICAgIHZhciBiYnMgPSBfcC5sYWJlbEJvdW5kcztcbiAgICAgIHZhciBiYiA9IGJic1tiYlByZWZpeF0gPSBiYnNbYmJQcmVmaXhdIHx8IHt9O1xuICAgICAgYmIueDEgPSBseDE7XG4gICAgICBiYi55MSA9IGx5MTtcbiAgICAgIGJiLngyID0gbHgyO1xuICAgICAgYmIueTIgPSBseTI7XG4gICAgICBiYi53ID0gbHgyIC0gbHgxO1xuICAgICAgYmIuaCA9IGx5MiAtIGx5MTtcbiAgICAgIHZhciBpc0F1dG9yb3RhdGUgPSBpc0VkZ2UgJiYgcm90YXRpb24uc3RyVmFsdWUgPT09ICdhdXRvcm90YXRlJztcbiAgICAgIHZhciBpc1BmVmFsdWUgPSByb3RhdGlvbi5wZlZhbHVlICE9IG51bGwgJiYgcm90YXRpb24ucGZWYWx1ZSAhPT0gMDtcblxuICAgICAgaWYgKGlzQXV0b3JvdGF0ZSB8fCBpc1BmVmFsdWUpIHtcbiAgICAgICAgdmFyIHRoZXRhID0gaXNBdXRvcm90YXRlID8gcHJlZml4ZWRQcm9wZXJ0eShfcC5yc3R5bGUsICdsYWJlbEFuZ2xlJywgcHJlZml4KSA6IHJvdGF0aW9uLnBmVmFsdWU7XG4gICAgICAgIHZhciBjb3MgPSBNYXRoLmNvcyh0aGV0YSk7XG4gICAgICAgIHZhciBzaW4gPSBNYXRoLnNpbih0aGV0YSk7IC8vIHJvdGF0aW9uIHBvaW50IChkZWZhdWx0IHZhbHVlIGZvciBjZW50ZXItY2VudGVyKVxuXG4gICAgICAgIHZhciB4byA9IChseDEgKyBseDIpIC8gMjtcbiAgICAgICAgdmFyIHlvID0gKGx5MSArIGx5MikgLyAyO1xuXG4gICAgICAgIGlmICghaXNFZGdlKSB7XG4gICAgICAgICAgc3dpdGNoIChoYWxpZ24udmFsdWUpIHtcbiAgICAgICAgICAgIGNhc2UgJ2xlZnQnOlxuICAgICAgICAgICAgICB4byA9IGx4MjtcbiAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJ3JpZ2h0JzpcbiAgICAgICAgICAgICAgeG8gPSBseDE7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHN3aXRjaCAodmFsaWduLnZhbHVlKSB7XG4gICAgICAgICAgICBjYXNlICd0b3AnOlxuICAgICAgICAgICAgICB5byA9IGx5MjtcbiAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJ2JvdHRvbSc6XG4gICAgICAgICAgICAgIHlvID0gbHkxO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcm90YXRlID0gZnVuY3Rpb24gcm90YXRlKHgsIHkpIHtcbiAgICAgICAgICB4ID0geCAtIHhvO1xuICAgICAgICAgIHkgPSB5IC0geW87XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHg6IHggKiBjb3MgLSB5ICogc2luICsgeG8sXG4gICAgICAgICAgICB5OiB4ICogc2luICsgeSAqIGNvcyArIHlvXG4gICAgICAgICAgfTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgcHgxeTEgPSByb3RhdGUobHgxLCBseTEpO1xuICAgICAgICB2YXIgcHgxeTIgPSByb3RhdGUobHgxLCBseTIpO1xuICAgICAgICB2YXIgcHgyeTEgPSByb3RhdGUobHgyLCBseTEpO1xuICAgICAgICB2YXIgcHgyeTIgPSByb3RhdGUobHgyLCBseTIpO1xuICAgICAgICBseDEgPSBNYXRoLm1pbihweDF5MS54LCBweDF5Mi54LCBweDJ5MS54LCBweDJ5Mi54KTtcbiAgICAgICAgbHgyID0gTWF0aC5tYXgocHgxeTEueCwgcHgxeTIueCwgcHgyeTEueCwgcHgyeTIueCk7XG4gICAgICAgIGx5MSA9IE1hdGgubWluKHB4MXkxLnksIHB4MXkyLnksIHB4MnkxLnksIHB4MnkyLnkpO1xuICAgICAgICBseTIgPSBNYXRoLm1heChweDF5MS55LCBweDF5Mi55LCBweDJ5MS55LCBweDJ5Mi55KTtcbiAgICAgIH1cblxuICAgICAgdmFyIGJiUHJlZml4Um90ID0gYmJQcmVmaXggKyAnUm90JztcbiAgICAgIHZhciBiYlJvdCA9IGJic1tiYlByZWZpeFJvdF0gPSBiYnNbYmJQcmVmaXhSb3RdIHx8IHt9O1xuICAgICAgYmJSb3QueDEgPSBseDE7XG4gICAgICBiYlJvdC55MSA9IGx5MTtcbiAgICAgIGJiUm90LngyID0gbHgyO1xuICAgICAgYmJSb3QueTIgPSBseTI7XG4gICAgICBiYlJvdC53ID0gbHgyIC0gbHgxO1xuICAgICAgYmJSb3QuaCA9IGx5MiAtIGx5MTtcbiAgICAgIHVwZGF0ZUJvdW5kcyhib3VuZHMsIGx4MSwgbHkxLCBseDIsIGx5Mik7XG4gICAgICB1cGRhdGVCb3VuZHMoX3AubGFiZWxCb3VuZHMuYWxsLCBseDEsIGx5MSwgbHgyLCBseTIpO1xuICAgIH1cblxuICAgIHJldHVybiBib3VuZHM7XG4gIH07IC8vIGdldCB0aGUgYm91bmRpbmcgYm94IG9mIHRoZSBlbGVtZW50cyAoaW4gcmF3IG1vZGVsIHBvc2l0aW9uKVxuXG5cbiAgdmFyIGJvdW5kaW5nQm94SW1wbCA9IGZ1bmN0aW9uIGJvdW5kaW5nQm94SW1wbChlbGUsIG9wdGlvbnMpIHtcbiAgICB2YXIgY3kgPSBlbGUuX3ByaXZhdGUuY3k7XG4gICAgdmFyIHN0eWxlRW5hYmxlZCA9IGN5LnN0eWxlRW5hYmxlZCgpO1xuICAgIHZhciBoZWFkbGVzcyA9IGN5LmhlYWRsZXNzKCk7XG4gICAgdmFyIGJvdW5kcyA9IG1ha2VCb3VuZGluZ0JveCgpO1xuICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICB2YXIgaXNOb2RlID0gZWxlLmlzTm9kZSgpO1xuICAgIHZhciBpc0VkZ2UgPSBlbGUuaXNFZGdlKCk7XG4gICAgdmFyIGV4MSwgZXgyLCBleTEsIGV5MjsgLy8gZXh0cmVtYSBvZiBib2R5IC8gbGluZXNcblxuICAgIHZhciB4LCB5OyAvLyBub2RlIHBvc1xuXG4gICAgdmFyIHJzdHlsZSA9IF9wLnJzdHlsZTtcbiAgICB2YXIgbWFudWFsRXhwYW5zaW9uID0gaXNOb2RlICYmIHN0eWxlRW5hYmxlZCA/IGVsZS5wc3R5bGUoJ2JvdW5kcy1leHBhbnNpb24nKS5wZlZhbHVlIDogWzBdOyAvLyBtdXN0IHVzZSBgZGlzcGxheWAgcHJvcCBvbmx5LCBhcyByZWFkaW5nIGBjb21wb3VuZC53aWR0aCgpYCBjYXVzZXMgcmVjdXJzaW9uXG4gICAgLy8gKG90aGVyIGZhY3RvcnMgbGlrZSB3aWR0aCB2YWx1ZXMgd2lsbCBiZSBjb25zaWRlcmVkIGxhdGVyIGluIHRoaXMgZnVuY3Rpb24gYW55d2F5KVxuXG4gICAgdmFyIGlzRGlzcGxheWVkID0gZnVuY3Rpb24gaXNEaXNwbGF5ZWQoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLnBzdHlsZSgnZGlzcGxheScpLnZhbHVlICE9PSAnbm9uZSc7XG4gICAgfTtcblxuICAgIHZhciBkaXNwbGF5ZWQgPSAhc3R5bGVFbmFibGVkIHx8IGlzRGlzcGxheWVkKGVsZSkgLy8gbXVzdCB0YWtlIGludG8gYWNjb3VudCBjb25uZWN0ZWQgbm9kZXMgYi9jIG9mIGltcGxpY2l0IGVkZ2UgaGlkaW5nIG9uIGRpc3BsYXk6bm9uZSBub2RlXG4gICAgJiYgKCFpc0VkZ2UgfHwgaXNEaXNwbGF5ZWQoZWxlLnNvdXJjZSgpKSAmJiBpc0Rpc3BsYXllZChlbGUudGFyZ2V0KCkpKTtcblxuICAgIGlmIChkaXNwbGF5ZWQpIHtcbiAgICAgIC8vIGRpc3BsYXllZCBzdWZmaWNlcywgc2luY2Ugd2Ugd2lsbCBmaW5kIHplcm8gYXJlYSBlbGVzIGFueXdheVxuICAgICAgdmFyIG92ZXJsYXlPcGFjaXR5ID0gMDtcbiAgICAgIHZhciBvdmVybGF5UGFkZGluZyA9IDA7XG5cbiAgICAgIGlmIChzdHlsZUVuYWJsZWQgJiYgb3B0aW9ucy5pbmNsdWRlT3ZlcmxheXMpIHtcbiAgICAgICAgb3ZlcmxheU9wYWNpdHkgPSBlbGUucHN0eWxlKCdvdmVybGF5LW9wYWNpdHknKS52YWx1ZTtcblxuICAgICAgICBpZiAob3ZlcmxheU9wYWNpdHkgIT09IDApIHtcbiAgICAgICAgICBvdmVybGF5UGFkZGluZyA9IGVsZS5wc3R5bGUoJ292ZXJsYXktcGFkZGluZycpLnZhbHVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHZhciB1bmRlcmxheU9wYWNpdHkgPSAwO1xuICAgICAgdmFyIHVuZGVybGF5UGFkZGluZyA9IDA7XG5cbiAgICAgIGlmIChzdHlsZUVuYWJsZWQgJiYgb3B0aW9ucy5pbmNsdWRlVW5kZXJsYXlzKSB7XG4gICAgICAgIHVuZGVybGF5T3BhY2l0eSA9IGVsZS5wc3R5bGUoJ3VuZGVybGF5LW9wYWNpdHknKS52YWx1ZTtcblxuICAgICAgICBpZiAodW5kZXJsYXlPcGFjaXR5ICE9PSAwKSB7XG4gICAgICAgICAgdW5kZXJsYXlQYWRkaW5nID0gZWxlLnBzdHlsZSgndW5kZXJsYXktcGFkZGluZycpLnZhbHVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHZhciBwYWRkaW5nID0gTWF0aC5tYXgob3ZlcmxheVBhZGRpbmcsIHVuZGVybGF5UGFkZGluZyk7XG4gICAgICB2YXIgdyA9IDA7XG4gICAgICB2YXIgd0hhbGYgPSAwO1xuXG4gICAgICBpZiAoc3R5bGVFbmFibGVkKSB7XG4gICAgICAgIHcgPSBlbGUucHN0eWxlKCd3aWR0aCcpLnBmVmFsdWU7XG4gICAgICAgIHdIYWxmID0gdyAvIDI7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc05vZGUgJiYgb3B0aW9ucy5pbmNsdWRlTm9kZXMpIHtcbiAgICAgICAgdmFyIHBvcyA9IGVsZS5wb3NpdGlvbigpO1xuICAgICAgICB4ID0gcG9zLng7XG4gICAgICAgIHkgPSBwb3MueTtcblxuICAgICAgICB2YXIgX3cgPSBlbGUub3V0ZXJXaWR0aCgpO1xuXG4gICAgICAgIHZhciBoYWxmVyA9IF93IC8gMjtcbiAgICAgICAgdmFyIGggPSBlbGUub3V0ZXJIZWlnaHQoKTtcbiAgICAgICAgdmFyIGhhbGZIID0gaCAvIDI7IC8vIGhhbmRsZSBub2RlIGRpbWVuc2lvbnNcbiAgICAgICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG4gICAgICAgIGV4MSA9IHggLSBoYWxmVztcbiAgICAgICAgZXgyID0geCArIGhhbGZXO1xuICAgICAgICBleTEgPSB5IC0gaGFsZkg7XG4gICAgICAgIGV5MiA9IHkgKyBoYWxmSDtcbiAgICAgICAgdXBkYXRlQm91bmRzKGJvdW5kcywgZXgxLCBleTEsIGV4MiwgZXkyKTtcbiAgICAgIH0gZWxzZSBpZiAoaXNFZGdlICYmIG9wdGlvbnMuaW5jbHVkZUVkZ2VzKSB7XG4gICAgICAgIGlmIChzdHlsZUVuYWJsZWQgJiYgIWhlYWRsZXNzKSB7XG4gICAgICAgICAgdmFyIGN1cnZlU3R5bGUgPSBlbGUucHN0eWxlKCdjdXJ2ZS1zdHlsZScpLnN0clZhbHVlOyAvLyBoYW5kbGUgZWRnZSBkaW1lbnNpb25zIChyb3VnaCBib3ggZXN0aW1hdGUpXG4gICAgICAgICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG4gICAgICAgICAgZXgxID0gTWF0aC5taW4ocnN0eWxlLnNyY1gsIHJzdHlsZS5taWRYLCByc3R5bGUudGd0WCk7XG4gICAgICAgICAgZXgyID0gTWF0aC5tYXgocnN0eWxlLnNyY1gsIHJzdHlsZS5taWRYLCByc3R5bGUudGd0WCk7XG4gICAgICAgICAgZXkxID0gTWF0aC5taW4ocnN0eWxlLnNyY1ksIHJzdHlsZS5taWRZLCByc3R5bGUudGd0WSk7XG4gICAgICAgICAgZXkyID0gTWF0aC5tYXgocnN0eWxlLnNyY1ksIHJzdHlsZS5taWRZLCByc3R5bGUudGd0WSk7IC8vIHRha2UgaW50byBhY2NvdW50IGVkZ2Ugd2lkdGhcblxuICAgICAgICAgIGV4MSAtPSB3SGFsZjtcbiAgICAgICAgICBleDIgKz0gd0hhbGY7XG4gICAgICAgICAgZXkxIC09IHdIYWxmO1xuICAgICAgICAgIGV5MiArPSB3SGFsZjtcbiAgICAgICAgICB1cGRhdGVCb3VuZHMoYm91bmRzLCBleDEsIGV5MSwgZXgyLCBleTIpOyAvLyBwcmVjaXNlIGVkZ2VzXG4gICAgICAgICAgLy8vLy8vLy8vLy8vLy8vL1xuXG4gICAgICAgICAgaWYgKGN1cnZlU3R5bGUgPT09ICdoYXlzdGFjaycpIHtcbiAgICAgICAgICAgIHZhciBocHRzID0gcnN0eWxlLmhheXN0YWNrUHRzO1xuXG4gICAgICAgICAgICBpZiAoaHB0cyAmJiBocHRzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICAgICAgICBleDEgPSBocHRzWzBdLng7XG4gICAgICAgICAgICAgIGV5MSA9IGhwdHNbMF0ueTtcbiAgICAgICAgICAgICAgZXgyID0gaHB0c1sxXS54O1xuICAgICAgICAgICAgICBleTIgPSBocHRzWzFdLnk7XG5cbiAgICAgICAgICAgICAgaWYgKGV4MSA+IGV4Mikge1xuICAgICAgICAgICAgICAgIHZhciB0ZW1wID0gZXgxO1xuICAgICAgICAgICAgICAgIGV4MSA9IGV4MjtcbiAgICAgICAgICAgICAgICBleDIgPSB0ZW1wO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgaWYgKGV5MSA+IGV5Mikge1xuICAgICAgICAgICAgICAgIHZhciBfdGVtcCA9IGV5MTtcbiAgICAgICAgICAgICAgICBleTEgPSBleTI7XG4gICAgICAgICAgICAgICAgZXkyID0gX3RlbXA7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICB1cGRhdGVCb3VuZHMoYm91bmRzLCBleDEgLSB3SGFsZiwgZXkxIC0gd0hhbGYsIGV4MiArIHdIYWxmLCBleTIgKyB3SGFsZik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChjdXJ2ZVN0eWxlID09PSAnYmV6aWVyJyB8fCBjdXJ2ZVN0eWxlID09PSAndW5idW5kbGVkLWJlemllcicgfHwgY3VydmVTdHlsZSA9PT0gJ3NlZ21lbnRzJyB8fCBjdXJ2ZVN0eWxlID09PSAndGF4aScpIHtcbiAgICAgICAgICAgIHZhciBwdHM7XG5cbiAgICAgICAgICAgIHN3aXRjaCAoY3VydmVTdHlsZSkge1xuICAgICAgICAgICAgICBjYXNlICdiZXppZXInOlxuICAgICAgICAgICAgICBjYXNlICd1bmJ1bmRsZWQtYmV6aWVyJzpcbiAgICAgICAgICAgICAgICBwdHMgPSByc3R5bGUuYmV6aWVyUHRzO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgIGNhc2UgJ3NlZ21lbnRzJzpcbiAgICAgICAgICAgICAgY2FzZSAndGF4aSc6XG4gICAgICAgICAgICAgICAgcHRzID0gcnN0eWxlLmxpbmVQdHM7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChwdHMgIT0gbnVsbCkge1xuICAgICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHB0cy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIHZhciBwdCA9IHB0c1tqXTtcbiAgICAgICAgICAgICAgICBleDEgPSBwdC54IC0gd0hhbGY7XG4gICAgICAgICAgICAgICAgZXgyID0gcHQueCArIHdIYWxmO1xuICAgICAgICAgICAgICAgIGV5MSA9IHB0LnkgLSB3SGFsZjtcbiAgICAgICAgICAgICAgICBleTIgPSBwdC55ICsgd0hhbGY7XG4gICAgICAgICAgICAgICAgdXBkYXRlQm91bmRzKGJvdW5kcywgZXgxLCBleTEsIGV4MiwgZXkyKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gYmV6aWVyLWxpa2Ugb3Igc2VnbWVudC1saWtlIGVkZ2VcblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIGhlYWRsZXNzIG9yIHN0eWxlIGRpc2FibGVkXG4gICAgICAgICAgLy8gZmFsbGJhY2sgb24gc291cmNlIGFuZCB0YXJnZXQgcG9zaXRpb25zXG4gICAgICAgICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4gICAgICAgICAgdmFyIG4xID0gZWxlLnNvdXJjZSgpO1xuICAgICAgICAgIHZhciBuMXBvcyA9IG4xLnBvc2l0aW9uKCk7XG4gICAgICAgICAgdmFyIG4yID0gZWxlLnRhcmdldCgpO1xuICAgICAgICAgIHZhciBuMnBvcyA9IG4yLnBvc2l0aW9uKCk7XG4gICAgICAgICAgZXgxID0gbjFwb3MueDtcbiAgICAgICAgICBleDIgPSBuMnBvcy54O1xuICAgICAgICAgIGV5MSA9IG4xcG9zLnk7XG4gICAgICAgICAgZXkyID0gbjJwb3MueTtcblxuICAgICAgICAgIGlmIChleDEgPiBleDIpIHtcbiAgICAgICAgICAgIHZhciBfdGVtcDIgPSBleDE7XG4gICAgICAgICAgICBleDEgPSBleDI7XG4gICAgICAgICAgICBleDIgPSBfdGVtcDI7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGV5MSA+IGV5Mikge1xuICAgICAgICAgICAgdmFyIF90ZW1wMyA9IGV5MTtcbiAgICAgICAgICAgIGV5MSA9IGV5MjtcbiAgICAgICAgICAgIGV5MiA9IF90ZW1wMztcbiAgICAgICAgICB9IC8vIHRha2UgaW50byBhY2NvdW50IGVkZ2Ugd2lkdGhcblxuXG4gICAgICAgICAgZXgxIC09IHdIYWxmO1xuICAgICAgICAgIGV4MiArPSB3SGFsZjtcbiAgICAgICAgICBleTEgLT0gd0hhbGY7XG4gICAgICAgICAgZXkyICs9IHdIYWxmO1xuICAgICAgICAgIHVwZGF0ZUJvdW5kcyhib3VuZHMsIGV4MSwgZXkxLCBleDIsIGV5Mik7XG4gICAgICAgIH0gLy8gaGVhZGxlc3Mgb3Igc3R5bGUgZGlzYWJsZWRcblxuICAgICAgfSAvLyBlZGdlc1xuICAgICAgLy8gaGFuZGxlIGVkZ2UgYXJyb3cgc2l6ZVxuICAgICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG5cbiAgICAgIGlmIChzdHlsZUVuYWJsZWQgJiYgb3B0aW9ucy5pbmNsdWRlRWRnZXMgJiYgaXNFZGdlKSB7XG4gICAgICAgIHVwZGF0ZUJvdW5kc0Zyb21BcnJvdyhib3VuZHMsIGVsZSwgJ21pZC1zb3VyY2UnKTtcbiAgICAgICAgdXBkYXRlQm91bmRzRnJvbUFycm93KGJvdW5kcywgZWxlLCAnbWlkLXRhcmdldCcpO1xuICAgICAgICB1cGRhdGVCb3VuZHNGcm9tQXJyb3coYm91bmRzLCBlbGUsICdzb3VyY2UnKTtcbiAgICAgICAgdXBkYXRlQm91bmRzRnJvbUFycm93KGJvdW5kcywgZWxlLCAndGFyZ2V0Jyk7XG4gICAgICB9IC8vIGdob3N0XG4gICAgICAvLy8vLy8vL1xuXG5cbiAgICAgIGlmIChzdHlsZUVuYWJsZWQpIHtcbiAgICAgICAgdmFyIGdob3N0ID0gZWxlLnBzdHlsZSgnZ2hvc3QnKS52YWx1ZSA9PT0gJ3llcyc7XG5cbiAgICAgICAgaWYgKGdob3N0KSB7XG4gICAgICAgICAgdmFyIGd4ID0gZWxlLnBzdHlsZSgnZ2hvc3Qtb2Zmc2V0LXgnKS5wZlZhbHVlO1xuICAgICAgICAgIHZhciBneSA9IGVsZS5wc3R5bGUoJ2dob3N0LW9mZnNldC15JykucGZWYWx1ZTtcbiAgICAgICAgICB1cGRhdGVCb3VuZHMoYm91bmRzLCBib3VuZHMueDEgKyBneCwgYm91bmRzLnkxICsgZ3ksIGJvdW5kcy54MiArIGd4LCBib3VuZHMueTIgKyBneSk7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gYWx3YXlzIHN0b3JlIHRoZSBib2R5IGJvdW5kcyBzZXBhcmF0ZWx5IGZyb20gdGhlIGxhYmVsc1xuXG5cbiAgICAgIHZhciBiYkJvZHkgPSBfcC5ib2R5Qm91bmRzID0gX3AuYm9keUJvdW5kcyB8fCB7fTtcbiAgICAgIGFzc2lnbkJvdW5kaW5nQm94KGJiQm9keSwgYm91bmRzKTtcbiAgICAgIGV4cGFuZEJvdW5kaW5nQm94U2lkZXMoYmJCb2R5LCBtYW51YWxFeHBhbnNpb24pO1xuICAgICAgZXhwYW5kQm91bmRpbmdCb3goYmJCb2R5LCAxKTsgLy8gZXhwYW5kIHRvIHdvcmsgYXJvdW5kIGJyb3dzZXIgZGltZW5zaW9uIGluYWNjdXJhY2llc1xuICAgICAgLy8gb3ZlcmxheVxuICAgICAgLy8vLy8vLy8vL1xuXG4gICAgICBpZiAoc3R5bGVFbmFibGVkKSB7XG4gICAgICAgIGV4MSA9IGJvdW5kcy54MTtcbiAgICAgICAgZXgyID0gYm91bmRzLngyO1xuICAgICAgICBleTEgPSBib3VuZHMueTE7XG4gICAgICAgIGV5MiA9IGJvdW5kcy55MjtcbiAgICAgICAgdXBkYXRlQm91bmRzKGJvdW5kcywgZXgxIC0gcGFkZGluZywgZXkxIC0gcGFkZGluZywgZXgyICsgcGFkZGluZywgZXkyICsgcGFkZGluZyk7XG4gICAgICB9IC8vIGFsd2F5cyBzdG9yZSB0aGUgYm9keSBib3VuZHMgc2VwYXJhdGVseSBmcm9tIHRoZSBsYWJlbHNcblxuXG4gICAgICB2YXIgYmJPdmVybGF5ID0gX3Aub3ZlcmxheUJvdW5kcyA9IF9wLm92ZXJsYXlCb3VuZHMgfHwge307XG4gICAgICBhc3NpZ25Cb3VuZGluZ0JveChiYk92ZXJsYXksIGJvdW5kcyk7XG4gICAgICBleHBhbmRCb3VuZGluZ0JveFNpZGVzKGJiT3ZlcmxheSwgbWFudWFsRXhwYW5zaW9uKTtcbiAgICAgIGV4cGFuZEJvdW5kaW5nQm94KGJiT3ZlcmxheSwgMSk7IC8vIGV4cGFuZCB0byB3b3JrIGFyb3VuZCBicm93c2VyIGRpbWVuc2lvbiBpbmFjY3VyYWNpZXNcbiAgICAgIC8vIGhhbmRsZSBsYWJlbCBkaW1lbnNpb25zXG4gICAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG4gICAgICB2YXIgYmJMYWJlbHMgPSBfcC5sYWJlbEJvdW5kcyA9IF9wLmxhYmVsQm91bmRzIHx8IHt9O1xuXG4gICAgICBpZiAoYmJMYWJlbHMuYWxsICE9IG51bGwpIHtcbiAgICAgICAgY2xlYXJCb3VuZGluZ0JveChiYkxhYmVscy5hbGwpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYmJMYWJlbHMuYWxsID0gbWFrZUJvdW5kaW5nQm94KCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzdHlsZUVuYWJsZWQgJiYgb3B0aW9ucy5pbmNsdWRlTGFiZWxzKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmluY2x1ZGVNYWluTGFiZWxzKSB7XG4gICAgICAgICAgdXBkYXRlQm91bmRzRnJvbUxhYmVsKGJvdW5kcywgZWxlLCBudWxsKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpc0VkZ2UpIHtcbiAgICAgICAgICBpZiAob3B0aW9ucy5pbmNsdWRlU291cmNlTGFiZWxzKSB7XG4gICAgICAgICAgICB1cGRhdGVCb3VuZHNGcm9tTGFiZWwoYm91bmRzLCBlbGUsICdzb3VyY2UnKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAob3B0aW9ucy5pbmNsdWRlVGFyZ2V0TGFiZWxzKSB7XG4gICAgICAgICAgICB1cGRhdGVCb3VuZHNGcm9tTGFiZWwoYm91bmRzLCBlbGUsICd0YXJnZXQnKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gLy8gc3R5bGUgZW5hYmxlZCBmb3IgbGFiZWxzXG5cbiAgICB9IC8vIGlmIGRpc3BsYXllZFxuXG5cbiAgICBib3VuZHMueDEgPSBub25pbmYoYm91bmRzLngxKTtcbiAgICBib3VuZHMueTEgPSBub25pbmYoYm91bmRzLnkxKTtcbiAgICBib3VuZHMueDIgPSBub25pbmYoYm91bmRzLngyKTtcbiAgICBib3VuZHMueTIgPSBub25pbmYoYm91bmRzLnkyKTtcbiAgICBib3VuZHMudyA9IG5vbmluZihib3VuZHMueDIgLSBib3VuZHMueDEpO1xuICAgIGJvdW5kcy5oID0gbm9uaW5mKGJvdW5kcy55MiAtIGJvdW5kcy55MSk7XG5cbiAgICBpZiAoYm91bmRzLncgPiAwICYmIGJvdW5kcy5oID4gMCAmJiBkaXNwbGF5ZWQpIHtcbiAgICAgIGV4cGFuZEJvdW5kaW5nQm94U2lkZXMoYm91bmRzLCBtYW51YWxFeHBhbnNpb24pOyAvLyBleHBhbmQgYm91bmRzIGJ5IDEgYmVjYXVzZSBhbnRpYWxpYXNpbmcgY2FuIGluY3JlYXNlIHRoZSB2aXN1YWwvZWZmZWN0aXZlIHNpemUgYnkgMSBvbiBhbGwgc2lkZXNcblxuICAgICAgZXhwYW5kQm91bmRpbmdCb3goYm91bmRzLCAxKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYm91bmRzO1xuICB9O1xuXG4gIHZhciBnZXRLZXkgPSBmdW5jdGlvbiBnZXRLZXkob3B0cykge1xuICAgIHZhciBpID0gMDtcblxuICAgIHZhciB0ZiA9IGZ1bmN0aW9uIHRmKHZhbCkge1xuICAgICAgcmV0dXJuICh2YWwgPyAxIDogMCkgPDwgaSsrO1xuICAgIH07XG5cbiAgICB2YXIga2V5ID0gMDtcbiAgICBrZXkgKz0gdGYob3B0cy5pbmN1ZGVOb2Rlcyk7XG4gICAga2V5ICs9IHRmKG9wdHMuaW5jbHVkZUVkZ2VzKTtcbiAgICBrZXkgKz0gdGYob3B0cy5pbmNsdWRlTGFiZWxzKTtcbiAgICBrZXkgKz0gdGYob3B0cy5pbmNsdWRlTWFpbkxhYmVscyk7XG4gICAga2V5ICs9IHRmKG9wdHMuaW5jbHVkZVNvdXJjZUxhYmVscyk7XG4gICAga2V5ICs9IHRmKG9wdHMuaW5jbHVkZVRhcmdldExhYmVscyk7XG4gICAga2V5ICs9IHRmKG9wdHMuaW5jbHVkZU92ZXJsYXlzKTtcbiAgICByZXR1cm4ga2V5O1xuICB9O1xuXG4gIHZhciBnZXRCb3VuZGluZ0JveFBvc0tleSA9IGZ1bmN0aW9uIGdldEJvdW5kaW5nQm94UG9zS2V5KGVsZSkge1xuICAgIGlmIChlbGUuaXNFZGdlKCkpIHtcbiAgICAgIHZhciBwMSA9IGVsZS5zb3VyY2UoKS5wb3NpdGlvbigpO1xuICAgICAgdmFyIHAyID0gZWxlLnRhcmdldCgpLnBvc2l0aW9uKCk7XG5cbiAgICAgIHZhciByID0gZnVuY3Rpb24gcih4KSB7XG4gICAgICAgIHJldHVybiBNYXRoLnJvdW5kKHgpO1xuICAgICAgfTtcblxuICAgICAgcmV0dXJuIGhhc2hJbnRzQXJyYXkoW3IocDEueCksIHIocDEueSksIHIocDIueCksIHIocDIueSldKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuICB9O1xuXG4gIHZhciBjYWNoZWRCb3VuZGluZ0JveEltcGwgPSBmdW5jdGlvbiBjYWNoZWRCb3VuZGluZ0JveEltcGwoZWxlLCBvcHRzKSB7XG4gICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgIHZhciBiYjtcbiAgICB2YXIgaXNFZGdlID0gZWxlLmlzRWRnZSgpO1xuICAgIHZhciBrZXkgPSBvcHRzID09IG51bGwgPyBkZWZCYk9wdHNLZXkgOiBnZXRLZXkob3B0cyk7XG4gICAgdmFyIHVzaW5nRGVmT3B0cyA9IGtleSA9PT0gZGVmQmJPcHRzS2V5O1xuICAgIHZhciBjdXJyUG9zS2V5ID0gZ2V0Qm91bmRpbmdCb3hQb3NLZXkoZWxlKTtcbiAgICB2YXIgaXNQb3NLZXlTYW1lID0gX3AuYmJDYWNoZVBvc0tleSA9PT0gY3VyclBvc0tleTtcbiAgICB2YXIgdXNlQ2FjaGUgPSBvcHRzLnVzZUNhY2hlICYmIGlzUG9zS2V5U2FtZTtcblxuICAgIHZhciBpc0RpcnR5ID0gZnVuY3Rpb24gaXNEaXJ0eShlbGUpIHtcbiAgICAgIHJldHVybiBlbGUuX3ByaXZhdGUuYmJDYWNoZSA9PSBudWxsIHx8IGVsZS5fcHJpdmF0ZS5zdHlsZURpcnR5O1xuICAgIH07XG5cbiAgICB2YXIgbmVlZFJlY2FsYyA9ICF1c2VDYWNoZSB8fCBpc0RpcnR5KGVsZSkgfHwgaXNFZGdlICYmIGlzRGlydHkoZWxlLnNvdXJjZSgpKSB8fCBpc0RpcnR5KGVsZS50YXJnZXQoKSk7XG5cbiAgICBpZiAobmVlZFJlY2FsYykge1xuICAgICAgaWYgKCFpc1Bvc0tleVNhbWUpIHtcbiAgICAgICAgZWxlLnJlY2FsY3VsYXRlUmVuZGVyZWRTdHlsZSh1c2VDYWNoZSk7XG4gICAgICB9XG5cbiAgICAgIGJiID0gYm91bmRpbmdCb3hJbXBsKGVsZSwgZGVmQmJPcHRzKTtcbiAgICAgIF9wLmJiQ2FjaGUgPSBiYjtcbiAgICAgIF9wLmJiQ2FjaGVQb3NLZXkgPSBjdXJyUG9zS2V5O1xuICAgIH0gZWxzZSB7XG4gICAgICBiYiA9IF9wLmJiQ2FjaGU7XG4gICAgfSAvLyBub3QgdXNpbmcgZGVmIG9wdHMgPT4gbmVlZCB0byBidWlsZCB1cCBiYiBmcm9tIGNvbWJpbmF0aW9uIG9mIHN1YiBiYnNcblxuXG4gICAgaWYgKCF1c2luZ0RlZk9wdHMpIHtcbiAgICAgIHZhciBpc05vZGUgPSBlbGUuaXNOb2RlKCk7XG4gICAgICBiYiA9IG1ha2VCb3VuZGluZ0JveCgpO1xuXG4gICAgICBpZiAob3B0cy5pbmNsdWRlTm9kZXMgJiYgaXNOb2RlIHx8IG9wdHMuaW5jbHVkZUVkZ2VzICYmICFpc05vZGUpIHtcbiAgICAgICAgaWYgKG9wdHMuaW5jbHVkZU92ZXJsYXlzKSB7XG4gICAgICAgICAgdXBkYXRlQm91bmRzRnJvbUJveChiYiwgX3Aub3ZlcmxheUJvdW5kcyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdXBkYXRlQm91bmRzRnJvbUJveChiYiwgX3AuYm9keUJvdW5kcyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKG9wdHMuaW5jbHVkZUxhYmVscykge1xuICAgICAgICBpZiAob3B0cy5pbmNsdWRlTWFpbkxhYmVscyAmJiAoIWlzRWRnZSB8fCBvcHRzLmluY2x1ZGVTb3VyY2VMYWJlbHMgJiYgb3B0cy5pbmNsdWRlVGFyZ2V0TGFiZWxzKSkge1xuICAgICAgICAgIHVwZGF0ZUJvdW5kc0Zyb21Cb3goYmIsIF9wLmxhYmVsQm91bmRzLmFsbCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYgKG9wdHMuaW5jbHVkZU1haW5MYWJlbHMpIHtcbiAgICAgICAgICAgIHVwZGF0ZUJvdW5kc0Zyb21Cb3goYmIsIF9wLmxhYmVsQm91bmRzLm1haW5Sb3QpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChvcHRzLmluY2x1ZGVTb3VyY2VMYWJlbHMpIHtcbiAgICAgICAgICAgIHVwZGF0ZUJvdW5kc0Zyb21Cb3goYmIsIF9wLmxhYmVsQm91bmRzLnNvdXJjZVJvdCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKG9wdHMuaW5jbHVkZVRhcmdldExhYmVscykge1xuICAgICAgICAgICAgdXBkYXRlQm91bmRzRnJvbUJveChiYiwgX3AubGFiZWxCb3VuZHMudGFyZ2V0Um90KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgYmIudyA9IGJiLngyIC0gYmIueDE7XG4gICAgICBiYi5oID0gYmIueTIgLSBiYi55MTtcbiAgICB9XG5cbiAgICByZXR1cm4gYmI7XG4gIH07XG5cbiAgdmFyIGRlZkJiT3B0cyA9IHtcbiAgICBpbmNsdWRlTm9kZXM6IHRydWUsXG4gICAgaW5jbHVkZUVkZ2VzOiB0cnVlLFxuICAgIGluY2x1ZGVMYWJlbHM6IHRydWUsXG4gICAgaW5jbHVkZU1haW5MYWJlbHM6IHRydWUsXG4gICAgaW5jbHVkZVNvdXJjZUxhYmVsczogdHJ1ZSxcbiAgICBpbmNsdWRlVGFyZ2V0TGFiZWxzOiB0cnVlLFxuICAgIGluY2x1ZGVPdmVybGF5czogdHJ1ZSxcbiAgICBpbmNsdWRlVW5kZXJsYXlzOiB0cnVlLFxuICAgIHVzZUNhY2hlOiB0cnVlXG4gIH07XG4gIHZhciBkZWZCYk9wdHNLZXkgPSBnZXRLZXkoZGVmQmJPcHRzKTtcbiAgdmFyIGZpbGxlZEJiT3B0cyA9IGRlZmF1bHRzJGcoZGVmQmJPcHRzKTtcblxuICBlbGVzZm4kYi5ib3VuZGluZ0JveCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGJvdW5kczsgLy8gdGhlIG1haW4gdXNlY2FzZSBpcyBlbGUuYm91bmRpbmdCb3goKSBmb3IgYSBzaW5nbGUgZWxlbWVudCB3aXRoIG5vL2RlZiBvcHRpb25zXG4gICAgLy8gc3BlY2lmaWVkIHMudC4gdGhlIGNhY2hlIGlzIHVzZWQsIHNvIGNoZWNrIGZvciB0aGlzIGNhc2UgdG8gbWFrZSBpdCBmYXN0ZXIgYnlcbiAgICAvLyBhdm9pZGluZyB0aGUgb3ZlcmhlYWQgb2YgdGhlIHJlc3Qgb2YgdGhlIGZ1bmN0aW9uXG5cbiAgICBpZiAodGhpcy5sZW5ndGggPT09IDEgJiYgdGhpc1swXS5fcHJpdmF0ZS5iYkNhY2hlICE9IG51bGwgJiYgIXRoaXNbMF0uX3ByaXZhdGUuc3R5bGVEaXJ0eSAmJiAob3B0aW9ucyA9PT0gdW5kZWZpbmVkIHx8IG9wdGlvbnMudXNlQ2FjaGUgPT09IHVuZGVmaW5lZCB8fCBvcHRpb25zLnVzZUNhY2hlID09PSB0cnVlKSkge1xuICAgICAgaWYgKG9wdGlvbnMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBvcHRpb25zID0gZGVmQmJPcHRzO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgb3B0aW9ucyA9IGZpbGxlZEJiT3B0cyhvcHRpb25zKTtcbiAgICAgIH1cblxuICAgICAgYm91bmRzID0gY2FjaGVkQm91bmRpbmdCb3hJbXBsKHRoaXNbMF0sIG9wdGlvbnMpO1xuICAgIH0gZWxzZSB7XG4gICAgICBib3VuZHMgPSBtYWtlQm91bmRpbmdCb3goKTtcbiAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IGRlZkJiT3B0cztcbiAgICAgIHZhciBvcHRzID0gZmlsbGVkQmJPcHRzKG9wdGlvbnMpO1xuICAgICAgdmFyIGVsZXMgPSB0aGlzO1xuICAgICAgdmFyIGN5ID0gZWxlcy5jeSgpO1xuICAgICAgdmFyIHN0eWxlRW5hYmxlZCA9IGN5LnN0eWxlRW5hYmxlZCgpO1xuXG4gICAgICBpZiAoc3R5bGVFbmFibGVkKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBlbGUgPSBlbGVzW2ldO1xuICAgICAgICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICAgICAgICB2YXIgY3VyclBvc0tleSA9IGdldEJvdW5kaW5nQm94UG9zS2V5KGVsZSk7XG4gICAgICAgICAgdmFyIGlzUG9zS2V5U2FtZSA9IF9wLmJiQ2FjaGVQb3NLZXkgPT09IGN1cnJQb3NLZXk7XG4gICAgICAgICAgdmFyIHVzZUNhY2hlID0gb3B0cy51c2VDYWNoZSAmJiBpc1Bvc0tleVNhbWUgJiYgIV9wLnN0eWxlRGlydHk7XG4gICAgICAgICAgZWxlLnJlY2FsY3VsYXRlUmVuZGVyZWRTdHlsZSh1c2VDYWNoZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy51cGRhdGVDb21wb3VuZEJvdW5kcyghb3B0aW9ucy51c2VDYWNoZSk7XG5cbiAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBlbGVzLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgX2VsZSA9IGVsZXNbX2ldO1xuICAgICAgICB1cGRhdGVCb3VuZHNGcm9tQm94KGJvdW5kcywgY2FjaGVkQm91bmRpbmdCb3hJbXBsKF9lbGUsIG9wdHMpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBib3VuZHMueDEgPSBub25pbmYoYm91bmRzLngxKTtcbiAgICBib3VuZHMueTEgPSBub25pbmYoYm91bmRzLnkxKTtcbiAgICBib3VuZHMueDIgPSBub25pbmYoYm91bmRzLngyKTtcbiAgICBib3VuZHMueTIgPSBub25pbmYoYm91bmRzLnkyKTtcbiAgICBib3VuZHMudyA9IG5vbmluZihib3VuZHMueDIgLSBib3VuZHMueDEpO1xuICAgIGJvdW5kcy5oID0gbm9uaW5mKGJvdW5kcy55MiAtIGJvdW5kcy55MSk7XG4gICAgcmV0dXJuIGJvdW5kcztcbiAgfTtcblxuICBlbGVzZm4kYi5kaXJ0eUJvdW5kaW5nQm94Q2FjaGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgX3AgPSB0aGlzW2ldLl9wcml2YXRlO1xuICAgICAgX3AuYmJDYWNoZSA9IG51bGw7XG4gICAgICBfcC5iYkNhY2hlUG9zS2V5ID0gbnVsbDtcbiAgICAgIF9wLmJvZHlCb3VuZHMgPSBudWxsO1xuICAgICAgX3Aub3ZlcmxheUJvdW5kcyA9IG51bGw7XG4gICAgICBfcC5sYWJlbEJvdW5kcy5hbGwgPSBudWxsO1xuICAgICAgX3AubGFiZWxCb3VuZHMuc291cmNlID0gbnVsbDtcbiAgICAgIF9wLmxhYmVsQm91bmRzLnRhcmdldCA9IG51bGw7XG4gICAgICBfcC5sYWJlbEJvdW5kcy5tYWluID0gbnVsbDtcbiAgICAgIF9wLmxhYmVsQm91bmRzLnNvdXJjZVJvdCA9IG51bGw7XG4gICAgICBfcC5sYWJlbEJvdW5kcy50YXJnZXRSb3QgPSBudWxsO1xuICAgICAgX3AubGFiZWxCb3VuZHMubWFpblJvdCA9IG51bGw7XG4gICAgICBfcC5hcnJvd0JvdW5kcy5zb3VyY2UgPSBudWxsO1xuICAgICAgX3AuYXJyb3dCb3VuZHMudGFyZ2V0ID0gbnVsbDtcbiAgICAgIF9wLmFycm93Qm91bmRzWydtaWQtc291cmNlJ10gPSBudWxsO1xuICAgICAgX3AuYXJyb3dCb3VuZHNbJ21pZC10YXJnZXQnXSA9IG51bGw7XG4gICAgfVxuXG4gICAgdGhpcy5lbWl0QW5kTm90aWZ5KCdib3VuZHMnKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfTsgLy8gcHJpdmF0ZSBoZWxwZXIgdG8gZ2V0IGJvdW5kaW5nIGJveCBmb3IgY3VzdG9tIG5vZGUgcG9zaXRpb25zXG4gIC8vIC0gZ29vZCBmb3IgcGVyZiBpbiBjZXJ0YWluIGNhc2VzIGJ1dCBjdXJyZW50bHkgcmVxdWlyZXMgZGlydHlpbmcgdGhlIHJlbmRlcmVkIHN0eWxlXG4gIC8vIC0gd291bGQgYmUgYmV0dGVyIHRvIG5vdCBtb2RpZnkgdGhlIG5vZGVzIGJ1dCB0aGUgbm9kZXMgYXJlIHJlYWQgZGlyZWN0bHkgZXZlcnl3aGVyZSBpbiB0aGUgcmVuZGVyZXIuLi5cbiAgLy8gLSB0cnkgdG8gdXNlIGZvciBvbmx5IHRoaW5ncyBsaWtlIGRpc2NyZXRlIGxheW91dHMgd2hlcmUgdGhlIG5vZGUgcG9zaXRpb24gd291bGQgY2hhbmdlIGFueXdheVxuXG5cbiAgZWxlc2ZuJGIuYm91bmRpbmdCb3hBdCA9IGZ1bmN0aW9uIChmbikge1xuICAgIHZhciBub2RlcyA9IHRoaXMubm9kZXMoKTtcbiAgICB2YXIgY3kgPSB0aGlzLmN5KCk7XG4gICAgdmFyIGhhc0NvbXBvdW5kTm9kZXMgPSBjeS5oYXNDb21wb3VuZE5vZGVzKCk7XG4gICAgdmFyIHBhcmVudHMgPSBjeS5jb2xsZWN0aW9uKCk7XG5cbiAgICBpZiAoaGFzQ29tcG91bmROb2Rlcykge1xuICAgICAgcGFyZW50cyA9IG5vZGVzLmZpbHRlcihmdW5jdGlvbiAobm9kZSkge1xuICAgICAgICByZXR1cm4gbm9kZS5pc1BhcmVudCgpO1xuICAgICAgfSk7XG4gICAgICBub2RlcyA9IG5vZGVzLm5vdChwYXJlbnRzKTtcbiAgICB9XG5cbiAgICBpZiAocGxhaW5PYmplY3QoZm4pKSB7XG4gICAgICB2YXIgb2JqID0gZm47XG5cbiAgICAgIGZuID0gZnVuY3Rpb24gZm4oKSB7XG4gICAgICAgIHJldHVybiBvYmo7XG4gICAgICB9O1xuICAgIH1cblxuICAgIHZhciBzdG9yZU9sZFBvcyA9IGZ1bmN0aW9uIHN0b3JlT2xkUG9zKG5vZGUsIGkpIHtcbiAgICAgIHJldHVybiBub2RlLl9wcml2YXRlLmJiQXRPbGRQb3MgPSBmbihub2RlLCBpKTtcbiAgICB9O1xuXG4gICAgdmFyIGdldE9sZFBvcyA9IGZ1bmN0aW9uIGdldE9sZFBvcyhub2RlKSB7XG4gICAgICByZXR1cm4gbm9kZS5fcHJpdmF0ZS5iYkF0T2xkUG9zO1xuICAgIH07XG5cbiAgICBjeS5zdGFydEJhdGNoKCk7XG4gICAgbm9kZXMuZm9yRWFjaChzdG9yZU9sZFBvcykuc2lsZW50UG9zaXRpb25zKGZuKTtcblxuICAgIGlmIChoYXNDb21wb3VuZE5vZGVzKSB7XG4gICAgICBwYXJlbnRzLmRpcnR5Q29tcG91bmRCb3VuZHNDYWNoZSgpO1xuICAgICAgcGFyZW50cy5kaXJ0eUJvdW5kaW5nQm94Q2FjaGUoKTtcbiAgICAgIHBhcmVudHMudXBkYXRlQ29tcG91bmRCb3VuZHModHJ1ZSk7IC8vIGZvcmNlIHVwZGF0ZSBiL2Mgd2UncmUgaW5zaWRlIGEgYmF0Y2ggY3ljbGVcbiAgICB9XG5cbiAgICB2YXIgYmIgPSBjb3B5Qm91bmRpbmdCb3godGhpcy5ib3VuZGluZ0JveCh7XG4gICAgICB1c2VDYWNoZTogZmFsc2VcbiAgICB9KSk7XG4gICAgbm9kZXMuc2lsZW50UG9zaXRpb25zKGdldE9sZFBvcyk7XG5cbiAgICBpZiAoaGFzQ29tcG91bmROb2Rlcykge1xuICAgICAgcGFyZW50cy5kaXJ0eUNvbXBvdW5kQm91bmRzQ2FjaGUoKTtcbiAgICAgIHBhcmVudHMuZGlydHlCb3VuZGluZ0JveENhY2hlKCk7XG4gICAgICBwYXJlbnRzLnVwZGF0ZUNvbXBvdW5kQm91bmRzKHRydWUpOyAvLyBmb3JjZSB1cGRhdGUgYi9jIHdlJ3JlIGluc2lkZSBhIGJhdGNoIGN5Y2xlXG4gICAgfVxuXG4gICAgY3kuZW5kQmF0Y2goKTtcbiAgICByZXR1cm4gYmI7XG4gIH07XG5cbiAgZm4kMy5ib3VuZGluZ2JveCA9IGZuJDMuYmIgPSBmbiQzLmJvdW5kaW5nQm94O1xuICBmbiQzLnJlbmRlcmVkQm91bmRpbmdib3ggPSBmbiQzLnJlbmRlcmVkQm91bmRpbmdCb3g7XG4gIHZhciBib3VuZHMgPSBlbGVzZm4kYjtcblxuICB2YXIgZm4kMiwgZWxlc2ZuJGE7XG4gIGZuJDIgPSBlbGVzZm4kYSA9IHt9O1xuXG4gIHZhciBkZWZpbmVEaW1GbnMgPSBmdW5jdGlvbiBkZWZpbmVEaW1GbnMob3B0cykge1xuICAgIG9wdHMudXBwZXJjYXNlTmFtZSA9IGNhcGl0YWxpemUob3B0cy5uYW1lKTtcbiAgICBvcHRzLmF1dG9OYW1lID0gJ2F1dG8nICsgb3B0cy51cHBlcmNhc2VOYW1lO1xuICAgIG9wdHMubGFiZWxOYW1lID0gJ2xhYmVsJyArIG9wdHMudXBwZXJjYXNlTmFtZTtcbiAgICBvcHRzLm91dGVyTmFtZSA9ICdvdXRlcicgKyBvcHRzLnVwcGVyY2FzZU5hbWU7XG4gICAgb3B0cy51cHBlcmNhc2VPdXRlck5hbWUgPSBjYXBpdGFsaXplKG9wdHMub3V0ZXJOYW1lKTtcblxuICAgIGZuJDJbb3B0cy5uYW1lXSA9IGZ1bmN0aW9uIGRpbUltcGwoKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1swXTtcbiAgICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICAgIHZhciBjeSA9IF9wLmN5O1xuICAgICAgdmFyIHN0eWxlRW5hYmxlZCA9IGN5Ll9wcml2YXRlLnN0eWxlRW5hYmxlZDtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICBpZiAoc3R5bGVFbmFibGVkKSB7XG4gICAgICAgICAgaWYgKGVsZS5pc1BhcmVudCgpKSB7XG4gICAgICAgICAgICBlbGUudXBkYXRlQ29tcG91bmRCb3VuZHMoKTtcbiAgICAgICAgICAgIHJldHVybiBfcFtvcHRzLmF1dG9OYW1lXSB8fCAwO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHZhciBkID0gZWxlLnBzdHlsZShvcHRzLm5hbWUpO1xuXG4gICAgICAgICAgc3dpdGNoIChkLnN0clZhbHVlKSB7XG4gICAgICAgICAgICBjYXNlICdsYWJlbCc6XG4gICAgICAgICAgICAgIGVsZS5yZWNhbGN1bGF0ZVJlbmRlcmVkU3R5bGUoKTtcbiAgICAgICAgICAgICAgcmV0dXJuIF9wLnJzdHlsZVtvcHRzLmxhYmVsTmFtZV0gfHwgMDtcblxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgcmV0dXJuIGQucGZWYWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgZm4kMlsnb3V0ZXInICsgb3B0cy51cHBlcmNhc2VOYW1lXSA9IGZ1bmN0aW9uIG91dGVyRGltSW1wbCgpIHtcbiAgICAgIHZhciBlbGUgPSB0aGlzWzBdO1xuICAgICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgICAgdmFyIGN5ID0gX3AuY3k7XG4gICAgICB2YXIgc3R5bGVFbmFibGVkID0gY3kuX3ByaXZhdGUuc3R5bGVFbmFibGVkO1xuXG4gICAgICBpZiAoZWxlKSB7XG4gICAgICAgIGlmIChzdHlsZUVuYWJsZWQpIHtcbiAgICAgICAgICB2YXIgZGltID0gZWxlW29wdHMubmFtZV0oKTtcbiAgICAgICAgICB2YXIgYm9yZGVyID0gZWxlLnBzdHlsZSgnYm9yZGVyLXdpZHRoJykucGZWYWx1ZTsgLy8gbi5iLiAxLzIgZWFjaCBzaWRlXG5cbiAgICAgICAgICB2YXIgcGFkZGluZyA9IDIgKiBlbGUucGFkZGluZygpO1xuICAgICAgICAgIHJldHVybiBkaW0gKyBib3JkZXIgKyBwYWRkaW5nO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIGZuJDJbJ3JlbmRlcmVkJyArIG9wdHMudXBwZXJjYXNlTmFtZV0gPSBmdW5jdGlvbiByZW5kZXJlZERpbUltcGwoKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1swXTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICB2YXIgZCA9IGVsZVtvcHRzLm5hbWVdKCk7XG4gICAgICAgIHJldHVybiBkICogdGhpcy5jeSgpLnpvb20oKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgZm4kMlsncmVuZGVyZWQnICsgb3B0cy51cHBlcmNhc2VPdXRlck5hbWVdID0gZnVuY3Rpb24gcmVuZGVyZWRPdXRlckRpbUltcGwoKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1swXTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICB2YXIgb2QgPSBlbGVbb3B0cy5vdXRlck5hbWVdKCk7XG4gICAgICAgIHJldHVybiBvZCAqIHRoaXMuY3koKS56b29tKCk7XG4gICAgICB9XG4gICAgfTtcbiAgfTtcblxuICBkZWZpbmVEaW1GbnMoe1xuICAgIG5hbWU6ICd3aWR0aCdcbiAgfSk7XG4gIGRlZmluZURpbUZucyh7XG4gICAgbmFtZTogJ2hlaWdodCdcbiAgfSk7XG5cbiAgZWxlc2ZuJGEucGFkZGluZyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZWxlID0gdGhpc1swXTtcbiAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG5cbiAgICBpZiAoZWxlLmlzUGFyZW50KCkpIHtcbiAgICAgIGVsZS51cGRhdGVDb21wb3VuZEJvdW5kcygpO1xuXG4gICAgICBpZiAoX3AuYXV0b1BhZGRpbmcgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gX3AuYXV0b1BhZGRpbmc7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gZWxlLnBzdHlsZSgncGFkZGluZycpLnBmVmFsdWU7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBlbGUucHN0eWxlKCdwYWRkaW5nJykucGZWYWx1ZTtcbiAgICB9XG4gIH07XG5cbiAgZWxlc2ZuJGEucGFkZGVkSGVpZ2h0ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBlbGUgPSB0aGlzWzBdO1xuICAgIHJldHVybiBlbGUuaGVpZ2h0KCkgKyAyICogZWxlLnBhZGRpbmcoKTtcbiAgfTtcblxuICBlbGVzZm4kYS5wYWRkZWRXaWR0aCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZWxlID0gdGhpc1swXTtcbiAgICByZXR1cm4gZWxlLndpZHRoKCkgKyAyICogZWxlLnBhZGRpbmcoKTtcbiAgfTtcblxuICB2YXIgd2lkdGhIZWlnaHQgPSBlbGVzZm4kYTtcblxuICB2YXIgaWZFZGdlID0gZnVuY3Rpb24gaWZFZGdlKGVsZSwgZ2V0VmFsdWUpIHtcbiAgICBpZiAoZWxlLmlzRWRnZSgpKSB7XG4gICAgICByZXR1cm4gZ2V0VmFsdWUoZWxlKTtcbiAgICB9XG4gIH07XG5cbiAgdmFyIGlmRWRnZVJlbmRlcmVkUG9zaXRpb24gPSBmdW5jdGlvbiBpZkVkZ2VSZW5kZXJlZFBvc2l0aW9uKGVsZSwgZ2V0UG9pbnQpIHtcbiAgICBpZiAoZWxlLmlzRWRnZSgpKSB7XG4gICAgICB2YXIgY3kgPSBlbGUuY3koKTtcbiAgICAgIHJldHVybiBtb2RlbFRvUmVuZGVyZWRQb3NpdGlvbihnZXRQb2ludChlbGUpLCBjeS56b29tKCksIGN5LnBhbigpKTtcbiAgICB9XG4gIH07XG5cbiAgdmFyIGlmRWRnZVJlbmRlcmVkUG9zaXRpb25zID0gZnVuY3Rpb24gaWZFZGdlUmVuZGVyZWRQb3NpdGlvbnMoZWxlLCBnZXRQb2ludHMpIHtcbiAgICBpZiAoZWxlLmlzRWRnZSgpKSB7XG4gICAgICB2YXIgY3kgPSBlbGUuY3koKTtcbiAgICAgIHZhciBwYW4gPSBjeS5wYW4oKTtcbiAgICAgIHZhciB6b29tID0gY3kuem9vbSgpO1xuICAgICAgcmV0dXJuIGdldFBvaW50cyhlbGUpLm1hcChmdW5jdGlvbiAocCkge1xuICAgICAgICByZXR1cm4gbW9kZWxUb1JlbmRlcmVkUG9zaXRpb24ocCwgem9vbSwgcGFuKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfTtcblxuICB2YXIgY29udHJvbFBvaW50cyA9IGZ1bmN0aW9uIGNvbnRyb2xQb2ludHMoZWxlKSB7XG4gICAgcmV0dXJuIGVsZS5yZW5kZXJlcigpLmdldENvbnRyb2xQb2ludHMoZWxlKTtcbiAgfTtcblxuICB2YXIgc2VnbWVudFBvaW50cyA9IGZ1bmN0aW9uIHNlZ21lbnRQb2ludHMoZWxlKSB7XG4gICAgcmV0dXJuIGVsZS5yZW5kZXJlcigpLmdldFNlZ21lbnRQb2ludHMoZWxlKTtcbiAgfTtcblxuICB2YXIgc291cmNlRW5kcG9pbnQgPSBmdW5jdGlvbiBzb3VyY2VFbmRwb2ludChlbGUpIHtcbiAgICByZXR1cm4gZWxlLnJlbmRlcmVyKCkuZ2V0U291cmNlRW5kcG9pbnQoZWxlKTtcbiAgfTtcblxuICB2YXIgdGFyZ2V0RW5kcG9pbnQgPSBmdW5jdGlvbiB0YXJnZXRFbmRwb2ludChlbGUpIHtcbiAgICByZXR1cm4gZWxlLnJlbmRlcmVyKCkuZ2V0VGFyZ2V0RW5kcG9pbnQoZWxlKTtcbiAgfTtcblxuICB2YXIgbWlkcG9pbnQgPSBmdW5jdGlvbiBtaWRwb2ludChlbGUpIHtcbiAgICByZXR1cm4gZWxlLnJlbmRlcmVyKCkuZ2V0RWRnZU1pZHBvaW50KGVsZSk7XG4gIH07XG5cbiAgdmFyIHB0cyA9IHtcbiAgICBjb250cm9sUG9pbnRzOiB7XG4gICAgICBnZXQ6IGNvbnRyb2xQb2ludHMsXG4gICAgICBtdWx0OiB0cnVlXG4gICAgfSxcbiAgICBzZWdtZW50UG9pbnRzOiB7XG4gICAgICBnZXQ6IHNlZ21lbnRQb2ludHMsXG4gICAgICBtdWx0OiB0cnVlXG4gICAgfSxcbiAgICBzb3VyY2VFbmRwb2ludDoge1xuICAgICAgZ2V0OiBzb3VyY2VFbmRwb2ludFxuICAgIH0sXG4gICAgdGFyZ2V0RW5kcG9pbnQ6IHtcbiAgICAgIGdldDogdGFyZ2V0RW5kcG9pbnRcbiAgICB9LFxuICAgIG1pZHBvaW50OiB7XG4gICAgICBnZXQ6IG1pZHBvaW50XG4gICAgfVxuICB9O1xuXG4gIHZhciByZW5kZXJlZE5hbWUgPSBmdW5jdGlvbiByZW5kZXJlZE5hbWUobmFtZSkge1xuICAgIHJldHVybiAncmVuZGVyZWQnICsgbmFtZVswXS50b1VwcGVyQ2FzZSgpICsgbmFtZS5zdWJzdHIoMSk7XG4gIH07XG5cbiAgdmFyIGVkZ2VQb2ludHMgPSBPYmplY3Qua2V5cyhwdHMpLnJlZHVjZShmdW5jdGlvbiAob2JqLCBuYW1lKSB7XG4gICAgdmFyIHNwZWMgPSBwdHNbbmFtZV07XG4gICAgdmFyIHJOYW1lID0gcmVuZGVyZWROYW1lKG5hbWUpO1xuXG4gICAgb2JqW25hbWVdID0gZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGlmRWRnZSh0aGlzLCBzcGVjLmdldCk7XG4gICAgfTtcblxuICAgIGlmIChzcGVjLm11bHQpIHtcbiAgICAgIG9ialtyTmFtZV0gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBpZkVkZ2VSZW5kZXJlZFBvc2l0aW9ucyh0aGlzLCBzcGVjLmdldCk7XG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICBvYmpbck5hbWVdID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gaWZFZGdlUmVuZGVyZWRQb3NpdGlvbih0aGlzLCBzcGVjLmdldCk7XG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBvYmo7XG4gIH0sIHt9KTtcblxuICB2YXIgZGltZW5zaW9ucyA9IGV4dGVuZCh7fSwgcG9zaXRpb24sIGJvdW5kcywgd2lkdGhIZWlnaHQsIGVkZ2VQb2ludHMpO1xuXG4gIC8qIVxuICBFdmVudCBvYmplY3QgYmFzZWQgb24galF1ZXJ5IGV2ZW50cywgTUlUIGxpY2Vuc2VcblxuICBodHRwczovL2pxdWVyeS5vcmcvbGljZW5zZS9cbiAgaHR0cHM6Ly90bGRybGVnYWwuY29tL2xpY2Vuc2UvbWl0LWxpY2Vuc2VcbiAgaHR0cHM6Ly9naXRodWIuY29tL2pxdWVyeS9qcXVlcnkvYmxvYi9tYXN0ZXIvc3JjL2V2ZW50LmpzXG4gICovXG4gIHZhciBFdmVudCA9IGZ1bmN0aW9uIEV2ZW50KHNyYywgcHJvcHMpIHtcbiAgICB0aGlzLnJlY3ljbGUoc3JjLCBwcm9wcyk7XG4gIH07XG5cbiAgZnVuY3Rpb24gcmV0dXJuRmFsc2UoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgZnVuY3Rpb24gcmV0dXJuVHJ1ZSgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSAvLyBodHRwOi8vd3d3LnczLm9yZy9UUi8yMDAzL1dELURPTS1MZXZlbC0zLUV2ZW50cy0yMDAzMDMzMS9lY21hLXNjcmlwdC1iaW5kaW5nLmh0bWxcblxuXG4gIEV2ZW50LnByb3RvdHlwZSA9IHtcbiAgICBpbnN0YW5jZVN0cmluZzogZnVuY3Rpb24gaW5zdGFuY2VTdHJpbmcoKSB7XG4gICAgICByZXR1cm4gJ2V2ZW50JztcbiAgICB9LFxuICAgIHJlY3ljbGU6IGZ1bmN0aW9uIHJlY3ljbGUoc3JjLCBwcm9wcykge1xuICAgICAgdGhpcy5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCA9IHRoaXMuaXNQcm9wYWdhdGlvblN0b3BwZWQgPSB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IHJldHVybkZhbHNlO1xuXG4gICAgICBpZiAoc3JjICE9IG51bGwgJiYgc3JjLnByZXZlbnREZWZhdWx0KSB7XG4gICAgICAgIC8vIEJyb3dzZXIgRXZlbnQgb2JqZWN0XG4gICAgICAgIHRoaXMudHlwZSA9IHNyYy50eXBlOyAvLyBFdmVudHMgYnViYmxpbmcgdXAgdGhlIGRvY3VtZW50IG1heSBoYXZlIGJlZW4gbWFya2VkIGFzIHByZXZlbnRlZFxuICAgICAgICAvLyBieSBhIGhhbmRsZXIgbG93ZXIgZG93biB0aGUgdHJlZTsgcmVmbGVjdCB0aGUgY29ycmVjdCB2YWx1ZS5cblxuICAgICAgICB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IHNyYy5kZWZhdWx0UHJldmVudGVkID8gcmV0dXJuVHJ1ZSA6IHJldHVybkZhbHNlO1xuICAgICAgfSBlbHNlIGlmIChzcmMgIT0gbnVsbCAmJiBzcmMudHlwZSkge1xuICAgICAgICAvLyBQbGFpbiBvYmplY3QgY29udGFpbmluZyBhbGwgZXZlbnQgZGV0YWlsc1xuICAgICAgICBwcm9wcyA9IHNyYztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEV2ZW50IHN0cmluZ1xuICAgICAgICB0aGlzLnR5cGUgPSBzcmM7XG4gICAgICB9IC8vIFB1dCBleHBsaWNpdGx5IHByb3ZpZGVkIHByb3BlcnRpZXMgb250byB0aGUgZXZlbnQgb2JqZWN0XG5cblxuICAgICAgaWYgKHByb3BzICE9IG51bGwpIHtcbiAgICAgICAgLy8gbW9yZSBlZmZpY2llbnQgdG8gbWFudWFsbHkgY29weSBmaWVsZHMgd2UgdXNlXG4gICAgICAgIHRoaXMub3JpZ2luYWxFdmVudCA9IHByb3BzLm9yaWdpbmFsRXZlbnQ7XG4gICAgICAgIHRoaXMudHlwZSA9IHByb3BzLnR5cGUgIT0gbnVsbCA/IHByb3BzLnR5cGUgOiB0aGlzLnR5cGU7XG4gICAgICAgIHRoaXMuY3kgPSBwcm9wcy5jeTtcbiAgICAgICAgdGhpcy50YXJnZXQgPSBwcm9wcy50YXJnZXQ7XG4gICAgICAgIHRoaXMucG9zaXRpb24gPSBwcm9wcy5wb3NpdGlvbjtcbiAgICAgICAgdGhpcy5yZW5kZXJlZFBvc2l0aW9uID0gcHJvcHMucmVuZGVyZWRQb3NpdGlvbjtcbiAgICAgICAgdGhpcy5uYW1lc3BhY2UgPSBwcm9wcy5uYW1lc3BhY2U7XG4gICAgICAgIHRoaXMubGF5b3V0ID0gcHJvcHMubGF5b3V0O1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5jeSAhPSBudWxsICYmIHRoaXMucG9zaXRpb24gIT0gbnVsbCAmJiB0aGlzLnJlbmRlcmVkUG9zaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAvLyBjcmVhdGUgYSByZW5kZXJlZCBwb3NpdGlvbiBiYXNlZCBvbiB0aGUgcGFzc2VkIHBvc2l0aW9uXG4gICAgICAgIHZhciBwb3MgPSB0aGlzLnBvc2l0aW9uO1xuICAgICAgICB2YXIgem9vbSA9IHRoaXMuY3kuem9vbSgpO1xuICAgICAgICB2YXIgcGFuID0gdGhpcy5jeS5wYW4oKTtcbiAgICAgICAgdGhpcy5yZW5kZXJlZFBvc2l0aW9uID0ge1xuICAgICAgICAgIHg6IHBvcy54ICogem9vbSArIHBhbi54LFxuICAgICAgICAgIHk6IHBvcy55ICogem9vbSArIHBhbi55XG4gICAgICAgIH07XG4gICAgICB9IC8vIENyZWF0ZSBhIHRpbWVzdGFtcCBpZiBpbmNvbWluZyBldmVudCBkb2Vzbid0IGhhdmUgb25lXG5cblxuICAgICAgdGhpcy50aW1lU3RhbXAgPSBzcmMgJiYgc3JjLnRpbWVTdGFtcCB8fCBEYXRlLm5vdygpO1xuICAgIH0sXG4gICAgcHJldmVudERlZmF1bHQ6IGZ1bmN0aW9uIHByZXZlbnREZWZhdWx0KCkge1xuICAgICAgdGhpcy5pc0RlZmF1bHRQcmV2ZW50ZWQgPSByZXR1cm5UcnVlO1xuICAgICAgdmFyIGUgPSB0aGlzLm9yaWdpbmFsRXZlbnQ7XG5cbiAgICAgIGlmICghZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIGlmIHByZXZlbnREZWZhdWx0IGV4aXN0cyBydW4gaXQgb24gdGhlIG9yaWdpbmFsIGV2ZW50XG5cblxuICAgICAgaWYgKGUucHJldmVudERlZmF1bHQpIHtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuICAgIH0sXG4gICAgc3RvcFByb3BhZ2F0aW9uOiBmdW5jdGlvbiBzdG9wUHJvcGFnYXRpb24oKSB7XG4gICAgICB0aGlzLmlzUHJvcGFnYXRpb25TdG9wcGVkID0gcmV0dXJuVHJ1ZTtcbiAgICAgIHZhciBlID0gdGhpcy5vcmlnaW5hbEV2ZW50O1xuXG4gICAgICBpZiAoIWUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBpZiBzdG9wUHJvcGFnYXRpb24gZXhpc3RzIHJ1biBpdCBvbiB0aGUgb3JpZ2luYWwgZXZlbnRcblxuXG4gICAgICBpZiAoZS5zdG9wUHJvcGFnYXRpb24pIHtcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgIH1cbiAgICB9LFxuICAgIHN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbjogZnVuY3Rpb24gc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCkge1xuICAgICAgdGhpcy5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCA9IHJldHVyblRydWU7XG4gICAgICB0aGlzLnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIH0sXG4gICAgaXNEZWZhdWx0UHJldmVudGVkOiByZXR1cm5GYWxzZSxcbiAgICBpc1Byb3BhZ2F0aW9uU3RvcHBlZDogcmV0dXJuRmFsc2UsXG4gICAgaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQ6IHJldHVybkZhbHNlXG4gIH07XG5cbiAgdmFyIGV2ZW50UmVnZXggPSAvXihbXi5dKykoXFwuKD86W14uXSspKT8kLzsgLy8gcmVnZXggZm9yIG1hdGNoaW5nIGV2ZW50IHN0cmluZ3MgKGUuZy4gXCJjbGljay5uYW1lc3BhY2VcIilcblxuICB2YXIgdW5pdmVyc2FsTmFtZXNwYWNlID0gJy4qJzsgLy8gbWF0Y2hlcyBhcyBpZiBubyBuYW1lc3BhY2Ugc3BlY2lmaWVkIGFuZCBwcmV2ZW50cyB1c2VycyBmcm9tIHVuYmluZGluZyBhY2NpZGVudGFsbHlcblxuICB2YXIgZGVmYXVsdHMkOCA9IHtcbiAgICBxdWFsaWZpZXJDb21wYXJlOiBmdW5jdGlvbiBxdWFsaWZpZXJDb21wYXJlKHExLCBxMikge1xuICAgICAgcmV0dXJuIHExID09PSBxMjtcbiAgICB9LFxuICAgIGV2ZW50TWF0Y2hlczogZnVuY3Rpb25cbiAgICAgIC8qY29udGV4dCwgbGlzdGVuZXIsIGV2ZW50T2JqKi9cbiAgICBldmVudE1hdGNoZXMoKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuICAgIGFkZEV2ZW50RmllbGRzOiBmdW5jdGlvblxuICAgICAgLypjb250ZXh0LCBldnQqL1xuICAgIGFkZEV2ZW50RmllbGRzKCkge30sXG4gICAgY2FsbGJhY2tDb250ZXh0OiBmdW5jdGlvbiBjYWxsYmFja0NvbnRleHQoY29udGV4dFxuICAgIC8qLCBsaXN0ZW5lciwgZXZlbnRPYmoqL1xuICAgICkge1xuICAgICAgcmV0dXJuIGNvbnRleHQ7XG4gICAgfSxcbiAgICBiZWZvcmVFbWl0OiBmdW5jdGlvblxuICAgICAgLyogY29udGV4dCwgbGlzdGVuZXIsIGV2ZW50T2JqICovXG4gICAgYmVmb3JlRW1pdCgpIHt9LFxuICAgIGFmdGVyRW1pdDogZnVuY3Rpb25cbiAgICAgIC8qIGNvbnRleHQsIGxpc3RlbmVyLCBldmVudE9iaiAqL1xuICAgIGFmdGVyRW1pdCgpIHt9LFxuICAgIGJ1YmJsZTogZnVuY3Rpb25cbiAgICAgIC8qY29udGV4dCovXG4gICAgYnViYmxlKCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0sXG4gICAgcGFyZW50OiBmdW5jdGlvblxuICAgICAgLypjb250ZXh0Ki9cbiAgICBwYXJlbnQoKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9LFxuICAgIGNvbnRleHQ6IG51bGxcbiAgfTtcbiAgdmFyIGRlZmF1bHRzS2V5cyA9IE9iamVjdC5rZXlzKGRlZmF1bHRzJDgpO1xuICB2YXIgZW1wdHlPcHRzID0ge307XG5cbiAgZnVuY3Rpb24gRW1pdHRlcigpIHtcbiAgICB2YXIgb3B0cyA9IGFyZ3VtZW50cy5sZW5ndGggPiAwICYmIGFyZ3VtZW50c1swXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzBdIDogZW1wdHlPcHRzO1xuICAgIHZhciBjb250ZXh0ID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBhcmd1bWVudHNbMV0gOiB1bmRlZmluZWQ7XG5cbiAgICAvLyBtaWNyby1vcHRpbWlzYXRpb24gdnMgT2JqZWN0LmFzc2lnbigpIC0tIHJlZHVjZXMgRWxlbWVudCBpbnN0YW50aWF0aW9uIHRpbWVcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGRlZmF1bHRzS2V5cy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGtleSA9IGRlZmF1bHRzS2V5c1tpXTtcbiAgICAgIHRoaXNba2V5XSA9IG9wdHNba2V5XSB8fCBkZWZhdWx0cyQ4W2tleV07XG4gICAgfVxuXG4gICAgdGhpcy5jb250ZXh0ID0gY29udGV4dCB8fCB0aGlzLmNvbnRleHQ7XG4gICAgdGhpcy5saXN0ZW5lcnMgPSBbXTtcbiAgICB0aGlzLmVtaXR0aW5nID0gMDtcbiAgfVxuXG4gIHZhciBwID0gRW1pdHRlci5wcm90b3R5cGU7XG5cbiAgdmFyIGZvckVhY2hFdmVudCA9IGZ1bmN0aW9uIGZvckVhY2hFdmVudChzZWxmLCBoYW5kbGVyLCBldmVudHMsIHF1YWxpZmllciwgY2FsbGJhY2ssIGNvbmYsIGNvbmZPdmVycmlkZXMpIHtcbiAgICBpZiAoZm4kNihxdWFsaWZpZXIpKSB7XG4gICAgICBjYWxsYmFjayA9IHF1YWxpZmllcjtcbiAgICAgIHF1YWxpZmllciA9IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKGNvbmZPdmVycmlkZXMpIHtcbiAgICAgIGlmIChjb25mID09IG51bGwpIHtcbiAgICAgICAgY29uZiA9IGNvbmZPdmVycmlkZXM7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25mID0gZXh0ZW5kKHt9LCBjb25mLCBjb25mT3ZlcnJpZGVzKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgZXZlbnRMaXN0ID0gYXJyYXkoZXZlbnRzKSA/IGV2ZW50cyA6IGV2ZW50cy5zcGxpdCgvXFxzKy8pO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBldmVudExpc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBldnQgPSBldmVudExpc3RbaV07XG5cbiAgICAgIGlmIChlbXB0eVN0cmluZyhldnQpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICB2YXIgbWF0Y2ggPSBldnQubWF0Y2goZXZlbnRSZWdleCk7IC8vIHR5cGVbLm5hbWVzcGFjZV1cblxuICAgICAgaWYgKG1hdGNoKSB7XG4gICAgICAgIHZhciB0eXBlID0gbWF0Y2hbMV07XG4gICAgICAgIHZhciBuYW1lc3BhY2UgPSBtYXRjaFsyXSA/IG1hdGNoWzJdIDogbnVsbDtcbiAgICAgICAgdmFyIHJldCA9IGhhbmRsZXIoc2VsZiwgZXZ0LCB0eXBlLCBuYW1lc3BhY2UsIHF1YWxpZmllciwgY2FsbGJhY2ssIGNvbmYpO1xuXG4gICAgICAgIGlmIChyZXQgPT09IGZhbHNlKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gLy8gYWxsb3cgZXhpdGluZyBlYXJseVxuXG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIHZhciBtYWtlRXZlbnRPYmogPSBmdW5jdGlvbiBtYWtlRXZlbnRPYmooc2VsZiwgb2JqKSB7XG4gICAgc2VsZi5hZGRFdmVudEZpZWxkcyhzZWxmLmNvbnRleHQsIG9iaik7XG4gICAgcmV0dXJuIG5ldyBFdmVudChvYmoudHlwZSwgb2JqKTtcbiAgfTtcblxuICB2YXIgZm9yRWFjaEV2ZW50T2JqID0gZnVuY3Rpb24gZm9yRWFjaEV2ZW50T2JqKHNlbGYsIGhhbmRsZXIsIGV2ZW50cykge1xuICAgIGlmIChldmVudChldmVudHMpKSB7XG4gICAgICBoYW5kbGVyKHNlbGYsIGV2ZW50cyk7XG4gICAgICByZXR1cm47XG4gICAgfSBlbHNlIGlmIChwbGFpbk9iamVjdChldmVudHMpKSB7XG4gICAgICBoYW5kbGVyKHNlbGYsIG1ha2VFdmVudE9iaihzZWxmLCBldmVudHMpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZXZlbnRMaXN0ID0gYXJyYXkoZXZlbnRzKSA/IGV2ZW50cyA6IGV2ZW50cy5zcGxpdCgvXFxzKy8pO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBldmVudExpc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBldnQgPSBldmVudExpc3RbaV07XG5cbiAgICAgIGlmIChlbXB0eVN0cmluZyhldnQpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICB2YXIgbWF0Y2ggPSBldnQubWF0Y2goZXZlbnRSZWdleCk7IC8vIHR5cGVbLm5hbWVzcGFjZV1cblxuICAgICAgaWYgKG1hdGNoKSB7XG4gICAgICAgIHZhciB0eXBlID0gbWF0Y2hbMV07XG4gICAgICAgIHZhciBuYW1lc3BhY2UgPSBtYXRjaFsyXSA/IG1hdGNoWzJdIDogbnVsbDtcbiAgICAgICAgdmFyIGV2ZW50T2JqID0gbWFrZUV2ZW50T2JqKHNlbGYsIHtcbiAgICAgICAgICB0eXBlOiB0eXBlLFxuICAgICAgICAgIG5hbWVzcGFjZTogbmFtZXNwYWNlLFxuICAgICAgICAgIHRhcmdldDogc2VsZi5jb250ZXh0XG4gICAgICAgIH0pO1xuICAgICAgICBoYW5kbGVyKHNlbGYsIGV2ZW50T2JqKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgcC5vbiA9IHAuYWRkTGlzdGVuZXIgPSBmdW5jdGlvbiAoZXZlbnRzLCBxdWFsaWZpZXIsIGNhbGxiYWNrLCBjb25mLCBjb25mT3ZlcnJpZGVzKSB7XG4gICAgZm9yRWFjaEV2ZW50KHRoaXMsIGZ1bmN0aW9uIChzZWxmLCBldmVudCwgdHlwZSwgbmFtZXNwYWNlLCBxdWFsaWZpZXIsIGNhbGxiYWNrLCBjb25mKSB7XG4gICAgICBpZiAoZm4kNihjYWxsYmFjaykpIHtcbiAgICAgICAgc2VsZi5saXN0ZW5lcnMucHVzaCh7XG4gICAgICAgICAgZXZlbnQ6IGV2ZW50LFxuICAgICAgICAgIC8vIGZ1bGwgZXZlbnQgc3RyaW5nXG4gICAgICAgICAgY2FsbGJhY2s6IGNhbGxiYWNrLFxuICAgICAgICAgIC8vIGNhbGxiYWNrIHRvIHJ1blxuICAgICAgICAgIHR5cGU6IHR5cGUsXG4gICAgICAgICAgLy8gdGhlIGV2ZW50IHR5cGUgKGUuZy4gJ2NsaWNrJylcbiAgICAgICAgICBuYW1lc3BhY2U6IG5hbWVzcGFjZSxcbiAgICAgICAgICAvLyB0aGUgZXZlbnQgbmFtZXNwYWNlIChlLmcuIFwiLmZvb1wiKVxuICAgICAgICAgIHF1YWxpZmllcjogcXVhbGlmaWVyLFxuICAgICAgICAgIC8vIGEgcmVzdHJpY3Rpb24gb24gd2hldGhlciB0byBtYXRjaCB0aGlzIGVtaXR0ZXJcbiAgICAgICAgICBjb25mOiBjb25mIC8vIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvblxuXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0sIGV2ZW50cywgcXVhbGlmaWVyLCBjYWxsYmFjaywgY29uZiwgY29uZk92ZXJyaWRlcyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH07XG5cbiAgcC5vbmUgPSBmdW5jdGlvbiAoZXZlbnRzLCBxdWFsaWZpZXIsIGNhbGxiYWNrLCBjb25mKSB7XG4gICAgcmV0dXJuIHRoaXMub24oZXZlbnRzLCBxdWFsaWZpZXIsIGNhbGxiYWNrLCBjb25mLCB7XG4gICAgICBvbmU6IHRydWVcbiAgICB9KTtcbiAgfTtcblxuICBwLnJlbW92ZUxpc3RlbmVyID0gcC5vZmYgPSBmdW5jdGlvbiAoZXZlbnRzLCBxdWFsaWZpZXIsIGNhbGxiYWNrLCBjb25mKSB7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIGlmICh0aGlzLmVtaXR0aW5nICE9PSAwKSB7XG4gICAgICB0aGlzLmxpc3RlbmVycyA9IGNvcHlBcnJheSQxKHRoaXMubGlzdGVuZXJzKTtcbiAgICB9XG5cbiAgICB2YXIgbGlzdGVuZXJzID0gdGhpcy5saXN0ZW5lcnM7XG5cbiAgICB2YXIgX2xvb3AgPSBmdW5jdGlvbiBfbG9vcChpKSB7XG4gICAgICB2YXIgbGlzdGVuZXIgPSBsaXN0ZW5lcnNbaV07XG4gICAgICBmb3JFYWNoRXZlbnQoX3RoaXMsIGZ1bmN0aW9uIChzZWxmLCBldmVudCwgdHlwZSwgbmFtZXNwYWNlLCBxdWFsaWZpZXIsIGNhbGxiYWNrXG4gICAgICAvKiwgY29uZiovXG4gICAgICApIHtcbiAgICAgICAgaWYgKChsaXN0ZW5lci50eXBlID09PSB0eXBlIHx8IGV2ZW50cyA9PT0gJyonKSAmJiAoIW5hbWVzcGFjZSAmJiBsaXN0ZW5lci5uYW1lc3BhY2UgIT09ICcuKicgfHwgbGlzdGVuZXIubmFtZXNwYWNlID09PSBuYW1lc3BhY2UpICYmICghcXVhbGlmaWVyIHx8IHNlbGYucXVhbGlmaWVyQ29tcGFyZShsaXN0ZW5lci5xdWFsaWZpZXIsIHF1YWxpZmllcikpICYmICghY2FsbGJhY2sgfHwgbGlzdGVuZXIuY2FsbGJhY2sgPT09IGNhbGxiYWNrKSkge1xuICAgICAgICAgIGxpc3RlbmVycy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9LCBldmVudHMsIHF1YWxpZmllciwgY2FsbGJhY2ssIGNvbmYpO1xuICAgIH07XG5cbiAgICBmb3IgKHZhciBpID0gbGlzdGVuZXJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICBfbG9vcChpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfTtcblxuICBwLnJlbW92ZUFsbExpc3RlbmVycyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5yZW1vdmVMaXN0ZW5lcignKicpO1xuICB9O1xuXG4gIHAuZW1pdCA9IHAudHJpZ2dlciA9IGZ1bmN0aW9uIChldmVudHMsIGV4dHJhUGFyYW1zLCBtYW51YWxDYWxsYmFjaykge1xuICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLmxpc3RlbmVycztcbiAgICB2YXIgbnVtTGlzdGVuZXJzQmVmb3JlRW1pdCA9IGxpc3RlbmVycy5sZW5ndGg7XG4gICAgdGhpcy5lbWl0dGluZysrO1xuXG4gICAgaWYgKCFhcnJheShleHRyYVBhcmFtcykpIHtcbiAgICAgIGV4dHJhUGFyYW1zID0gW2V4dHJhUGFyYW1zXTtcbiAgICB9XG5cbiAgICBmb3JFYWNoRXZlbnRPYmoodGhpcywgZnVuY3Rpb24gKHNlbGYsIGV2ZW50T2JqKSB7XG4gICAgICBpZiAobWFudWFsQ2FsbGJhY2sgIT0gbnVsbCkge1xuICAgICAgICBsaXN0ZW5lcnMgPSBbe1xuICAgICAgICAgIGV2ZW50OiBldmVudE9iai5ldmVudCxcbiAgICAgICAgICB0eXBlOiBldmVudE9iai50eXBlLFxuICAgICAgICAgIG5hbWVzcGFjZTogZXZlbnRPYmoubmFtZXNwYWNlLFxuICAgICAgICAgIGNhbGxiYWNrOiBtYW51YWxDYWxsYmFja1xuICAgICAgICB9XTtcbiAgICAgICAgbnVtTGlzdGVuZXJzQmVmb3JlRW1pdCA9IGxpc3RlbmVycy5sZW5ndGg7XG4gICAgICB9XG5cbiAgICAgIHZhciBfbG9vcDIgPSBmdW5jdGlvbiBfbG9vcDIoaSkge1xuICAgICAgICB2YXIgbGlzdGVuZXIgPSBsaXN0ZW5lcnNbaV07XG5cbiAgICAgICAgaWYgKGxpc3RlbmVyLnR5cGUgPT09IGV2ZW50T2JqLnR5cGUgJiYgKCFsaXN0ZW5lci5uYW1lc3BhY2UgfHwgbGlzdGVuZXIubmFtZXNwYWNlID09PSBldmVudE9iai5uYW1lc3BhY2UgfHwgbGlzdGVuZXIubmFtZXNwYWNlID09PSB1bml2ZXJzYWxOYW1lc3BhY2UpICYmIHNlbGYuZXZlbnRNYXRjaGVzKHNlbGYuY29udGV4dCwgbGlzdGVuZXIsIGV2ZW50T2JqKSkge1xuICAgICAgICAgIHZhciBhcmdzID0gW2V2ZW50T2JqXTtcblxuICAgICAgICAgIGlmIChleHRyYVBhcmFtcyAhPSBudWxsKSB7XG4gICAgICAgICAgICBwdXNoKGFyZ3MsIGV4dHJhUGFyYW1zKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzZWxmLmJlZm9yZUVtaXQoc2VsZi5jb250ZXh0LCBsaXN0ZW5lciwgZXZlbnRPYmopO1xuXG4gICAgICAgICAgaWYgKGxpc3RlbmVyLmNvbmYgJiYgbGlzdGVuZXIuY29uZi5vbmUpIHtcbiAgICAgICAgICAgIHNlbGYubGlzdGVuZXJzID0gc2VsZi5saXN0ZW5lcnMuZmlsdGVyKGZ1bmN0aW9uIChsKSB7XG4gICAgICAgICAgICAgIHJldHVybiBsICE9PSBsaXN0ZW5lcjtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHZhciBjb250ZXh0ID0gc2VsZi5jYWxsYmFja0NvbnRleHQoc2VsZi5jb250ZXh0LCBsaXN0ZW5lciwgZXZlbnRPYmopO1xuICAgICAgICAgIHZhciByZXQgPSBsaXN0ZW5lci5jYWxsYmFjay5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgICBzZWxmLmFmdGVyRW1pdChzZWxmLmNvbnRleHQsIGxpc3RlbmVyLCBldmVudE9iaik7XG5cbiAgICAgICAgICBpZiAocmV0ID09PSBmYWxzZSkge1xuICAgICAgICAgICAgZXZlbnRPYmouc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICBldmVudE9iai5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSAvLyBpZiBsaXN0ZW5lciBtYXRjaGVzXG5cbiAgICAgIH07XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbnVtTGlzdGVuZXJzQmVmb3JlRW1pdDsgaSsrKSB7XG4gICAgICAgIF9sb29wMihpKTtcbiAgICAgIH0gLy8gZm9yIGxpc3RlbmVyXG5cblxuICAgICAgaWYgKHNlbGYuYnViYmxlKHNlbGYuY29udGV4dCkgJiYgIWV2ZW50T2JqLmlzUHJvcGFnYXRpb25TdG9wcGVkKCkpIHtcbiAgICAgICAgc2VsZi5wYXJlbnQoc2VsZi5jb250ZXh0KS5lbWl0KGV2ZW50T2JqLCBleHRyYVBhcmFtcyk7XG4gICAgICB9XG4gICAgfSwgZXZlbnRzKTtcbiAgICB0aGlzLmVtaXR0aW5nLS07XG4gICAgcmV0dXJuIHRoaXM7XG4gIH07XG5cbiAgdmFyIGVtaXR0ZXJPcHRpb25zJDEgPSB7XG4gICAgcXVhbGlmaWVyQ29tcGFyZTogZnVuY3Rpb24gcXVhbGlmaWVyQ29tcGFyZShzZWxlY3RvcjEsIHNlbGVjdG9yMikge1xuICAgICAgaWYgKHNlbGVjdG9yMSA9PSBudWxsIHx8IHNlbGVjdG9yMiA9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiBzZWxlY3RvcjEgPT0gbnVsbCAmJiBzZWxlY3RvcjIgPT0gbnVsbDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBzZWxlY3RvcjEuc2FtZVRleHQoc2VsZWN0b3IyKTtcbiAgICAgIH1cbiAgICB9LFxuICAgIGV2ZW50TWF0Y2hlczogZnVuY3Rpb24gZXZlbnRNYXRjaGVzKGVsZSwgbGlzdGVuZXIsIGV2ZW50T2JqKSB7XG4gICAgICB2YXIgc2VsZWN0b3IgPSBsaXN0ZW5lci5xdWFsaWZpZXI7XG5cbiAgICAgIGlmIChzZWxlY3RvciAhPSBudWxsKSB7XG4gICAgICAgIHJldHVybiBlbGUgIT09IGV2ZW50T2JqLnRhcmdldCAmJiBlbGVtZW50KGV2ZW50T2JqLnRhcmdldCkgJiYgc2VsZWN0b3IubWF0Y2hlcyhldmVudE9iai50YXJnZXQpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuICAgIGFkZEV2ZW50RmllbGRzOiBmdW5jdGlvbiBhZGRFdmVudEZpZWxkcyhlbGUsIGV2dCkge1xuICAgICAgZXZ0LmN5ID0gZWxlLmN5KCk7XG4gICAgICBldnQudGFyZ2V0ID0gZWxlO1xuICAgIH0sXG4gICAgY2FsbGJhY2tDb250ZXh0OiBmdW5jdGlvbiBjYWxsYmFja0NvbnRleHQoZWxlLCBsaXN0ZW5lciwgZXZlbnRPYmopIHtcbiAgICAgIHJldHVybiBsaXN0ZW5lci5xdWFsaWZpZXIgIT0gbnVsbCA/IGV2ZW50T2JqLnRhcmdldCA6IGVsZTtcbiAgICB9LFxuICAgIGJlZm9yZUVtaXQ6IGZ1bmN0aW9uIGJlZm9yZUVtaXQoY29udGV4dCwgbGlzdGVuZXJcbiAgICAvKiwgZXZlbnRPYmoqL1xuICAgICkge1xuICAgICAgaWYgKGxpc3RlbmVyLmNvbmYgJiYgbGlzdGVuZXIuY29uZi5vbmNlKSB7XG4gICAgICAgIGxpc3RlbmVyLmNvbmYub25jZUNvbGxlY3Rpb24ucmVtb3ZlTGlzdGVuZXIobGlzdGVuZXIuZXZlbnQsIGxpc3RlbmVyLnF1YWxpZmllciwgbGlzdGVuZXIuY2FsbGJhY2spO1xuICAgICAgfVxuICAgIH0sXG4gICAgYnViYmxlOiBmdW5jdGlvbiBidWJibGUoKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuICAgIHBhcmVudDogZnVuY3Rpb24gcGFyZW50KGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS5pc0NoaWxkKCkgPyBlbGUucGFyZW50KCkgOiBlbGUuY3koKTtcbiAgICB9XG4gIH07XG5cbiAgdmFyIGFyZ1NlbGVjdG9yJDEgPSBmdW5jdGlvbiBhcmdTZWxlY3RvcihhcmcpIHtcbiAgICBpZiAoc3RyaW5nKGFyZykpIHtcbiAgICAgIHJldHVybiBuZXcgU2VsZWN0b3IoYXJnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGFyZztcbiAgICB9XG4gIH07XG5cbiAgdmFyIGVsZXNmbiQ5ID0ge1xuICAgIGNyZWF0ZUVtaXR0ZXI6IGZ1bmN0aW9uIGNyZWF0ZUVtaXR0ZXIoKSB7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG4gICAgICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcblxuICAgICAgICBpZiAoIV9wLmVtaXR0ZXIpIHtcbiAgICAgICAgICBfcC5lbWl0dGVyID0gbmV3IEVtaXR0ZXIoZW1pdHRlck9wdGlvbnMkMSwgZWxlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIGVtaXR0ZXI6IGZ1bmN0aW9uIGVtaXR0ZXIoKSB7XG4gICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5lbWl0dGVyO1xuICAgIH0sXG4gICAgb246IGZ1bmN0aW9uIG9uKGV2ZW50cywgc2VsZWN0b3IsIGNhbGxiYWNrKSB7XG4gICAgICB2YXIgYXJnU2VsID0gYXJnU2VsZWN0b3IkMShzZWxlY3Rvcik7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWxlID0gdGhpc1tpXTtcbiAgICAgICAgZWxlLmVtaXR0ZXIoKS5vbihldmVudHMsIGFyZ1NlbCwgY2FsbGJhY2spO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIHJlbW92ZUxpc3RlbmVyOiBmdW5jdGlvbiByZW1vdmVMaXN0ZW5lcihldmVudHMsIHNlbGVjdG9yLCBjYWxsYmFjaykge1xuICAgICAgdmFyIGFyZ1NlbCA9IGFyZ1NlbGVjdG9yJDEoc2VsZWN0b3IpO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG4gICAgICAgIGVsZS5lbWl0dGVyKCkucmVtb3ZlTGlzdGVuZXIoZXZlbnRzLCBhcmdTZWwsIGNhbGxiYWNrKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICByZW1vdmVBbGxMaXN0ZW5lcnM6IGZ1bmN0aW9uIHJlbW92ZUFsbExpc3RlbmVycygpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWxlID0gdGhpc1tpXTtcbiAgICAgICAgZWxlLmVtaXR0ZXIoKS5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICBvbmU6IGZ1bmN0aW9uIG9uZShldmVudHMsIHNlbGVjdG9yLCBjYWxsYmFjaykge1xuICAgICAgdmFyIGFyZ1NlbCA9IGFyZ1NlbGVjdG9yJDEoc2VsZWN0b3IpO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG4gICAgICAgIGVsZS5lbWl0dGVyKCkub25lKGV2ZW50cywgYXJnU2VsLCBjYWxsYmFjayk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgb25jZTogZnVuY3Rpb24gb25jZShldmVudHMsIHNlbGVjdG9yLCBjYWxsYmFjaykge1xuICAgICAgdmFyIGFyZ1NlbCA9IGFyZ1NlbGVjdG9yJDEoc2VsZWN0b3IpO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG4gICAgICAgIGVsZS5lbWl0dGVyKCkub24oZXZlbnRzLCBhcmdTZWwsIGNhbGxiYWNrLCB7XG4gICAgICAgICAgb25jZTogdHJ1ZSxcbiAgICAgICAgICBvbmNlQ29sbGVjdGlvbjogdGhpc1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9LFxuICAgIGVtaXQ6IGZ1bmN0aW9uIGVtaXQoZXZlbnRzLCBleHRyYVBhcmFtcykge1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBlbGUgPSB0aGlzW2ldO1xuICAgICAgICBlbGUuZW1pdHRlcigpLmVtaXQoZXZlbnRzLCBleHRyYVBhcmFtcyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgZW1pdEFuZE5vdGlmeTogZnVuY3Rpb24gZW1pdEFuZE5vdGlmeShldmVudCwgZXh0cmFQYXJhbXMpIHtcbiAgICAgIC8vIGZvciBpbnRlcm5hbCB1c2Ugb25seVxuICAgICAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gZW1wdHkgY29sbGVjdGlvbnMgZG9uJ3QgbmVlZCB0byBub3RpZnkgYW55dGhpbmdcbiAgICAgIC8vIG5vdGlmeSByZW5kZXJlclxuXG5cbiAgICAgIHRoaXMuY3koKS5ub3RpZnkoZXZlbnQsIHRoaXMpO1xuICAgICAgdGhpcy5lbWl0KGV2ZW50LCBleHRyYVBhcmFtcyk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG4gIH07XG4gIGRlZmluZS5ldmVudEFsaWFzZXNPbihlbGVzZm4kOSk7XG5cbiAgdmFyIGVsZXNmbiQ4ID0ge1xuICAgIG5vZGVzOiBmdW5jdGlvbiBub2RlcyhzZWxlY3Rvcikge1xuICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgICAgcmV0dXJuIGVsZS5pc05vZGUoKTtcbiAgICAgIH0pLmZpbHRlcihzZWxlY3Rvcik7XG4gICAgfSxcbiAgICBlZGdlczogZnVuY3Rpb24gZWRnZXMoc2VsZWN0b3IpIHtcbiAgICAgIHJldHVybiB0aGlzLmZpbHRlcihmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgIHJldHVybiBlbGUuaXNFZGdlKCk7XG4gICAgICB9KS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgIH0sXG4gICAgLy8gaW50ZXJuYWwgaGVscGVyIHRvIGdldCBub2RlcyBhbmQgZWRnZXMgYXMgc2VwYXJhdGUgY29sbGVjdGlvbnMgd2l0aCBzaW5nbGUgaXRlcmF0aW9uIG92ZXIgZWxlbWVudHNcbiAgICBieUdyb3VwOiBmdW5jdGlvbiBieUdyb3VwKCkge1xuICAgICAgdmFyIG5vZGVzID0gdGhpcy5zcGF3bigpO1xuICAgICAgdmFyIGVkZ2VzID0gdGhpcy5zcGF3bigpO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG5cbiAgICAgICAgaWYgKGVsZS5pc05vZGUoKSkge1xuICAgICAgICAgIG5vZGVzLnB1c2goZWxlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBlZGdlcy5wdXNoKGVsZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbm9kZXM6IG5vZGVzLFxuICAgICAgICBlZGdlczogZWRnZXNcbiAgICAgIH07XG4gICAgfSxcbiAgICBmaWx0ZXI6IGZ1bmN0aW9uIGZpbHRlcihfZmlsdGVyLCB0aGlzQXJnKSB7XG4gICAgICBpZiAoX2ZpbHRlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIC8vIGNoZWNrIHRoaXMgZmlyc3QgYi9jIGl0J3MgdGhlIG1vc3QgY29tbW9uL3BlcmZvcm1hbnQgY2FzZVxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH0gZWxzZSBpZiAoc3RyaW5nKF9maWx0ZXIpIHx8IGVsZW1lbnRPckNvbGxlY3Rpb24oX2ZpbHRlcikpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBTZWxlY3RvcihfZmlsdGVyKS5maWx0ZXIodGhpcyk7XG4gICAgICB9IGVsc2UgaWYgKGZuJDYoX2ZpbHRlcikpIHtcbiAgICAgICAgdmFyIGZpbHRlckVsZXMgPSB0aGlzLnNwYXduKCk7XG4gICAgICAgIHZhciBlbGVzID0gdGhpcztcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWxlID0gZWxlc1tpXTtcbiAgICAgICAgICB2YXIgaW5jbHVkZSA9IHRoaXNBcmcgPyBfZmlsdGVyLmFwcGx5KHRoaXNBcmcsIFtlbGUsIGksIGVsZXNdKSA6IF9maWx0ZXIoZWxlLCBpLCBlbGVzKTtcblxuICAgICAgICAgIGlmIChpbmNsdWRlKSB7XG4gICAgICAgICAgICBmaWx0ZXJFbGVzLnB1c2goZWxlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmlsdGVyRWxlcztcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXMuc3Bhd24oKTsgLy8gaWYgbm90IGhhbmRsZWQgYnkgYWJvdmUsIGdpdmUgJ2VtIGFuIGVtcHR5IGNvbGxlY3Rpb25cbiAgICB9LFxuICAgIG5vdDogZnVuY3Rpb24gbm90KHRvUmVtb3ZlKSB7XG4gICAgICBpZiAoIXRvUmVtb3ZlKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHN0cmluZyh0b1JlbW92ZSkpIHtcbiAgICAgICAgICB0b1JlbW92ZSA9IHRoaXMuZmlsdGVyKHRvUmVtb3ZlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBlbGVtZW50cyA9IHRoaXMuc3Bhd24oKTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWxlbWVudCA9IHRoaXNbaV07XG4gICAgICAgICAgdmFyIHJlbW92ZSA9IHRvUmVtb3ZlLmhhcyhlbGVtZW50KTtcblxuICAgICAgICAgIGlmICghcmVtb3ZlKSB7XG4gICAgICAgICAgICBlbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGVtZW50cztcbiAgICAgIH1cbiAgICB9LFxuICAgIGFic29sdXRlQ29tcGxlbWVudDogZnVuY3Rpb24gYWJzb2x1dGVDb21wbGVtZW50KCkge1xuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuICAgICAgcmV0dXJuIGN5Lm11dGFibGVFbGVtZW50cygpLm5vdCh0aGlzKTtcbiAgICB9LFxuICAgIGludGVyc2VjdDogZnVuY3Rpb24gaW50ZXJzZWN0KG90aGVyKSB7XG4gICAgICAvLyBpZiBhIHNlbGVjdG9yIGlzIHNwZWNpZmllZCwgdGhlbiBmaWx0ZXIgYnkgaXQgaW5zdGVhZFxuICAgICAgaWYgKHN0cmluZyhvdGhlcikpIHtcbiAgICAgICAgdmFyIHNlbGVjdG9yID0gb3RoZXI7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbHRlcihzZWxlY3Rvcik7XG4gICAgICB9XG5cbiAgICAgIHZhciBlbGVtZW50cyA9IHRoaXMuc3Bhd24oKTtcbiAgICAgIHZhciBjb2wxID0gdGhpcztcbiAgICAgIHZhciBjb2wyID0gb3RoZXI7XG4gICAgICB2YXIgY29sMVNtYWxsZXIgPSB0aGlzLmxlbmd0aCA8IG90aGVyLmxlbmd0aDtcbiAgICAgIHZhciBjb2xTID0gY29sMVNtYWxsZXIgPyBjb2wxIDogY29sMjtcbiAgICAgIHZhciBjb2xMID0gY29sMVNtYWxsZXIgPyBjb2wyIDogY29sMTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb2xTLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBlbGUgPSBjb2xTW2ldO1xuXG4gICAgICAgIGlmIChjb2xMLmhhcyhlbGUpKSB7XG4gICAgICAgICAgZWxlbWVudHMucHVzaChlbGUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBlbGVtZW50cztcbiAgICB9LFxuICAgIHhvcjogZnVuY3Rpb24geG9yKG90aGVyKSB7XG4gICAgICB2YXIgY3kgPSB0aGlzLl9wcml2YXRlLmN5O1xuXG4gICAgICBpZiAoc3RyaW5nKG90aGVyKSkge1xuICAgICAgICBvdGhlciA9IGN5LiQob3RoZXIpO1xuICAgICAgfVxuXG4gICAgICB2YXIgZWxlbWVudHMgPSB0aGlzLnNwYXduKCk7XG4gICAgICB2YXIgY29sMSA9IHRoaXM7XG4gICAgICB2YXIgY29sMiA9IG90aGVyO1xuXG4gICAgICB2YXIgYWRkID0gZnVuY3Rpb24gYWRkKGNvbCwgb3RoZXIpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb2wubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWxlID0gY29sW2ldO1xuICAgICAgICAgIHZhciBpZCA9IGVsZS5fcHJpdmF0ZS5kYXRhLmlkO1xuICAgICAgICAgIHZhciBpbk90aGVyID0gb3RoZXIuaGFzRWxlbWVudFdpdGhJZChpZCk7XG5cbiAgICAgICAgICBpZiAoIWluT3RoZXIpIHtcbiAgICAgICAgICAgIGVsZW1lbnRzLnB1c2goZWxlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIGFkZChjb2wxLCBjb2wyKTtcbiAgICAgIGFkZChjb2wyLCBjb2wxKTtcbiAgICAgIHJldHVybiBlbGVtZW50cztcbiAgICB9LFxuICAgIGRpZmY6IGZ1bmN0aW9uIGRpZmYob3RoZXIpIHtcbiAgICAgIHZhciBjeSA9IHRoaXMuX3ByaXZhdGUuY3k7XG5cbiAgICAgIGlmIChzdHJpbmcob3RoZXIpKSB7XG4gICAgICAgIG90aGVyID0gY3kuJChvdGhlcik7XG4gICAgICB9XG5cbiAgICAgIHZhciBsZWZ0ID0gdGhpcy5zcGF3bigpO1xuICAgICAgdmFyIHJpZ2h0ID0gdGhpcy5zcGF3bigpO1xuICAgICAgdmFyIGJvdGggPSB0aGlzLnNwYXduKCk7XG4gICAgICB2YXIgY29sMSA9IHRoaXM7XG4gICAgICB2YXIgY29sMiA9IG90aGVyO1xuXG4gICAgICB2YXIgYWRkID0gZnVuY3Rpb24gYWRkKGNvbCwgb3RoZXIsIHJldEVsZXMpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb2wubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWxlID0gY29sW2ldO1xuICAgICAgICAgIHZhciBpZCA9IGVsZS5fcHJpdmF0ZS5kYXRhLmlkO1xuICAgICAgICAgIHZhciBpbk90aGVyID0gb3RoZXIuaGFzRWxlbWVudFdpdGhJZChpZCk7XG5cbiAgICAgICAgICBpZiAoaW5PdGhlcikge1xuICAgICAgICAgICAgYm90aC5tZXJnZShlbGUpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXRFbGVzLnB1c2goZWxlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIGFkZChjb2wxLCBjb2wyLCBsZWZ0KTtcbiAgICAgIGFkZChjb2wyLCBjb2wxLCByaWdodCk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBsZWZ0OiBsZWZ0LFxuICAgICAgICByaWdodDogcmlnaHQsXG4gICAgICAgIGJvdGg6IGJvdGhcbiAgICAgIH07XG4gICAgfSxcbiAgICBhZGQ6IGZ1bmN0aW9uIGFkZCh0b0FkZCkge1xuICAgICAgdmFyIGN5ID0gdGhpcy5fcHJpdmF0ZS5jeTtcblxuICAgICAgaWYgKCF0b0FkZCkge1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cblxuICAgICAgaWYgKHN0cmluZyh0b0FkZCkpIHtcbiAgICAgICAgdmFyIHNlbGVjdG9yID0gdG9BZGQ7XG4gICAgICAgIHRvQWRkID0gY3kubXV0YWJsZUVsZW1lbnRzKCkuZmlsdGVyKHNlbGVjdG9yKTtcbiAgICAgIH1cblxuICAgICAgdmFyIGVsZW1lbnRzID0gdGhpcy5zcGF3blNlbGYoKTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0b0FkZC5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWxlID0gdG9BZGRbaV07XG4gICAgICAgIHZhciBhZGQgPSAhdGhpcy5oYXMoZWxlKTtcblxuICAgICAgICBpZiAoYWRkKSB7XG4gICAgICAgICAgZWxlbWVudHMucHVzaChlbGUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBlbGVtZW50cztcbiAgICB9LFxuICAgIC8vIGluIHBsYWNlIG1lcmdlIG9uIGNhbGxpbmcgY29sbGVjdGlvblxuICAgIG1lcmdlOiBmdW5jdGlvbiBtZXJnZSh0b0FkZCkge1xuICAgICAgdmFyIF9wID0gdGhpcy5fcHJpdmF0ZTtcbiAgICAgIHZhciBjeSA9IF9wLmN5O1xuXG4gICAgICBpZiAoIXRvQWRkKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuXG4gICAgICBpZiAodG9BZGQgJiYgc3RyaW5nKHRvQWRkKSkge1xuICAgICAgICB2YXIgc2VsZWN0b3IgPSB0b0FkZDtcbiAgICAgICAgdG9BZGQgPSBjeS5tdXRhYmxlRWxlbWVudHMoKS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgICAgfVxuXG4gICAgICB2YXIgbWFwID0gX3AubWFwO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRvQWRkLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciB0b0FkZEVsZSA9IHRvQWRkW2ldO1xuICAgICAgICB2YXIgaWQgPSB0b0FkZEVsZS5fcHJpdmF0ZS5kYXRhLmlkO1xuICAgICAgICB2YXIgYWRkID0gIW1hcC5oYXMoaWQpO1xuXG4gICAgICAgIGlmIChhZGQpIHtcbiAgICAgICAgICB2YXIgaW5kZXggPSB0aGlzLmxlbmd0aCsrO1xuICAgICAgICAgIHRoaXNbaW5kZXhdID0gdG9BZGRFbGU7XG4gICAgICAgICAgbWFwLnNldChpZCwge1xuICAgICAgICAgICAgZWxlOiB0b0FkZEVsZSxcbiAgICAgICAgICAgIGluZGV4OiBpbmRleFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICAgIH0sXG4gICAgdW5tZXJnZUF0OiBmdW5jdGlvbiB1bm1lcmdlQXQoaSkge1xuICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG4gICAgICB2YXIgaWQgPSBlbGUuaWQoKTtcbiAgICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG4gICAgICB2YXIgbWFwID0gX3AubWFwOyAvLyByZW1vdmUgZWxlXG5cbiAgICAgIHRoaXNbaV0gPSB1bmRlZmluZWQ7XG4gICAgICBtYXBbXCJkZWxldGVcIl0oaWQpO1xuICAgICAgdmFyIHVubWVyZ2VkTGFzdEVsZSA9IGkgPT09IHRoaXMubGVuZ3RoIC0gMTsgLy8gcmVwbGFjZSBlbXB0eSBzcG90IHdpdGggbGFzdCBlbGUgaW4gY29sbGVjdGlvblxuXG4gICAgICBpZiAodGhpcy5sZW5ndGggPiAxICYmICF1bm1lcmdlZExhc3RFbGUpIHtcbiAgICAgICAgdmFyIGxhc3RFbGVJID0gdGhpcy5sZW5ndGggLSAxO1xuICAgICAgICB2YXIgbGFzdEVsZSA9IHRoaXNbbGFzdEVsZUldO1xuICAgICAgICB2YXIgbGFzdEVsZUlkID0gbGFzdEVsZS5fcHJpdmF0ZS5kYXRhLmlkO1xuICAgICAgICB0aGlzW2xhc3RFbGVJXSA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpc1tpXSA9IGxhc3RFbGU7XG4gICAgICAgIG1hcC5zZXQobGFzdEVsZUlkLCB7XG4gICAgICAgICAgZWxlOiBsYXN0RWxlLFxuICAgICAgICAgIGluZGV4OiBpXG4gICAgICAgIH0pO1xuICAgICAgfSAvLyB0aGUgY29sbGVjdGlvbiBpcyBub3cgMSBlbGUgc21hbGxlclxuXG5cbiAgICAgIHRoaXMubGVuZ3RoLS07XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIC8vIHJlbW92ZSBzaW5nbGUgZWxlIGluIHBsYWNlIGluIGNhbGxpbmcgY29sbGVjdGlvblxuICAgIHVubWVyZ2VPbmU6IGZ1bmN0aW9uIHVubWVyZ2VPbmUoZWxlKSB7XG4gICAgICBlbGUgPSBlbGVbMF07XG4gICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuICAgICAgdmFyIGlkID0gZWxlLl9wcml2YXRlLmRhdGEuaWQ7XG4gICAgICB2YXIgbWFwID0gX3AubWFwO1xuICAgICAgdmFyIGVudHJ5ID0gbWFwLmdldChpZCk7XG5cbiAgICAgIGlmICghZW50cnkpIHtcbiAgICAgICAgcmV0dXJuIHRoaXM7IC8vIG5vIG5lZWQgdG8gcmVtb3ZlXG4gICAgICB9XG5cbiAgICAgIHZhciBpID0gZW50cnkuaW5kZXg7XG4gICAgICB0aGlzLnVubWVyZ2VBdChpKTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgLy8gcmVtb3ZlIGVsZXMgaW4gcGxhY2Ugb24gY2FsbGluZyBjb2xsZWN0aW9uXG4gICAgdW5tZXJnZTogZnVuY3Rpb24gdW5tZXJnZSh0b1JlbW92ZSkge1xuICAgICAgdmFyIGN5ID0gdGhpcy5fcHJpdmF0ZS5jeTtcblxuICAgICAgaWYgKCF0b1JlbW92ZSkge1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cblxuICAgICAgaWYgKHRvUmVtb3ZlICYmIHN0cmluZyh0b1JlbW92ZSkpIHtcbiAgICAgICAgdmFyIHNlbGVjdG9yID0gdG9SZW1vdmU7XG4gICAgICAgIHRvUmVtb3ZlID0gY3kubXV0YWJsZUVsZW1lbnRzKCkuZmlsdGVyKHNlbGVjdG9yKTtcbiAgICAgIH1cblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0b1JlbW92ZS5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLnVubWVyZ2VPbmUodG9SZW1vdmVbaV0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgICB9LFxuICAgIHVubWVyZ2VCeTogZnVuY3Rpb24gdW5tZXJnZUJ5KHRvUm1Gbikge1xuICAgICAgZm9yICh2YXIgaSA9IHRoaXMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG5cbiAgICAgICAgaWYgKHRvUm1GbihlbGUpKSB7XG4gICAgICAgICAgdGhpcy51bm1lcmdlQXQoaSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICBtYXA6IGZ1bmN0aW9uIG1hcChtYXBGbiwgdGhpc0FyZykge1xuICAgICAgdmFyIGFyciA9IFtdO1xuICAgICAgdmFyIGVsZXMgPSB0aGlzO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG4gICAgICAgIHZhciByZXQgPSB0aGlzQXJnID8gbWFwRm4uYXBwbHkodGhpc0FyZywgW2VsZSwgaSwgZWxlc10pIDogbWFwRm4oZWxlLCBpLCBlbGVzKTtcbiAgICAgICAgYXJyLnB1c2gocmV0KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGFycjtcbiAgICB9LFxuICAgIHJlZHVjZTogZnVuY3Rpb24gcmVkdWNlKGZuLCBpbml0aWFsVmFsdWUpIHtcbiAgICAgIHZhciB2YWwgPSBpbml0aWFsVmFsdWU7XG4gICAgICB2YXIgZWxlcyA9IHRoaXM7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YWwgPSBmbih2YWwsIGVsZXNbaV0sIGksIGVsZXMpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdmFsO1xuICAgIH0sXG4gICAgbWF4OiBmdW5jdGlvbiBtYXgodmFsRm4sIHRoaXNBcmcpIHtcbiAgICAgIHZhciBtYXggPSAtSW5maW5pdHk7XG4gICAgICB2YXIgbWF4RWxlO1xuICAgICAgdmFyIGVsZXMgPSB0aGlzO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG4gICAgICAgIHZhciB2YWwgPSB0aGlzQXJnID8gdmFsRm4uYXBwbHkodGhpc0FyZywgW2VsZSwgaSwgZWxlc10pIDogdmFsRm4oZWxlLCBpLCBlbGVzKTtcblxuICAgICAgICBpZiAodmFsID4gbWF4KSB7XG4gICAgICAgICAgbWF4ID0gdmFsO1xuICAgICAgICAgIG1heEVsZSA9IGVsZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZTogbWF4LFxuICAgICAgICBlbGU6IG1heEVsZVxuICAgICAgfTtcbiAgICB9LFxuICAgIG1pbjogZnVuY3Rpb24gbWluKHZhbEZuLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgbWluID0gSW5maW5pdHk7XG4gICAgICB2YXIgbWluRWxlO1xuICAgICAgdmFyIGVsZXMgPSB0aGlzO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG4gICAgICAgIHZhciB2YWwgPSB0aGlzQXJnID8gdmFsRm4uYXBwbHkodGhpc0FyZywgW2VsZSwgaSwgZWxlc10pIDogdmFsRm4oZWxlLCBpLCBlbGVzKTtcblxuICAgICAgICBpZiAodmFsIDwgbWluKSB7XG4gICAgICAgICAgbWluID0gdmFsO1xuICAgICAgICAgIG1pbkVsZSA9IGVsZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZTogbWluLFxuICAgICAgICBlbGU6IG1pbkVsZVxuICAgICAgfTtcbiAgICB9XG4gIH07IC8vIGFsaWFzZXNcblxuICB2YXIgZm4kMSA9IGVsZXNmbiQ4O1xuICBmbiQxWyd1J10gPSBmbiQxWyd8J10gPSBmbiQxWycrJ10gPSBmbiQxLnVuaW9uID0gZm4kMS5vciA9IGZuJDEuYWRkO1xuICBmbiQxWydcXFxcJ10gPSBmbiQxWychJ10gPSBmbiQxWyctJ10gPSBmbiQxLmRpZmZlcmVuY2UgPSBmbiQxLnJlbGF0aXZlQ29tcGxlbWVudCA9IGZuJDEuc3VidHJhY3QgPSBmbiQxLm5vdDtcbiAgZm4kMVsnbiddID0gZm4kMVsnJiddID0gZm4kMVsnLiddID0gZm4kMS5hbmQgPSBmbiQxLmludGVyc2VjdGlvbiA9IGZuJDEuaW50ZXJzZWN0O1xuICBmbiQxWydeJ10gPSBmbiQxWycoKyknXSA9IGZuJDFbJygtKSddID0gZm4kMS5zeW1tZXRyaWNEaWZmZXJlbmNlID0gZm4kMS5zeW1kaWZmID0gZm4kMS54b3I7XG4gIGZuJDEuZm5GaWx0ZXIgPSBmbiQxLmZpbHRlckZuID0gZm4kMS5zdGRGaWx0ZXIgPSBmbiQxLmZpbHRlcjtcbiAgZm4kMS5jb21wbGVtZW50ID0gZm4kMS5hYnNjb21wID0gZm4kMS5hYnNvbHV0ZUNvbXBsZW1lbnQ7XG5cbiAgdmFyIGVsZXNmbiQ3ID0ge1xuICAgIGlzTm9kZTogZnVuY3Rpb24gaXNOb2RlKCkge1xuICAgICAgcmV0dXJuIHRoaXMuZ3JvdXAoKSA9PT0gJ25vZGVzJztcbiAgICB9LFxuICAgIGlzRWRnZTogZnVuY3Rpb24gaXNFZGdlKCkge1xuICAgICAgcmV0dXJuIHRoaXMuZ3JvdXAoKSA9PT0gJ2VkZ2VzJztcbiAgICB9LFxuICAgIGlzTG9vcDogZnVuY3Rpb24gaXNMb29wKCkge1xuICAgICAgcmV0dXJuIHRoaXMuaXNFZGdlKCkgJiYgdGhpcy5zb3VyY2UoKVswXSA9PT0gdGhpcy50YXJnZXQoKVswXTtcbiAgICB9LFxuICAgIGlzU2ltcGxlOiBmdW5jdGlvbiBpc1NpbXBsZSgpIHtcbiAgICAgIHJldHVybiB0aGlzLmlzRWRnZSgpICYmIHRoaXMuc291cmNlKClbMF0gIT09IHRoaXMudGFyZ2V0KClbMF07XG4gICAgfSxcbiAgICBncm91cDogZnVuY3Rpb24gZ3JvdXAoKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1swXTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICByZXR1cm4gZWxlLl9wcml2YXRlLmdyb3VwO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICAvKipcbiAgICogIEVsZW1lbnRzIGFyZSBkcmF3biBpbiBhIHNwZWNpZmljIG9yZGVyIGJhc2VkIG9uIGNvbXBvdW5kIGRlcHRoIChsb3cgdG8gaGlnaCksIHRoZSBlbGVtZW50IHR5cGUgKG5vZGVzIGFib3ZlIGVkZ2VzKSxcbiAgICogIGFuZCB6LWluZGV4IChsb3cgdG8gaGlnaCkuICBUaGVzZSBzdHlsZXMgYWZmZWN0IGhvdyB0aGlzIGFwcGxpZXM6XG4gICAqXG4gICAqICB6LWNvbXBvdW5kLWRlcHRoOiBNYXkgYmUgYGJvdHRvbSB8IG9ycGhhbiB8IGF1dG8gfCB0b3BgLiAgVGhlIGZpcnN0IGRyYXduIGlzIGBib3R0b21gLCB0aGVuIGBvcnBoYW5gIHdoaWNoIGlzIHRoZVxuICAgKiAgICAgIHNhbWUgZGVwdGggYXMgdGhlIHJvb3Qgb2YgdGhlIGNvbXBvdW5kIGdyYXBoLCBmb2xsb3dlZCBieSB0aGUgZGVmYXVsdCB2YWx1ZSBgYXV0b2Agd2hpY2ggZHJhd3MgaW4gb3JkZXIgZnJvbVxuICAgKiAgICAgIHJvb3QgdG8gbGVhdmVzIG9mIHRoZSBjb21wb3VuZCBncmFwaC4gIFRoZSBsYXN0IGRyYXduIGlzIGB0b3BgLlxuICAgKiAgei1pbmRleC1jb21wYXJlOiBNYXkgYmUgYGF1dG8gfCBtYW51YWxgLiAgVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGF1dG9gIHdoaWNoIGFsd2F5cyBkcmF3cyBlZGdlcyB1bmRlciBub2Rlcy5cbiAgICogICAgICBgbWFudWFsYCBpZ25vcmVzIHRoaXMgY29udmVudGlvbiBhbmQgZHJhd3MgYmFzZWQgb24gdGhlIGB6LWluZGV4YCB2YWx1ZSBzZXR0aW5nLlxuICAgKiAgei1pbmRleDogQW4gaW50ZWdlciB2YWx1ZSB0aGF0IGFmZmVjdHMgdGhlIHJlbGF0aXZlIGRyYXcgb3JkZXIgb2YgZWxlbWVudHMuICBJbiBnZW5lcmFsLCBhbiBlbGVtZW50IHdpdGggYSBoaWdoZXJcbiAgICogICAgICBgei1pbmRleGAgd2lsbCBiZSBkcmF3biBvbiB0b3Agb2YgYW4gZWxlbWVudCB3aXRoIGEgbG93ZXIgYHotaW5kZXhgLlxuICAgKi9cblxuICB2YXIgekluZGV4U29ydCA9IGZ1bmN0aW9uIHpJbmRleFNvcnQoYSwgYikge1xuICAgIHZhciBjeSA9IGEuY3koKTtcbiAgICB2YXIgaGFzQ29tcG91bmROb2RlcyA9IGN5Lmhhc0NvbXBvdW5kTm9kZXMoKTtcblxuICAgIGZ1bmN0aW9uIGdldERlcHRoKGVsZSkge1xuICAgICAgdmFyIHN0eWxlID0gZWxlLnBzdHlsZSgnei1jb21wb3VuZC1kZXB0aCcpO1xuXG4gICAgICBpZiAoc3R5bGUudmFsdWUgPT09ICdhdXRvJykge1xuICAgICAgICByZXR1cm4gaGFzQ29tcG91bmROb2RlcyA/IGVsZS56RGVwdGgoKSA6IDA7XG4gICAgICB9IGVsc2UgaWYgKHN0eWxlLnZhbHVlID09PSAnYm90dG9tJykge1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgICB9IGVsc2UgaWYgKHN0eWxlLnZhbHVlID09PSAndG9wJykge1xuICAgICAgICByZXR1cm4gTUFYX0lOVCQxO1xuICAgICAgfSAvLyAnb3JwaGFuJ1xuXG5cbiAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIHZhciBkZXB0aERpZmYgPSBnZXREZXB0aChhKSAtIGdldERlcHRoKGIpO1xuXG4gICAgaWYgKGRlcHRoRGlmZiAhPT0gMCkge1xuICAgICAgcmV0dXJuIGRlcHRoRGlmZjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRFbGVEZXB0aChlbGUpIHtcbiAgICAgIHZhciBzdHlsZSA9IGVsZS5wc3R5bGUoJ3otaW5kZXgtY29tcGFyZScpO1xuXG4gICAgICBpZiAoc3R5bGUudmFsdWUgPT09ICdhdXRvJykge1xuICAgICAgICByZXR1cm4gZWxlLmlzTm9kZSgpID8gMSA6IDA7XG4gICAgICB9IC8vICdtYW51YWwnXG5cblxuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgdmFyIGVsZURpZmYgPSBnZXRFbGVEZXB0aChhKSAtIGdldEVsZURlcHRoKGIpO1xuXG4gICAgaWYgKGVsZURpZmYgIT09IDApIHtcbiAgICAgIHJldHVybiBlbGVEaWZmO1xuICAgIH1cblxuICAgIHZhciB6RGlmZiA9IGEucHN0eWxlKCd6LWluZGV4JykudmFsdWUgLSBiLnBzdHlsZSgnei1pbmRleCcpLnZhbHVlO1xuXG4gICAgaWYgKHpEaWZmICE9PSAwKSB7XG4gICAgICByZXR1cm4gekRpZmY7XG4gICAgfSAvLyBjb21wYXJlIGluZGljZXMgaW4gdGhlIGNvcmUgKG9yZGVyIGFkZGVkIHRvIGdyYXBoIHcvIGxhc3Qgb24gdG9wKVxuXG5cbiAgICByZXR1cm4gYS5wb29sSW5kZXgoKSAtIGIucG9vbEluZGV4KCk7XG4gIH07XG5cbiAgdmFyIGVsZXNmbiQ2ID0ge1xuICAgIGZvckVhY2g6IGZ1bmN0aW9uIGZvckVhY2goZm4sIHRoaXNBcmcpIHtcbiAgICAgIGlmIChmbiQ2KGZuKSkge1xuICAgICAgICB2YXIgTiA9IHRoaXMubGVuZ3RoO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgTjsgaSsrKSB7XG4gICAgICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG4gICAgICAgICAgdmFyIHJldCA9IHRoaXNBcmcgPyBmbi5hcHBseSh0aGlzQXJnLCBbZWxlLCBpLCB0aGlzXSkgOiBmbihlbGUsIGksIHRoaXMpO1xuXG4gICAgICAgICAgaWYgKHJldCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH0gLy8gZXhpdCBlYWNoIGVhcmx5IG9uIHJldHVybiBmYWxzZVxuXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICB0b0FycmF5OiBmdW5jdGlvbiB0b0FycmF5KCkge1xuICAgICAgdmFyIGFycmF5ID0gW107XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBhcnJheS5wdXNoKHRoaXNbaV0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gYXJyYXk7XG4gICAgfSxcbiAgICBzbGljZTogZnVuY3Rpb24gc2xpY2Uoc3RhcnQsIGVuZCkge1xuICAgICAgdmFyIGFycmF5ID0gW107XG4gICAgICB2YXIgdGhpc1NpemUgPSB0aGlzLmxlbmd0aDtcblxuICAgICAgaWYgKGVuZCA9PSBudWxsKSB7XG4gICAgICAgIGVuZCA9IHRoaXNTaXplO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3RhcnQgPT0gbnVsbCkge1xuICAgICAgICBzdGFydCA9IDA7XG4gICAgICB9XG5cbiAgICAgIGlmIChzdGFydCA8IDApIHtcbiAgICAgICAgc3RhcnQgPSB0aGlzU2l6ZSArIHN0YXJ0O1xuICAgICAgfVxuXG4gICAgICBpZiAoZW5kIDwgMCkge1xuICAgICAgICBlbmQgPSB0aGlzU2l6ZSArIGVuZDtcbiAgICAgIH1cblxuICAgICAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpID49IDAgJiYgaSA8IGVuZCAmJiBpIDwgdGhpc1NpemU7IGkrKykge1xuICAgICAgICBhcnJheS5wdXNoKHRoaXNbaV0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcy5zcGF3bihhcnJheSk7XG4gICAgfSxcbiAgICBzaXplOiBmdW5jdGlvbiBzaXplKCkge1xuICAgICAgcmV0dXJuIHRoaXMubGVuZ3RoO1xuICAgIH0sXG4gICAgZXE6IGZ1bmN0aW9uIGVxKGkpIHtcbiAgICAgIHJldHVybiB0aGlzW2ldIHx8IHRoaXMuc3Bhd24oKTtcbiAgICB9LFxuICAgIGZpcnN0OiBmdW5jdGlvbiBmaXJzdCgpIHtcbiAgICAgIHJldHVybiB0aGlzWzBdIHx8IHRoaXMuc3Bhd24oKTtcbiAgICB9LFxuICAgIGxhc3Q6IGZ1bmN0aW9uIGxhc3QoKSB7XG4gICAgICByZXR1cm4gdGhpc1t0aGlzLmxlbmd0aCAtIDFdIHx8IHRoaXMuc3Bhd24oKTtcbiAgICB9LFxuICAgIGVtcHR5OiBmdW5jdGlvbiBlbXB0eSgpIHtcbiAgICAgIHJldHVybiB0aGlzLmxlbmd0aCA9PT0gMDtcbiAgICB9LFxuICAgIG5vbmVtcHR5OiBmdW5jdGlvbiBub25lbXB0eSgpIHtcbiAgICAgIHJldHVybiAhdGhpcy5lbXB0eSgpO1xuICAgIH0sXG4gICAgc29ydDogZnVuY3Rpb24gc29ydChzb3J0Rm4pIHtcbiAgICAgIGlmICghZm4kNihzb3J0Rm4pKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuXG4gICAgICB2YXIgc29ydGVkID0gdGhpcy50b0FycmF5KCkuc29ydChzb3J0Rm4pO1xuICAgICAgcmV0dXJuIHRoaXMuc3Bhd24oc29ydGVkKTtcbiAgICB9LFxuICAgIHNvcnRCeVpJbmRleDogZnVuY3Rpb24gc29ydEJ5WkluZGV4KCkge1xuICAgICAgcmV0dXJuIHRoaXMuc29ydCh6SW5kZXhTb3J0KTtcbiAgICB9LFxuICAgIHpEZXB0aDogZnVuY3Rpb24gekRlcHRoKCkge1xuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICAgIGlmICghZWxlKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9IC8vIGxldCBjeSA9IGVsZS5jeSgpO1xuXG5cbiAgICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICAgIHZhciBncm91cCA9IF9wLmdyb3VwO1xuXG4gICAgICBpZiAoZ3JvdXAgPT09ICdub2RlcycpIHtcbiAgICAgICAgdmFyIGRlcHRoID0gX3AuZGF0YS5wYXJlbnQgPyBlbGUucGFyZW50cygpLnNpemUoKSA6IDA7XG5cbiAgICAgICAgaWYgKCFlbGUuaXNQYXJlbnQoKSkge1xuICAgICAgICAgIHJldHVybiBNQVhfSU5UJDEgLSAxOyAvLyBjaGlsZGxlc3Mgbm9kZXMgYWx3YXlzIG9uIHRvcFxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGRlcHRoO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIHNyYyA9IF9wLnNvdXJjZTtcbiAgICAgICAgdmFyIHRndCA9IF9wLnRhcmdldDtcbiAgICAgICAgdmFyIHNyY0RlcHRoID0gc3JjLnpEZXB0aCgpO1xuICAgICAgICB2YXIgdGd0RGVwdGggPSB0Z3QuekRlcHRoKCk7XG4gICAgICAgIHJldHVybiBNYXRoLm1heChzcmNEZXB0aCwgdGd0RGVwdGgsIDApOyAvLyBkZXB0aCBvZiBkZWVwZXN0IHBhcmVudFxuICAgICAgfVxuICAgIH1cbiAgfTtcbiAgZWxlc2ZuJDYuZWFjaCA9IGVsZXNmbiQ2LmZvckVhY2g7XG5cbiAgdmFyIGRlZmluZVN5bWJvbEl0ZXJhdG9yID0gZnVuY3Rpb24gZGVmaW5lU3ltYm9sSXRlcmF0b3IoKSB7XG4gICAgdmFyIHR5cGVvZlVuZGVmID0gXCJ1bmRlZmluZWRcIiA7XG4gICAgdmFyIGlzSXRlcmF0b3JTdXBwb3J0ZWQgPSAodHlwZW9mIFN5bWJvbCA9PT0gXCJ1bmRlZmluZWRcIiA/IFwidW5kZWZpbmVkXCIgOiBfdHlwZW9mKFN5bWJvbCkpICE9IHR5cGVvZlVuZGVmICYmIF90eXBlb2YoU3ltYm9sLml0ZXJhdG9yKSAhPSB0eXBlb2ZVbmRlZjsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuXG4gICAgaWYgKGlzSXRlcmF0b3JTdXBwb3J0ZWQpIHtcbiAgICAgIGVsZXNmbiQ2W1N5bWJvbC5pdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuICAgICAgICB2YXIgZW50cnkgPSB7XG4gICAgICAgICAgdmFsdWU6IHVuZGVmaW5lZCxcbiAgICAgICAgICBkb25lOiBmYWxzZVxuICAgICAgICB9O1xuICAgICAgICB2YXIgaSA9IDA7XG4gICAgICAgIHZhciBsZW5ndGggPSB0aGlzLmxlbmd0aDtcbiAgICAgICAgcmV0dXJuIF9kZWZpbmVQcm9wZXJ0eSQxKHtcbiAgICAgICAgICBuZXh0OiBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKGkgPCBsZW5ndGgpIHtcbiAgICAgICAgICAgICAgZW50cnkudmFsdWUgPSBfdGhpc1tpKytdO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgZW50cnkudmFsdWUgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgIGVudHJ5LmRvbmUgPSB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gZW50cnk7XG4gICAgICAgICAgfVxuICAgICAgICB9LCBTeW1ib2wuaXRlcmF0b3IsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0pO1xuICAgICAgfTtcbiAgICB9XG4gIH07XG5cbiAgZGVmaW5lU3ltYm9sSXRlcmF0b3IoKTtcblxuICB2YXIgZ2V0TGF5b3V0RGltZW5zaW9uT3B0aW9ucyA9IGRlZmF1bHRzJGcoe1xuICAgIG5vZGVEaW1lbnNpb25zSW5jbHVkZUxhYmVsczogZmFsc2VcbiAgfSk7XG4gIHZhciBlbGVzZm4kNSA9IHtcbiAgICAvLyBDYWxjdWxhdGVzIGFuZCByZXR1cm5zIG5vZGUgZGltZW5zaW9ucyB7IHgsIHkgfSBiYXNlZCBvbiBvcHRpb25zIGdpdmVuXG4gICAgbGF5b3V0RGltZW5zaW9uczogZnVuY3Rpb24gbGF5b3V0RGltZW5zaW9ucyhvcHRpb25zKSB7XG4gICAgICBvcHRpb25zID0gZ2V0TGF5b3V0RGltZW5zaW9uT3B0aW9ucyhvcHRpb25zKTtcbiAgICAgIHZhciBkaW1zO1xuXG4gICAgICBpZiAoIXRoaXMudGFrZXNVcFNwYWNlKCkpIHtcbiAgICAgICAgZGltcyA9IHtcbiAgICAgICAgICB3OiAwLFxuICAgICAgICAgIGg6IDBcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5ub2RlRGltZW5zaW9uc0luY2x1ZGVMYWJlbHMpIHtcbiAgICAgICAgdmFyIGJiRGltID0gdGhpcy5ib3VuZGluZ0JveCgpO1xuICAgICAgICBkaW1zID0ge1xuICAgICAgICAgIHc6IGJiRGltLncsXG4gICAgICAgICAgaDogYmJEaW0uaFxuICAgICAgICB9O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGltcyA9IHtcbiAgICAgICAgICB3OiB0aGlzLm91dGVyV2lkdGgoKSxcbiAgICAgICAgICBoOiB0aGlzLm91dGVySGVpZ2h0KClcbiAgICAgICAgfTtcbiAgICAgIH0gLy8gc2FuaXRpc2UgdGhlIGRpbWVuc2lvbnMgZm9yIGV4dGVybmFsIGxheW91dHMgKGF2b2lkIGRpdmlzaW9uIGJ5IHplcm8pXG5cblxuICAgICAgaWYgKGRpbXMudyA9PT0gMCB8fCBkaW1zLmggPT09IDApIHtcbiAgICAgICAgZGltcy53ID0gZGltcy5oID0gMTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGRpbXM7XG4gICAgfSxcbiAgICAvLyB1c2luZyBzdGFuZGFyZCBsYXlvdXQgb3B0aW9ucywgYXBwbHkgcG9zaXRpb24gZnVuY3Rpb24gKHcvIG9yIHcvbyBhbmltYXRpb24pXG4gICAgbGF5b3V0UG9zaXRpb25zOiBmdW5jdGlvbiBsYXlvdXRQb3NpdGlvbnMobGF5b3V0LCBvcHRpb25zLCBmbikge1xuICAgICAgdmFyIG5vZGVzID0gdGhpcy5ub2RlcygpLmZpbHRlcihmdW5jdGlvbiAobikge1xuICAgICAgICByZXR1cm4gIW4uaXNQYXJlbnQoKTtcbiAgICAgIH0pO1xuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuICAgICAgdmFyIGxheW91dEVsZXMgPSBvcHRpb25zLmVsZXM7IC8vIG5vZGVzICYgZWRnZXNcblxuICAgICAgdmFyIGdldE1lbW9pemVLZXkgPSBmdW5jdGlvbiBnZXRNZW1vaXplS2V5KG5vZGUpIHtcbiAgICAgICAgcmV0dXJuIG5vZGUuaWQoKTtcbiAgICAgIH07XG5cbiAgICAgIHZhciBmbk1lbSA9IG1lbW9pemUkMShmbiwgZ2V0TWVtb2l6ZUtleSk7IC8vIG1lbW9pemVkIHZlcnNpb24gb2YgcG9zaXRpb24gZnVuY3Rpb25cblxuICAgICAgbGF5b3V0LmVtaXQoe1xuICAgICAgICB0eXBlOiAnbGF5b3V0c3RhcnQnLFxuICAgICAgICBsYXlvdXQ6IGxheW91dFxuICAgICAgfSk7XG4gICAgICBsYXlvdXQuYW5pbWF0aW9ucyA9IFtdO1xuXG4gICAgICB2YXIgY2FsY3VsYXRlU3BhY2luZyA9IGZ1bmN0aW9uIGNhbGN1bGF0ZVNwYWNpbmcoc3BhY2luZywgbm9kZXNCYiwgcG9zKSB7XG4gICAgICAgIHZhciBjZW50ZXIgPSB7XG4gICAgICAgICAgeDogbm9kZXNCYi54MSArIG5vZGVzQmIudyAvIDIsXG4gICAgICAgICAgeTogbm9kZXNCYi55MSArIG5vZGVzQmIuaCAvIDJcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIHNwYWNpbmdWZWN0b3IgPSB7XG4gICAgICAgICAgLy8gc2NhbGUgZnJvbSBjZW50ZXIgb2YgYm91bmRpbmcgYm94IChub3QgbmVjZXNzYXJpbHkgMCwwKVxuICAgICAgICAgIHg6IChwb3MueCAtIGNlbnRlci54KSAqIHNwYWNpbmcsXG4gICAgICAgICAgeTogKHBvcy55IC0gY2VudGVyLnkpICogc3BhY2luZ1xuICAgICAgICB9O1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHg6IGNlbnRlci54ICsgc3BhY2luZ1ZlY3Rvci54LFxuICAgICAgICAgIHk6IGNlbnRlci55ICsgc3BhY2luZ1ZlY3Rvci55XG4gICAgICAgIH07XG4gICAgICB9O1xuXG4gICAgICB2YXIgdXNlU3BhY2luZ0ZhY3RvciA9IG9wdGlvbnMuc3BhY2luZ0ZhY3RvciAmJiBvcHRpb25zLnNwYWNpbmdGYWN0b3IgIT09IDE7XG5cbiAgICAgIHZhciBzcGFjaW5nQmIgPSBmdW5jdGlvbiBzcGFjaW5nQmIoKSB7XG4gICAgICAgIGlmICghdXNlU3BhY2luZ0ZhY3Rvcikge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJiID0gbWFrZUJvdW5kaW5nQm94KCk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBub2RlID0gbm9kZXNbaV07XG4gICAgICAgICAgdmFyIHBvcyA9IGZuTWVtKG5vZGUsIGkpO1xuICAgICAgICAgIGV4cGFuZEJvdW5kaW5nQm94QnlQb2ludChiYiwgcG9zLngsIHBvcy55KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBiYjtcbiAgICAgIH07XG5cbiAgICAgIHZhciBiYiA9IHNwYWNpbmdCYigpO1xuICAgICAgdmFyIGdldEZpbmFsUG9zID0gbWVtb2l6ZSQxKGZ1bmN0aW9uIChub2RlLCBpKSB7XG4gICAgICAgIHZhciBuZXdQb3MgPSBmbk1lbShub2RlLCBpKTtcblxuICAgICAgICBpZiAodXNlU3BhY2luZ0ZhY3Rvcikge1xuICAgICAgICAgIHZhciBzcGFjaW5nID0gTWF0aC5hYnMob3B0aW9ucy5zcGFjaW5nRmFjdG9yKTtcbiAgICAgICAgICBuZXdQb3MgPSBjYWxjdWxhdGVTcGFjaW5nKHNwYWNpbmcsIGJiLCBuZXdQb3MpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG9wdGlvbnMudHJhbnNmb3JtICE9IG51bGwpIHtcbiAgICAgICAgICBuZXdQb3MgPSBvcHRpb25zLnRyYW5zZm9ybShub2RlLCBuZXdQb3MpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ld1BvcztcbiAgICAgIH0sIGdldE1lbW9pemVLZXkpO1xuXG4gICAgICBpZiAob3B0aW9ucy5hbmltYXRlKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgbm9kZSA9IG5vZGVzW2ldO1xuICAgICAgICAgIHZhciBuZXdQb3MgPSBnZXRGaW5hbFBvcyhub2RlLCBpKTtcbiAgICAgICAgICB2YXIgYW5pbWF0ZU5vZGUgPSBvcHRpb25zLmFuaW1hdGVGaWx0ZXIgPT0gbnVsbCB8fCBvcHRpb25zLmFuaW1hdGVGaWx0ZXIobm9kZSwgaSk7XG5cbiAgICAgICAgICBpZiAoYW5pbWF0ZU5vZGUpIHtcbiAgICAgICAgICAgIHZhciBhbmkgPSBub2RlLmFuaW1hdGlvbih7XG4gICAgICAgICAgICAgIHBvc2l0aW9uOiBuZXdQb3MsXG4gICAgICAgICAgICAgIGR1cmF0aW9uOiBvcHRpb25zLmFuaW1hdGlvbkR1cmF0aW9uLFxuICAgICAgICAgICAgICBlYXNpbmc6IG9wdGlvbnMuYW5pbWF0aW9uRWFzaW5nXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGxheW91dC5hbmltYXRpb25zLnB1c2goYW5pKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbm9kZS5wb3NpdGlvbihuZXdQb3MpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChvcHRpb25zLmZpdCkge1xuICAgICAgICAgIHZhciBmaXRBbmkgPSBjeS5hbmltYXRpb24oe1xuICAgICAgICAgICAgZml0OiB7XG4gICAgICAgICAgICAgIGJvdW5kaW5nQm94OiBsYXlvdXRFbGVzLmJvdW5kaW5nQm94QXQoZ2V0RmluYWxQb3MpLFxuICAgICAgICAgICAgICBwYWRkaW5nOiBvcHRpb25zLnBhZGRpbmdcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkdXJhdGlvbjogb3B0aW9ucy5hbmltYXRpb25EdXJhdGlvbixcbiAgICAgICAgICAgIGVhc2luZzogb3B0aW9ucy5hbmltYXRpb25FYXNpbmdcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBsYXlvdXQuYW5pbWF0aW9ucy5wdXNoKGZpdEFuaSk7XG4gICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy56b29tICE9PSB1bmRlZmluZWQgJiYgb3B0aW9ucy5wYW4gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHZhciB6b29tUGFuQW5pID0gY3kuYW5pbWF0aW9uKHtcbiAgICAgICAgICAgIHpvb206IG9wdGlvbnMuem9vbSxcbiAgICAgICAgICAgIHBhbjogb3B0aW9ucy5wYW4sXG4gICAgICAgICAgICBkdXJhdGlvbjogb3B0aW9ucy5hbmltYXRpb25EdXJhdGlvbixcbiAgICAgICAgICAgIGVhc2luZzogb3B0aW9ucy5hbmltYXRpb25FYXNpbmdcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBsYXlvdXQuYW5pbWF0aW9ucy5wdXNoKHpvb21QYW5BbmkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGF5b3V0LmFuaW1hdGlvbnMuZm9yRWFjaChmdW5jdGlvbiAoYW5pKSB7XG4gICAgICAgICAgcmV0dXJuIGFuaS5wbGF5KCk7XG4gICAgICAgIH0pO1xuICAgICAgICBsYXlvdXQub25lKCdsYXlvdXRyZWFkeScsIG9wdGlvbnMucmVhZHkpO1xuICAgICAgICBsYXlvdXQuZW1pdCh7XG4gICAgICAgICAgdHlwZTogJ2xheW91dHJlYWR5JyxcbiAgICAgICAgICBsYXlvdXQ6IGxheW91dFxuICAgICAgICB9KTtcbiAgICAgICAgUHJvbWlzZSQxLmFsbChsYXlvdXQuYW5pbWF0aW9ucy5tYXAoZnVuY3Rpb24gKGFuaSkge1xuICAgICAgICAgIHJldHVybiBhbmkucHJvbWlzZSgpO1xuICAgICAgICB9KSkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgbGF5b3V0Lm9uZSgnbGF5b3V0c3RvcCcsIG9wdGlvbnMuc3RvcCk7XG4gICAgICAgICAgbGF5b3V0LmVtaXQoe1xuICAgICAgICAgICAgdHlwZTogJ2xheW91dHN0b3AnLFxuICAgICAgICAgICAgbGF5b3V0OiBsYXlvdXRcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBub2Rlcy5wb3NpdGlvbnMoZ2V0RmluYWxQb3MpO1xuXG4gICAgICAgIGlmIChvcHRpb25zLmZpdCkge1xuICAgICAgICAgIGN5LmZpdChvcHRpb25zLmVsZXMsIG9wdGlvbnMucGFkZGluZyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob3B0aW9ucy56b29tICE9IG51bGwpIHtcbiAgICAgICAgICBjeS56b29tKG9wdGlvbnMuem9vbSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob3B0aW9ucy5wYW4pIHtcbiAgICAgICAgICBjeS5wYW4ob3B0aW9ucy5wYW4pO1xuICAgICAgICB9XG5cbiAgICAgICAgbGF5b3V0Lm9uZSgnbGF5b3V0cmVhZHknLCBvcHRpb25zLnJlYWR5KTtcbiAgICAgICAgbGF5b3V0LmVtaXQoe1xuICAgICAgICAgIHR5cGU6ICdsYXlvdXRyZWFkeScsXG4gICAgICAgICAgbGF5b3V0OiBsYXlvdXRcbiAgICAgICAgfSk7XG4gICAgICAgIGxheW91dC5vbmUoJ2xheW91dHN0b3AnLCBvcHRpb25zLnN0b3ApO1xuICAgICAgICBsYXlvdXQuZW1pdCh7XG4gICAgICAgICAgdHlwZTogJ2xheW91dHN0b3AnLFxuICAgICAgICAgIGxheW91dDogbGF5b3V0XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgICB9LFxuICAgIGxheW91dDogZnVuY3Rpb24gbGF5b3V0KG9wdGlvbnMpIHtcbiAgICAgIHZhciBjeSA9IHRoaXMuY3koKTtcbiAgICAgIHJldHVybiBjeS5tYWtlTGF5b3V0KGV4dGVuZCh7fSwgb3B0aW9ucywge1xuICAgICAgICBlbGVzOiB0aGlzXG4gICAgICB9KSk7XG4gICAgfVxuICB9OyAvLyBhbGlhc2VzOlxuXG4gIGVsZXNmbiQ1LmNyZWF0ZUxheW91dCA9IGVsZXNmbiQ1Lm1ha2VMYXlvdXQgPSBlbGVzZm4kNS5sYXlvdXQ7XG5cbiAgZnVuY3Rpb24gc3R5bGVDYWNoZShrZXksIGZuLCBlbGUpIHtcbiAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG4gICAgdmFyIGNhY2hlID0gX3Auc3R5bGVDYWNoZSA9IF9wLnN0eWxlQ2FjaGUgfHwgW107XG4gICAgdmFyIHZhbDtcblxuICAgIGlmICgodmFsID0gY2FjaGVba2V5XSkgIT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHZhbDtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFsID0gY2FjaGVba2V5XSA9IGZuKGVsZSk7XG4gICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGNhY2hlU3R5bGVGdW5jdGlvbihrZXksIGZuKSB7XG4gICAga2V5ID0gaGFzaFN0cmluZyhrZXkpO1xuICAgIHJldHVybiBmdW5jdGlvbiBjYWNoZWRTdHlsZUZ1bmN0aW9uKGVsZSkge1xuICAgICAgcmV0dXJuIHN0eWxlQ2FjaGUoa2V5LCBmbiwgZWxlKTtcbiAgICB9O1xuICB9XG5cbiAgZnVuY3Rpb24gY2FjaGVQcm90b3R5cGVTdHlsZUZ1bmN0aW9uKGtleSwgZm4pIHtcbiAgICBrZXkgPSBoYXNoU3RyaW5nKGtleSk7XG5cbiAgICB2YXIgc2VsZkZuID0gZnVuY3Rpb24gc2VsZkZuKGVsZSkge1xuICAgICAgcmV0dXJuIGZuLmNhbGwoZWxlKTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIGNhY2hlZFByb3RvdHlwZVN0eWxlRnVuY3Rpb24oKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1swXTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICByZXR1cm4gc3R5bGVDYWNoZShrZXksIHNlbGZGbiwgZWxlKTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgdmFyIGVsZXNmbiQ0ID0ge1xuICAgIHJlY2FsY3VsYXRlUmVuZGVyZWRTdHlsZTogZnVuY3Rpb24gcmVjYWxjdWxhdGVSZW5kZXJlZFN0eWxlKHVzZUNhY2hlKSB7XG4gICAgICB2YXIgY3kgPSB0aGlzLmN5KCk7XG4gICAgICB2YXIgcmVuZGVyZXIgPSBjeS5yZW5kZXJlcigpO1xuICAgICAgdmFyIHN0eWxlRW5hYmxlZCA9IGN5LnN0eWxlRW5hYmxlZCgpO1xuXG4gICAgICBpZiAocmVuZGVyZXIgJiYgc3R5bGVFbmFibGVkKSB7XG4gICAgICAgIHJlbmRlcmVyLnJlY2FsY3VsYXRlUmVuZGVyZWRTdHlsZSh0aGlzLCB1c2VDYWNoZSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgZGlydHlTdHlsZUNhY2hlOiBmdW5jdGlvbiBkaXJ0eVN0eWxlQ2FjaGUoKSB7XG4gICAgICB2YXIgY3kgPSB0aGlzLmN5KCk7XG5cbiAgICAgIHZhciBkaXJ0eSA9IGZ1bmN0aW9uIGRpcnR5KGVsZSkge1xuICAgICAgICByZXR1cm4gZWxlLl9wcml2YXRlLnN0eWxlQ2FjaGUgPSBudWxsO1xuICAgICAgfTtcblxuICAgICAgaWYgKGN5Lmhhc0NvbXBvdW5kTm9kZXMoKSkge1xuICAgICAgICB2YXIgZWxlcztcbiAgICAgICAgZWxlcyA9IHRoaXMuc3Bhd25TZWxmKCkubWVyZ2UodGhpcy5kZXNjZW5kYW50cygpKS5tZXJnZSh0aGlzLnBhcmVudHMoKSk7XG4gICAgICAgIGVsZXMubWVyZ2UoZWxlcy5jb25uZWN0ZWRFZGdlcygpKTtcbiAgICAgICAgZWxlcy5mb3JFYWNoKGRpcnR5KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuZm9yRWFjaChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgICAgZGlydHkoZWxlKTtcbiAgICAgICAgICBlbGUuY29ubmVjdGVkRWRnZXMoKS5mb3JFYWNoKGRpcnR5KTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgLy8gZnVsbHkgdXBkYXRlcyAocmVjYWxjdWxhdGVzKSB0aGUgc3R5bGUgZm9yIHRoZSBlbGVtZW50c1xuICAgIHVwZGF0ZVN0eWxlOiBmdW5jdGlvbiB1cGRhdGVTdHlsZShub3RpZnlSZW5kZXJlcikge1xuICAgICAgdmFyIGN5ID0gdGhpcy5fcHJpdmF0ZS5jeTtcblxuICAgICAgaWYgKCFjeS5zdHlsZUVuYWJsZWQoKSkge1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cblxuICAgICAgaWYgKGN5LmJhdGNoaW5nKCkpIHtcbiAgICAgICAgdmFyIGJFbGVzID0gY3kuX3ByaXZhdGUuYmF0Y2hTdHlsZUVsZXM7XG4gICAgICAgIGJFbGVzLm1lcmdlKHRoaXMpO1xuICAgICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmcgYW5kIGV4aXQgZWFybHkgd2hlbiBiYXRjaGluZ1xuICAgICAgfVxuXG4gICAgICB2YXIgaGFzQ29tcG91bmRzID0gY3kuaGFzQ29tcG91bmROb2RlcygpO1xuICAgICAgdmFyIHVwZGF0ZWRFbGVzID0gdGhpcztcbiAgICAgIG5vdGlmeVJlbmRlcmVyID0gbm90aWZ5UmVuZGVyZXIgfHwgbm90aWZ5UmVuZGVyZXIgPT09IHVuZGVmaW5lZCA/IHRydWUgOiBmYWxzZTtcblxuICAgICAgaWYgKGhhc0NvbXBvdW5kcykge1xuICAgICAgICAvLyB0aGVuIGFkZCBldmVyeXRoaW5nIHVwIGFuZCBkb3duIGZvciBjb21wb3VuZCBzZWxlY3RvciBjaGVja3NcbiAgICAgICAgdXBkYXRlZEVsZXMgPSB0aGlzLnNwYXduU2VsZigpLm1lcmdlKHRoaXMuZGVzY2VuZGFudHMoKSkubWVyZ2UodGhpcy5wYXJlbnRzKCkpO1xuICAgICAgfSAvLyBsZXQgY2hhbmdlZEVsZXMgPSBzdHlsZS5hcHBseSggdXBkYXRlZEVsZXMgKTtcblxuXG4gICAgICB2YXIgY2hhbmdlZEVsZXMgPSB1cGRhdGVkRWxlcztcblxuICAgICAgaWYgKG5vdGlmeVJlbmRlcmVyKSB7XG4gICAgICAgIGNoYW5nZWRFbGVzLmVtaXRBbmROb3RpZnkoJ3N0eWxlJyk7IC8vIGxldCByZW5kZXJlciBrbm93IHdlIGNoYW5nZWQgc3R5bGVcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNoYW5nZWRFbGVzLmVtaXQoJ3N0eWxlJyk7IC8vIGp1c3QgZmlyZSB0aGUgZXZlbnRcbiAgICAgIH1cblxuICAgICAgdXBkYXRlZEVsZXMuZm9yRWFjaChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgIHJldHVybiBlbGUuX3ByaXZhdGUuc3R5bGVEaXJ0eSA9IHRydWU7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICAgIH0sXG4gICAgLy8gcHJpdmF0ZTogY2xlYXJzIGRpcnR5IGZsYWcgYW5kIHJlY2FsY3VsYXRlcyBzdHlsZVxuICAgIGNsZWFuU3R5bGU6IGZ1bmN0aW9uIGNsZWFuU3R5bGUoKSB7XG4gICAgICB2YXIgY3kgPSB0aGlzLmN5KCk7XG5cbiAgICAgIGlmICghY3kuc3R5bGVFbmFibGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGVsZSA9IHRoaXNbaV07XG5cbiAgICAgICAgaWYgKGVsZS5fcHJpdmF0ZS5zdHlsZURpcnR5KSB7XG4gICAgICAgICAgLy8gbi5iLiB0aGlzIGZsYWcgc2hvdWxkIGJlIHNldCBiZWZvcmUgYXBwbHkoKSB0byBhdm9pZCBwb3RlbnRpYWwgaW5maW5pdGUgcmVjdXJzaW9uXG4gICAgICAgICAgZWxlLl9wcml2YXRlLnN0eWxlRGlydHkgPSBmYWxzZTtcbiAgICAgICAgICBjeS5zdHlsZSgpLmFwcGx5KGVsZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICAgIC8vIGdldCB0aGUgaW50ZXJuYWwgcGFyc2VkIHN0eWxlIG9iamVjdCBmb3IgdGhlIHNwZWNpZmllZCBwcm9wZXJ0eVxuICAgIHBhcnNlZFN0eWxlOiBmdW5jdGlvbiBwYXJzZWRTdHlsZShwcm9wZXJ0eSkge1xuICAgICAgdmFyIGluY2x1ZGVOb25EZWZhdWx0ID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiB0cnVlO1xuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG4gICAgICB2YXIgY3kgPSBlbGUuY3koKTtcblxuICAgICAgaWYgKCFjeS5zdHlsZUVuYWJsZWQoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChlbGUpIHtcbiAgICAgICAgdGhpcy5jbGVhblN0eWxlKCk7XG4gICAgICAgIHZhciBvdmVycmlkZGVuU3R5bGUgPSBlbGUuX3ByaXZhdGUuc3R5bGVbcHJvcGVydHldO1xuXG4gICAgICAgIGlmIChvdmVycmlkZGVuU3R5bGUgIT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybiBvdmVycmlkZGVuU3R5bGU7XG4gICAgICAgIH0gZWxzZSBpZiAoaW5jbHVkZU5vbkRlZmF1bHQpIHtcbiAgICAgICAgICByZXR1cm4gY3kuc3R5bGUoKS5nZXREZWZhdWx0UHJvcGVydHkocHJvcGVydHkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBudW1lcmljU3R5bGU6IGZ1bmN0aW9uIG51bWVyaWNTdHlsZShwcm9wZXJ0eSkge1xuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICAgIGlmICghZWxlLmN5KCkuc3R5bGVFbmFibGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZWxlKSB7XG4gICAgICAgIHZhciBwc3R5bGUgPSBlbGUucHN0eWxlKHByb3BlcnR5KTtcbiAgICAgICAgcmV0dXJuIHBzdHlsZS5wZlZhbHVlICE9PSB1bmRlZmluZWQgPyBwc3R5bGUucGZWYWx1ZSA6IHBzdHlsZS52YWx1ZTtcbiAgICAgIH1cbiAgICB9LFxuICAgIG51bWVyaWNTdHlsZVVuaXRzOiBmdW5jdGlvbiBudW1lcmljU3R5bGVVbml0cyhwcm9wZXJ0eSkge1xuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICAgIGlmICghZWxlLmN5KCkuc3R5bGVFbmFibGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZWxlKSB7XG4gICAgICAgIHJldHVybiBlbGUucHN0eWxlKHByb3BlcnR5KS51bml0cztcbiAgICAgIH1cbiAgICB9LFxuICAgIC8vIGdldCB0aGUgc3BlY2lmaWVkIGNzcyBwcm9wZXJ0eSBhcyBhIHJlbmRlcmVkIHZhbHVlIChpLmUuIG9uLXNjcmVlbiB2YWx1ZSlcbiAgICAvLyBvciBnZXQgdGhlIHdob2xlIHJlbmRlcmVkIHN0eWxlIGlmIG5vIHByb3BlcnR5IHNwZWNpZmllZCAoTkIgZG9lc24ndCBhbGxvdyBzZXR0aW5nKVxuICAgIHJlbmRlcmVkU3R5bGU6IGZ1bmN0aW9uIHJlbmRlcmVkU3R5bGUocHJvcGVydHkpIHtcbiAgICAgIHZhciBjeSA9IHRoaXMuY3koKTtcblxuICAgICAgaWYgKCFjeS5zdHlsZUVuYWJsZWQoKSkge1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cblxuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICAgIGlmIChlbGUpIHtcbiAgICAgICAgcmV0dXJuIGN5LnN0eWxlKCkuZ2V0UmVuZGVyZWRTdHlsZShlbGUsIHByb3BlcnR5KTtcbiAgICAgIH1cbiAgICB9LFxuICAgIC8vIHJlYWQgdGhlIGNhbGN1bGF0ZWQgY3NzIHN0eWxlIG9mIHRoZSBlbGVtZW50IG9yIG92ZXJyaWRlIHRoZSBzdHlsZSAodmlhIGEgYnlwYXNzKVxuICAgIHN0eWxlOiBmdW5jdGlvbiBzdHlsZShuYW1lLCB2YWx1ZSkge1xuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuXG4gICAgICBpZiAoIWN5LnN0eWxlRW5hYmxlZCgpKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuXG4gICAgICB2YXIgdXBkYXRlVHJhbnNpdGlvbnMgPSBmYWxzZTtcbiAgICAgIHZhciBzdHlsZSA9IGN5LnN0eWxlKCk7XG5cbiAgICAgIGlmIChwbGFpbk9iamVjdChuYW1lKSkge1xuICAgICAgICAvLyB0aGVuIGV4dGVuZCB0aGUgYnlwYXNzXG4gICAgICAgIHZhciBwcm9wcyA9IG5hbWU7XG4gICAgICAgIHN0eWxlLmFwcGx5QnlwYXNzKHRoaXMsIHByb3BzLCB1cGRhdGVUcmFuc2l0aW9ucyk7XG4gICAgICAgIHRoaXMuZW1pdEFuZE5vdGlmeSgnc3R5bGUnKTsgLy8gbGV0IHRoZSByZW5kZXJlciBrbm93IHdlJ3ZlIHVwZGF0ZWQgc3R5bGVcbiAgICAgIH0gZWxzZSBpZiAoc3RyaW5nKG5hbWUpKSB7XG4gICAgICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgLy8gdGhlbiBnZXQgdGhlIHByb3BlcnR5IGZyb20gdGhlIHN0eWxlXG4gICAgICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICAgICAgICBpZiAoZWxlKSB7XG4gICAgICAgICAgICByZXR1cm4gc3R5bGUuZ2V0U3R5bGVQcm9wZXJ0eVZhbHVlKGVsZSwgbmFtZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGVtcHR5IGNvbGxlY3Rpb24gPT4gY2FuJ3QgZ2V0IGFueSB2YWx1ZVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyB0aGVuIHNldCB0aGUgYnlwYXNzIHdpdGggdGhlIHByb3BlcnR5IHZhbHVlXG4gICAgICAgICAgc3R5bGUuYXBwbHlCeXBhc3ModGhpcywgbmFtZSwgdmFsdWUsIHVwZGF0ZVRyYW5zaXRpb25zKTtcbiAgICAgICAgICB0aGlzLmVtaXRBbmROb3RpZnkoJ3N0eWxlJyk7IC8vIGxldCB0aGUgcmVuZGVyZXIga25vdyB3ZSd2ZSB1cGRhdGVkIHN0eWxlXG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAobmFtZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHZhciBfZWxlID0gdGhpc1swXTtcblxuICAgICAgICBpZiAoX2VsZSkge1xuICAgICAgICAgIHJldHVybiBzdHlsZS5nZXRSYXdTdHlsZShfZWxlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBlbXB0eSBjb2xsZWN0aW9uID0+IGNhbid0IGdldCBhbnkgdmFsdWVcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICByZW1vdmVTdHlsZTogZnVuY3Rpb24gcmVtb3ZlU3R5bGUobmFtZXMpIHtcbiAgICAgIHZhciBjeSA9IHRoaXMuY3koKTtcblxuICAgICAgaWYgKCFjeS5zdHlsZUVuYWJsZWQoKSkge1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cblxuICAgICAgdmFyIHVwZGF0ZVRyYW5zaXRpb25zID0gZmFsc2U7XG4gICAgICB2YXIgc3R5bGUgPSBjeS5zdHlsZSgpO1xuICAgICAgdmFyIGVsZXMgPSB0aGlzO1xuXG4gICAgICBpZiAobmFtZXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWxlID0gZWxlc1tpXTtcbiAgICAgICAgICBzdHlsZS5yZW1vdmVBbGxCeXBhc3NlcyhlbGUsIHVwZGF0ZVRyYW5zaXRpb25zKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbmFtZXMgPSBuYW1lcy5zcGxpdCgvXFxzKy8pO1xuXG4gICAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBlbGVzLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgIHZhciBfZWxlMiA9IGVsZXNbX2ldO1xuICAgICAgICAgIHN0eWxlLnJlbW92ZUJ5cGFzc2VzKF9lbGUyLCBuYW1lcywgdXBkYXRlVHJhbnNpdGlvbnMpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHRoaXMuZW1pdEFuZE5vdGlmeSgnc3R5bGUnKTsgLy8gbGV0IHRoZSByZW5kZXJlciBrbm93IHdlJ3ZlIHVwZGF0ZWQgc3R5bGVcblxuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICBzaG93OiBmdW5jdGlvbiBzaG93KCkge1xuICAgICAgdGhpcy5jc3MoJ2Rpc3BsYXknLCAnZWxlbWVudCcpO1xuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICBoaWRlOiBmdW5jdGlvbiBoaWRlKCkge1xuICAgICAgdGhpcy5jc3MoJ2Rpc3BsYXknLCAnbm9uZScpO1xuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICBlZmZlY3RpdmVPcGFjaXR5OiBmdW5jdGlvbiBlZmZlY3RpdmVPcGFjaXR5KCkge1xuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuXG4gICAgICBpZiAoIWN5LnN0eWxlRW5hYmxlZCgpKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfVxuXG4gICAgICB2YXIgaGFzQ29tcG91bmROb2RlcyA9IGN5Lmhhc0NvbXBvdW5kTm9kZXMoKTtcbiAgICAgIHZhciBlbGUgPSB0aGlzWzBdO1xuXG4gICAgICBpZiAoZWxlKSB7XG4gICAgICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICAgICAgdmFyIHBhcmVudE9wYWNpdHkgPSBlbGUucHN0eWxlKCdvcGFjaXR5JykudmFsdWU7XG5cbiAgICAgICAgaWYgKCFoYXNDb21wb3VuZE5vZGVzKSB7XG4gICAgICAgICAgcmV0dXJuIHBhcmVudE9wYWNpdHk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcGFyZW50cyA9ICFfcC5kYXRhLnBhcmVudCA/IG51bGwgOiBlbGUucGFyZW50cygpO1xuXG4gICAgICAgIGlmIChwYXJlbnRzKSB7XG4gICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwYXJlbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgcGFyZW50ID0gcGFyZW50c1tpXTtcbiAgICAgICAgICAgIHZhciBvcGFjaXR5ID0gcGFyZW50LnBzdHlsZSgnb3BhY2l0eScpLnZhbHVlO1xuICAgICAgICAgICAgcGFyZW50T3BhY2l0eSA9IG9wYWNpdHkgKiBwYXJlbnRPcGFjaXR5O1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBwYXJlbnRPcGFjaXR5O1xuICAgICAgfVxuICAgIH0sXG4gICAgdHJhbnNwYXJlbnQ6IGZ1bmN0aW9uIHRyYW5zcGFyZW50KCkge1xuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuXG4gICAgICBpZiAoIWN5LnN0eWxlRW5hYmxlZCgpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG4gICAgICB2YXIgaGFzQ29tcG91bmROb2RlcyA9IGVsZS5jeSgpLmhhc0NvbXBvdW5kTm9kZXMoKTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICBpZiAoIWhhc0NvbXBvdW5kTm9kZXMpIHtcbiAgICAgICAgICByZXR1cm4gZWxlLnBzdHlsZSgnb3BhY2l0eScpLnZhbHVlID09PSAwO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBlbGUuZWZmZWN0aXZlT3BhY2l0eSgpID09PSAwO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBiYWNrZ3JvdW5kaW5nOiBmdW5jdGlvbiBiYWNrZ3JvdW5kaW5nKCkge1xuICAgICAgdmFyIGN5ID0gdGhpcy5jeSgpO1xuXG4gICAgICBpZiAoIWN5LnN0eWxlRW5hYmxlZCgpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG4gICAgICByZXR1cm4gZWxlLl9wcml2YXRlLmJhY2tncm91bmRpbmcgPyB0cnVlIDogZmFsc2U7XG4gICAgfVxuICB9O1xuXG4gIGZ1bmN0aW9uIGNoZWNrQ29tcG91bmQoZWxlLCBwYXJlbnRPaykge1xuICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICB2YXIgcGFyZW50cyA9IF9wLmRhdGEucGFyZW50ID8gZWxlLnBhcmVudHMoKSA6IG51bGw7XG5cbiAgICBpZiAocGFyZW50cykge1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwYXJlbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBwYXJlbnQgPSBwYXJlbnRzW2ldO1xuXG4gICAgICAgIGlmICghcGFyZW50T2socGFyZW50KSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgZnVuY3Rpb24gZGVmaW5lRGVyaXZlZFN0YXRlRnVuY3Rpb24oc3BlY3MpIHtcbiAgICB2YXIgb2sgPSBzcGVjcy5vaztcbiAgICB2YXIgZWRnZU9rVmlhTm9kZSA9IHNwZWNzLmVkZ2VPa1ZpYU5vZGUgfHwgc3BlY3Mub2s7XG4gICAgdmFyIHBhcmVudE9rID0gc3BlY3MucGFyZW50T2sgfHwgc3BlY3Mub2s7XG4gICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciBjeSA9IHRoaXMuY3koKTtcblxuICAgICAgaWYgKCFjeS5zdHlsZUVuYWJsZWQoKSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgdmFyIGVsZSA9IHRoaXNbMF07XG4gICAgICB2YXIgaGFzQ29tcG91bmROb2RlcyA9IGN5Lmhhc0NvbXBvdW5kTm9kZXMoKTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG5cbiAgICAgICAgaWYgKCFvayhlbGUpKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGVsZS5pc05vZGUoKSkge1xuICAgICAgICAgIHJldHVybiAhaGFzQ29tcG91bmROb2RlcyB8fCBjaGVja0NvbXBvdW5kKGVsZSwgcGFyZW50T2spO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhciBzcmMgPSBfcC5zb3VyY2U7XG4gICAgICAgICAgdmFyIHRndCA9IF9wLnRhcmdldDtcbiAgICAgICAgICByZXR1cm4gZWRnZU9rVmlhTm9kZShzcmMpICYmICghaGFzQ29tcG91bmROb2RlcyB8fCBjaGVja0NvbXBvdW5kKHNyYywgZWRnZU9rVmlhTm9kZSkpICYmIChzcmMgPT09IHRndCB8fCBlZGdlT2tWaWFOb2RlKHRndCkgJiYgKCFoYXNDb21wb3VuZE5vZGVzIHx8IGNoZWNrQ29tcG91bmQodGd0LCBlZGdlT2tWaWFOb2RlKSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIHZhciBlbGVUYWtlc1VwU3BhY2UgPSBjYWNoZVN0eWxlRnVuY3Rpb24oJ2VsZVRha2VzVXBTcGFjZScsIGZ1bmN0aW9uIChlbGUpIHtcbiAgICByZXR1cm4gZWxlLnBzdHlsZSgnZGlzcGxheScpLnZhbHVlID09PSAnZWxlbWVudCcgJiYgZWxlLndpZHRoKCkgIT09IDAgJiYgKGVsZS5pc05vZGUoKSA/IGVsZS5oZWlnaHQoKSAhPT0gMCA6IHRydWUpO1xuICB9KTtcbiAgZWxlc2ZuJDQudGFrZXNVcFNwYWNlID0gY2FjaGVQcm90b3R5cGVTdHlsZUZ1bmN0aW9uKCd0YWtlc1VwU3BhY2UnLCBkZWZpbmVEZXJpdmVkU3RhdGVGdW5jdGlvbih7XG4gICAgb2s6IGVsZVRha2VzVXBTcGFjZVxuICB9KSk7XG4gIHZhciBlbGVJbnRlcmFjdGl2ZSA9IGNhY2hlU3R5bGVGdW5jdGlvbignZWxlSW50ZXJhY3RpdmUnLCBmdW5jdGlvbiAoZWxlKSB7XG4gICAgcmV0dXJuIGVsZS5wc3R5bGUoJ2V2ZW50cycpLnZhbHVlID09PSAneWVzJyAmJiBlbGUucHN0eWxlKCd2aXNpYmlsaXR5JykudmFsdWUgPT09ICd2aXNpYmxlJyAmJiBlbGVUYWtlc1VwU3BhY2UoZWxlKTtcbiAgfSk7XG4gIHZhciBwYXJlbnRJbnRlcmFjdGl2ZSA9IGNhY2hlU3R5bGVGdW5jdGlvbigncGFyZW50SW50ZXJhY3RpdmUnLCBmdW5jdGlvbiAocGFyZW50KSB7XG4gICAgcmV0dXJuIHBhcmVudC5wc3R5bGUoJ3Zpc2liaWxpdHknKS52YWx1ZSA9PT0gJ3Zpc2libGUnICYmIGVsZVRha2VzVXBTcGFjZShwYXJlbnQpO1xuICB9KTtcbiAgZWxlc2ZuJDQuaW50ZXJhY3RpdmUgPSBjYWNoZVByb3RvdHlwZVN0eWxlRnVuY3Rpb24oJ2ludGVyYWN0aXZlJywgZGVmaW5lRGVyaXZlZFN0YXRlRnVuY3Rpb24oe1xuICAgIG9rOiBlbGVJbnRlcmFjdGl2ZSxcbiAgICBwYXJlbnRPazogcGFyZW50SW50ZXJhY3RpdmUsXG4gICAgZWRnZU9rVmlhTm9kZTogZWxlVGFrZXNVcFNwYWNlXG4gIH0pKTtcblxuICBlbGVzZm4kNC5ub25pbnRlcmFjdGl2ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZWxlID0gdGhpc1swXTtcblxuICAgIGlmIChlbGUpIHtcbiAgICAgIHJldHVybiAhZWxlLmludGVyYWN0aXZlKCk7XG4gICAgfVxuICB9O1xuXG4gIHZhciBlbGVWaXNpYmxlID0gY2FjaGVTdHlsZUZ1bmN0aW9uKCdlbGVWaXNpYmxlJywgZnVuY3Rpb24gKGVsZSkge1xuICAgIHJldHVybiBlbGUucHN0eWxlKCd2aXNpYmlsaXR5JykudmFsdWUgPT09ICd2aXNpYmxlJyAmJiBlbGUucHN0eWxlKCdvcGFjaXR5JykucGZWYWx1ZSAhPT0gMCAmJiBlbGVUYWtlc1VwU3BhY2UoZWxlKTtcbiAgfSk7XG4gIHZhciBlZGdlVmlzaWJsZVZpYU5vZGUgPSBlbGVUYWtlc1VwU3BhY2U7XG4gIGVsZXNmbiQ0LnZpc2libGUgPSBjYWNoZVByb3RvdHlwZVN0eWxlRnVuY3Rpb24oJ3Zpc2libGUnLCBkZWZpbmVEZXJpdmVkU3RhdGVGdW5jdGlvbih7XG4gICAgb2s6IGVsZVZpc2libGUsXG4gICAgZWRnZU9rVmlhTm9kZTogZWRnZVZpc2libGVWaWFOb2RlXG4gIH0pKTtcblxuICBlbGVzZm4kNC5oaWRkZW4gPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICBpZiAoZWxlKSB7XG4gICAgICByZXR1cm4gIWVsZS52aXNpYmxlKCk7XG4gICAgfVxuICB9O1xuXG4gIGVsZXNmbiQ0LmlzQnVuZGxlZEJlemllciA9IGNhY2hlUHJvdG90eXBlU3R5bGVGdW5jdGlvbignaXNCdW5kbGVkQmV6aWVyJywgZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy5jeSgpLnN0eWxlRW5hYmxlZCgpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuICF0aGlzLnJlbW92ZWQoKSAmJiB0aGlzLnBzdHlsZSgnY3VydmUtc3R5bGUnKS52YWx1ZSA9PT0gJ2JlemllcicgJiYgdGhpcy50YWtlc1VwU3BhY2UoKTtcbiAgfSk7XG4gIGVsZXNmbiQ0LmJ5cGFzcyA9IGVsZXNmbiQ0LmNzcyA9IGVsZXNmbiQ0LnN0eWxlO1xuICBlbGVzZm4kNC5yZW5kZXJlZENzcyA9IGVsZXNmbiQ0LnJlbmRlcmVkU3R5bGU7XG4gIGVsZXNmbiQ0LnJlbW92ZUJ5cGFzcyA9IGVsZXNmbiQ0LnJlbW92ZUNzcyA9IGVsZXNmbiQ0LnJlbW92ZVN0eWxlO1xuICBlbGVzZm4kNC5wc3R5bGUgPSBlbGVzZm4kNC5wYXJzZWRTdHlsZTtcblxuICB2YXIgZWxlc2ZuJDMgPSB7fTtcblxuICBmdW5jdGlvbiBkZWZpbmVTd2l0Y2hGdW5jdGlvbihwYXJhbXMpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICB2YXIgY2hhbmdlZEVsZXMgPSBbXTsgLy8gZS5nLiBjeS5ub2RlcygpLnNlbGVjdCggZGF0YSwgaGFuZGxlciApXG5cbiAgICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICB2YXIgZGF0YSA9IGFyZ3NbMF07XG4gICAgICAgIHZhciBoYW5kbGVyID0gYXJnc1sxXTtcbiAgICAgICAgdGhpcy5vbihwYXJhbXMuZXZlbnQsIGRhdGEsIGhhbmRsZXIpO1xuICAgICAgfSAvLyBlLmcuIGN5Lm5vZGVzKCkuc2VsZWN0KCBoYW5kbGVyIClcbiAgICAgIGVsc2UgaWYgKGFyZ3MubGVuZ3RoID09PSAxICYmIGZuJDYoYXJnc1swXSkpIHtcbiAgICAgICAgdmFyIF9oYW5kbGVyID0gYXJnc1swXTtcbiAgICAgICAgdGhpcy5vbihwYXJhbXMuZXZlbnQsIF9oYW5kbGVyKTtcbiAgICAgIH0gLy8gZS5nLiBjeS5ub2RlcygpLnNlbGVjdCgpXG4gICAgICAvLyBlLmcuIChwcml2YXRlKSBjeS5ub2RlcygpLnNlbGVjdChbJ3RhcHNlbGVjdCddKVxuICAgICAgZWxzZSBpZiAoYXJncy5sZW5ndGggPT09IDAgfHwgYXJncy5sZW5ndGggPT09IDEgJiYgYXJyYXkoYXJnc1swXSkpIHtcbiAgICAgICAgdmFyIGFkZGxFdmVudHMgPSBhcmdzLmxlbmd0aCA9PT0gMSA/IGFyZ3NbMF0gOiBudWxsO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBlbGUgPSB0aGlzW2ldO1xuICAgICAgICAgIHZhciBhYmxlID0gIXBhcmFtcy5hYmxlRmllbGQgfHwgZWxlLl9wcml2YXRlW3BhcmFtcy5hYmxlRmllbGRdO1xuICAgICAgICAgIHZhciBjaGFuZ2VkID0gZWxlLl9wcml2YXRlW3BhcmFtcy5maWVsZF0gIT0gcGFyYW1zLnZhbHVlO1xuXG4gICAgICAgICAgaWYgKHBhcmFtcy5vdmVycmlkZUFibGUpIHtcbiAgICAgICAgICAgIHZhciBvdmVycmlkZUFibGUgPSBwYXJhbXMub3ZlcnJpZGVBYmxlKGVsZSk7XG5cbiAgICAgICAgICAgIGlmIChvdmVycmlkZUFibGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICBhYmxlID0gb3ZlcnJpZGVBYmxlO1xuXG4gICAgICAgICAgICAgIGlmICghb3ZlcnJpZGVBYmxlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICAgIH0gLy8gdG8gc2F2ZSBjeWNsZXMgYXNzdW1lIG5vdCBhYmxlIGZvciBhbGwgb24gb3ZlcnJpZGVcblxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChhYmxlKSB7XG4gICAgICAgICAgICBlbGUuX3ByaXZhdGVbcGFyYW1zLmZpZWxkXSA9IHBhcmFtcy52YWx1ZTtcblxuICAgICAgICAgICAgaWYgKGNoYW5nZWQpIHtcbiAgICAgICAgICAgICAgY2hhbmdlZEVsZXMucHVzaChlbGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBjaGFuZ2VkQ29sbCA9IHRoaXMuc3Bhd24oY2hhbmdlZEVsZXMpO1xuICAgICAgICBjaGFuZ2VkQ29sbC51cGRhdGVTdHlsZSgpOyAvLyBjaGFuZ2Ugb2Ygc3RhdGUgPT4gcG9zc2libGUgY2hhbmdlIG9mIHN0eWxlXG5cbiAgICAgICAgY2hhbmdlZENvbGwuZW1pdChwYXJhbXMuZXZlbnQpO1xuXG4gICAgICAgIGlmIChhZGRsRXZlbnRzKSB7XG4gICAgICAgICAgY2hhbmdlZENvbGwuZW1pdChhZGRsRXZlbnRzKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuICB9XG5cbiAgZnVuY3Rpb24gZGVmaW5lU3dpdGNoU2V0KHBhcmFtcykge1xuICAgIGVsZXNmbiQzW3BhcmFtcy5maWVsZF0gPSBmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1swXTtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICBpZiAocGFyYW1zLm92ZXJyaWRlRmllbGQpIHtcbiAgICAgICAgICB2YXIgdmFsID0gcGFyYW1zLm92ZXJyaWRlRmllbGQoZWxlKTtcblxuICAgICAgICAgIGlmICh2YWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmV0dXJuIHZhbDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlLl9wcml2YXRlW3BhcmFtcy5maWVsZF07XG4gICAgICB9XG4gICAgfTtcblxuICAgIGVsZXNmbiQzW3BhcmFtcy5vbl0gPSBkZWZpbmVTd2l0Y2hGdW5jdGlvbih7XG4gICAgICBldmVudDogcGFyYW1zLm9uLFxuICAgICAgZmllbGQ6IHBhcmFtcy5maWVsZCxcbiAgICAgIGFibGVGaWVsZDogcGFyYW1zLmFibGVGaWVsZCxcbiAgICAgIG92ZXJyaWRlQWJsZTogcGFyYW1zLm92ZXJyaWRlQWJsZSxcbiAgICAgIHZhbHVlOiB0cnVlXG4gICAgfSk7XG4gICAgZWxlc2ZuJDNbcGFyYW1zLm9mZl0gPSBkZWZpbmVTd2l0Y2hGdW5jdGlvbih7XG4gICAgICBldmVudDogcGFyYW1zLm9mZixcbiAgICAgIGZpZWxkOiBwYXJhbXMuZmllbGQsXG4gICAgICBhYmxlRmllbGQ6IHBhcmFtcy5hYmxlRmllbGQsXG4gICAgICBvdmVycmlkZUFibGU6IHBhcmFtcy5vdmVycmlkZUFibGUsXG4gICAgICB2YWx1ZTogZmFsc2VcbiAgICB9KTtcbiAgfVxuXG4gIGRlZmluZVN3aXRjaFNldCh7XG4gICAgZmllbGQ6ICdsb2NrZWQnLFxuICAgIG92ZXJyaWRlRmllbGQ6IGZ1bmN0aW9uIG92ZXJyaWRlRmllbGQoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLmN5KCkuYXV0b2xvY2soKSA/IHRydWUgOiB1bmRlZmluZWQ7XG4gICAgfSxcbiAgICBvbjogJ2xvY2snLFxuICAgIG9mZjogJ3VubG9jaydcbiAgfSk7XG4gIGRlZmluZVN3aXRjaFNldCh7XG4gICAgZmllbGQ6ICdncmFiYmFibGUnLFxuICAgIG92ZXJyaWRlRmllbGQ6IGZ1bmN0aW9uIG92ZXJyaWRlRmllbGQoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLmN5KCkuYXV0b3VuZ3JhYmlmeSgpIHx8IGVsZS5wYW5uYWJsZSgpID8gZmFsc2UgOiB1bmRlZmluZWQ7XG4gICAgfSxcbiAgICBvbjogJ2dyYWJpZnknLFxuICAgIG9mZjogJ3VuZ3JhYmlmeSdcbiAgfSk7XG4gIGRlZmluZVN3aXRjaFNldCh7XG4gICAgZmllbGQ6ICdzZWxlY3RlZCcsXG4gICAgYWJsZUZpZWxkOiAnc2VsZWN0YWJsZScsXG4gICAgb3ZlcnJpZGVBYmxlOiBmdW5jdGlvbiBvdmVycmlkZUFibGUoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLmN5KCkuYXV0b3Vuc2VsZWN0aWZ5KCkgPyBmYWxzZSA6IHVuZGVmaW5lZDtcbiAgICB9LFxuICAgIG9uOiAnc2VsZWN0JyxcbiAgICBvZmY6ICd1bnNlbGVjdCdcbiAgfSk7XG4gIGRlZmluZVN3aXRjaFNldCh7XG4gICAgZmllbGQ6ICdzZWxlY3RhYmxlJyxcbiAgICBvdmVycmlkZUZpZWxkOiBmdW5jdGlvbiBvdmVycmlkZUZpZWxkKGVsZSkge1xuICAgICAgcmV0dXJuIGVsZS5jeSgpLmF1dG91bnNlbGVjdGlmeSgpID8gZmFsc2UgOiB1bmRlZmluZWQ7XG4gICAgfSxcbiAgICBvbjogJ3NlbGVjdGlmeScsXG4gICAgb2ZmOiAndW5zZWxlY3RpZnknXG4gIH0pO1xuICBlbGVzZm4kMy5kZXNlbGVjdCA9IGVsZXNmbiQzLnVuc2VsZWN0O1xuXG4gIGVsZXNmbiQzLmdyYWJiZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICBpZiAoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLl9wcml2YXRlLmdyYWJiZWQ7XG4gICAgfVxuICB9O1xuXG4gIGRlZmluZVN3aXRjaFNldCh7XG4gICAgZmllbGQ6ICdhY3RpdmUnLFxuICAgIG9uOiAnYWN0aXZhdGUnLFxuICAgIG9mZjogJ3VuYWN0aXZhdGUnXG4gIH0pO1xuICBkZWZpbmVTd2l0Y2hTZXQoe1xuICAgIGZpZWxkOiAncGFubmFibGUnLFxuICAgIG9uOiAncGFuaWZ5JyxcbiAgICBvZmY6ICd1bnBhbmlmeSdcbiAgfSk7XG5cbiAgZWxlc2ZuJDMuaW5hY3RpdmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGVsZSA9IHRoaXNbMF07XG5cbiAgICBpZiAoZWxlKSB7XG4gICAgICByZXR1cm4gIWVsZS5fcHJpdmF0ZS5hY3RpdmU7XG4gICAgfVxuICB9O1xuXG4gIHZhciBlbGVzZm4kMiA9IHt9OyAvLyBEQUcgZnVuY3Rpb25zXG4gIC8vLy8vLy8vLy8vLy8vLy9cblxuICB2YXIgZGVmaW5lRGFnRXh0cmVtaXR5ID0gZnVuY3Rpb24gZGVmaW5lRGFnRXh0cmVtaXR5KHBhcmFtcykge1xuICAgIHJldHVybiBmdW5jdGlvbiBkYWdFeHRyZW1pdHlJbXBsKHNlbGVjdG9yKSB7XG4gICAgICB2YXIgZWxlcyA9IHRoaXM7XG4gICAgICB2YXIgcmV0ID0gW107XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWxlID0gZWxlc1tpXTtcblxuICAgICAgICBpZiAoIWVsZS5pc05vZGUoKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRpc3F1YWxpZmllZCA9IGZhbHNlO1xuICAgICAgICB2YXIgZWRnZXMgPSBlbGUuY29ubmVjdGVkRWRnZXMoKTtcblxuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGVkZ2VzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgdmFyIGVkZ2UgPSBlZGdlc1tqXTtcbiAgICAgICAgICB2YXIgc3JjID0gZWRnZS5zb3VyY2UoKTtcbiAgICAgICAgICB2YXIgdGd0ID0gZWRnZS50YXJnZXQoKTtcblxuICAgICAgICAgIGlmIChwYXJhbXMubm9JbmNvbWluZ0VkZ2VzICYmIHRndCA9PT0gZWxlICYmIHNyYyAhPT0gZWxlIHx8IHBhcmFtcy5ub091dGdvaW5nRWRnZXMgJiYgc3JjID09PSBlbGUgJiYgdGd0ICE9PSBlbGUpIHtcbiAgICAgICAgICAgIGRpc3F1YWxpZmllZCA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWRpc3F1YWxpZmllZCkge1xuICAgICAgICAgIHJldC5wdXNoKGVsZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXMuc3Bhd24ocmV0LCB0cnVlKS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgIH07XG4gIH07XG5cbiAgdmFyIGRlZmluZURhZ09uZUhvcCA9IGZ1bmN0aW9uIGRlZmluZURhZ09uZUhvcChwYXJhbXMpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlbGVjdG9yKSB7XG4gICAgICB2YXIgZWxlcyA9IHRoaXM7XG4gICAgICB2YXIgb0VsZXMgPSBbXTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBlbGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBlbGUgPSBlbGVzW2ldO1xuXG4gICAgICAgIGlmICghZWxlLmlzTm9kZSgpKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZWRnZXMgPSBlbGUuY29ubmVjdGVkRWRnZXMoKTtcblxuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGVkZ2VzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgdmFyIGVkZ2UgPSBlZGdlc1tqXTtcbiAgICAgICAgICB2YXIgc3JjID0gZWRnZS5zb3VyY2UoKTtcbiAgICAgICAgICB2YXIgdGd0ID0gZWRnZS50YXJnZXQoKTtcblxuICAgICAgICAgIGlmIChwYXJhbXMub3V0Z29pbmcgJiYgc3JjID09PSBlbGUpIHtcbiAgICAgICAgICAgIG9FbGVzLnB1c2goZWRnZSk7XG4gICAgICAgICAgICBvRWxlcy5wdXNoKHRndCk7XG4gICAgICAgICAgfSBlbHNlIGlmIChwYXJhbXMuaW5jb21pbmcgJiYgdGd0ID09PSBlbGUpIHtcbiAgICAgICAgICAgIG9FbGVzLnB1c2goZWRnZSk7XG4gICAgICAgICAgICBvRWxlcy5wdXNoKHNyYyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzLnNwYXduKG9FbGVzLCB0cnVlKS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgIH07XG4gIH07XG5cbiAgdmFyIGRlZmluZURhZ0FsbEhvcHMgPSBmdW5jdGlvbiBkZWZpbmVEYWdBbGxIb3BzKHBhcmFtcykge1xuICAgIHJldHVybiBmdW5jdGlvbiAoc2VsZWN0b3IpIHtcbiAgICAgIHZhciBlbGVzID0gdGhpcztcbiAgICAgIHZhciBzRWxlcyA9IFtdO1xuICAgICAgdmFyIHNFbGVzSWRzID0ge307XG5cbiAgICAgIGZvciAoOzspIHtcbiAgICAgICAgdmFyIG5leHQgPSBwYXJhbXMub3V0Z29pbmcgPyBlbGVzLm91dGdvZXJzKCkgOiBlbGVzLmluY29tZXJzKCk7XG5cbiAgICAgICAgaWYgKG5leHQubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gLy8gZG9uZSBpZiBub25lIGxlZnRcblxuXG4gICAgICAgIHZhciBuZXdOZXh0ID0gZmFsc2U7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuZXh0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgdmFyIG4gPSBuZXh0W2ldO1xuICAgICAgICAgIHZhciBuaWQgPSBuLmlkKCk7XG5cbiAgICAgICAgICBpZiAoIXNFbGVzSWRzW25pZF0pIHtcbiAgICAgICAgICAgIHNFbGVzSWRzW25pZF0gPSB0cnVlO1xuICAgICAgICAgICAgc0VsZXMucHVzaChuKTtcbiAgICAgICAgICAgIG5ld05leHQgPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghbmV3TmV4dCkge1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9IC8vIGRvbmUgaWYgdG91Y2hlZCBhbGwgb3V0Z29lcnMgYWxyZWFkeVxuXG5cbiAgICAgICAgZWxlcyA9IG5leHQ7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzLnNwYXduKHNFbGVzLCB0cnVlKS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgIH07XG4gIH07XG5cbiAgZWxlc2ZuJDIuY2xlYXJUcmF2ZXJzYWxDYWNoZSA9IGZ1bmN0aW9uICgpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHRoaXNbaV0uX3ByaXZhdGUudHJhdmVyc2FsQ2FjaGUgPSBudWxsO1xuICAgIH1cbiAgfTtcblxuICBleHRlbmQoZWxlc2ZuJDIsIHtcbiAgICAvLyBnZXQgdGhlIHJvb3Qgbm9kZXMgaW4gdGhlIERBR1xuICAgIHJvb3RzOiBkZWZpbmVEYWdFeHRyZW1pdHkoe1xuICAgICAgbm9JbmNvbWluZ0VkZ2VzOiB0cnVlXG4gICAgfSksXG4gICAgLy8gZ2V0IHRoZSBsZWFmIG5vZGVzIGluIHRoZSBEQUdcbiAgICBsZWF2ZXM6IGRlZmluZURhZ0V4dHJlbWl0eSh7XG4gICAgICBub091dGdvaW5nRWRnZXM6IHRydWVcbiAgICB9KSxcbiAgICAvLyBub3JtYWxseSBjYWxsZWQgY2hpbGRyZW4gaW4gZ3JhcGggdGhlb3J5XG4gICAgLy8gdGhlc2Ugbm9kZXMgPWVkZ2VzPT4gb3V0Z29pbmcgbm9kZXNcbiAgICBvdXRnb2VyczogY2FjaGUoZGVmaW5lRGFnT25lSG9wKHtcbiAgICAgIG91dGdvaW5nOiB0cnVlXG4gICAgfSksICdvdXRnb2VycycpLFxuICAgIC8vIGFrYSBEQUcgZGVzY2VuZGFudHNcbiAgICBzdWNjZXNzb3JzOiBkZWZpbmVEYWdBbGxIb3BzKHtcbiAgICAgIG91dGdvaW5nOiB0cnVlXG4gICAgfSksXG4gICAgLy8gbm9ybWFsbHkgY2FsbGVkIHBhcmVudHMgaW4gZ3JhcGggdGhlb3J5XG4gICAgLy8gdGhlc2Ugbm9kZXMgPD1lZGdlcz0gaW5jb21pbmcgbm9kZXNcbiAgICBpbmNvbWVyczogY2FjaGUoZGVmaW5lRGFnT25lSG9wKHtcbiAgICAgIGluY29taW5nOiB0cnVlXG4gICAgfSksICdpbmNvbWVycycpLFxuICAgIC8vIGFrYSBEQUcgYW5jZXN0b3JzXG4gICAgcHJlZGVjZXNzb3JzOiBkZWZpbmVEYWdBbGxIb3BzKHtcbiAgICAgIGluY29taW5nOiB0cnVlXG4gICAgfSlcbiAgfSk7IC8vIE5laWdoYm91cmhvb2QgZnVuY3Rpb25zXG4gIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbiAgZXh0ZW5kKGVsZXNmbiQyLCB7XG4gICAgbmVpZ2hib3Job29kOiBjYWNoZShmdW5jdGlvbiAoc2VsZWN0b3IpIHtcbiAgICAgIHZhciBlbGVtZW50cyA9IFtdO1xuICAgICAgdmFyIG5vZGVzID0gdGhpcy5ub2RlcygpO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIC8vIGZvciBhbGwgbm9kZXNcbiAgICAgICAgdmFyIG5vZGUgPSBub2Rlc1tpXTtcbiAgICAgICAgdmFyIGNvbm5lY3RlZEVkZ2VzID0gbm9kZS5jb25uZWN0ZWRFZGdlcygpOyAvLyBmb3IgZWFjaCBjb25uZWN0ZWQgZWRnZSwgYWRkIHRoZSBlZGdlIGFuZCB0aGUgb3RoZXIgbm9kZVxuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgY29ubmVjdGVkRWRnZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICB2YXIgZWRnZSA9IGNvbm5lY3RlZEVkZ2VzW2pdO1xuICAgICAgICAgIHZhciBzcmMgPSBlZGdlLnNvdXJjZSgpO1xuICAgICAgICAgIHZhciB0Z3QgPSBlZGdlLnRhcmdldCgpO1xuICAgICAgICAgIHZhciBvdGhlck5vZGUgPSBub2RlID09PSBzcmMgPyB0Z3QgOiBzcmM7IC8vIG5lZWQgY2hlY2sgaW4gY2FzZSBvZiBsb29wXG5cbiAgICAgICAgICBpZiAob3RoZXJOb2RlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGVsZW1lbnRzLnB1c2gob3RoZXJOb2RlWzBdKTsgLy8gYWRkIG5vZGUgMSBob3AgYXdheVxuICAgICAgICAgIH0gLy8gYWRkIGNvbm5lY3RlZCBlZGdlXG5cblxuICAgICAgICAgIGVsZW1lbnRzLnB1c2goZWRnZVswXSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXMuc3Bhd24oZWxlbWVudHMsIHRydWUpLmZpbHRlcihzZWxlY3Rvcik7XG4gICAgfSwgJ25laWdoYm9yaG9vZCcpLFxuICAgIGNsb3NlZE5laWdoYm9yaG9vZDogZnVuY3Rpb24gY2xvc2VkTmVpZ2hib3Job29kKHNlbGVjdG9yKSB7XG4gICAgICByZXR1cm4gdGhpcy5uZWlnaGJvcmhvb2QoKS5hZGQodGhpcykuZmlsdGVyKHNlbGVjdG9yKTtcbiAgICB9LFxuICAgIG9wZW5OZWlnaGJvcmhvb2Q6IGZ1bmN0aW9uIG9wZW5OZWlnaGJvcmhvb2Qoc2VsZWN0b3IpIHtcbiAgICAgIHJldHVybiB0aGlzLm5laWdoYm9yaG9vZChzZWxlY3Rvcik7XG4gICAgfVxuICB9KTsgLy8gYWxpYXNlc1xuXG4gIGVsZXNmbiQyLm5laWdoYm91cmhvb2QgPSBlbGVzZm4kMi5uZWlnaGJvcmhvb2Q7XG4gIGVsZXNmbiQyLmNsb3NlZE5laWdoYm91cmhvb2QgPSBlbGVzZm4kMi5jbG9zZWROZWlnaGJvcmhvb2Q7XG4gIGVsZXNmbiQyLm9wZW5OZWlnaGJvdXJob29kID0gZWxlc2ZuJDIub3Blbk5laWdoYm9yaG9vZDsgLy8gRWRnZSBmdW5jdGlvbnNcbiAgLy8vLy8vLy8vLy8vLy8vLy9cblxuICBleHRlbmQoZWxlc2ZuJDIsIHtcbiAgICBzb3VyY2U6IGNhY2hlKGZ1bmN0aW9uIHNvdXJjZUltcGwoc2VsZWN0b3IpIHtcbiAgICAgIHZhciBlbGUgPSB0aGlzWzBdO1xuICAgICAgdmFyIHNyYztcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICBzcmMgPSBlbGUuX3ByaXZhdGUuc291cmNlIHx8IGVsZS5jeSgpLmNvbGxlY3Rpb24oKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHNyYyAmJiBzZWxlY3RvciA/IHNyYy5maWx0ZXIoc2VsZWN0b3IpIDogc3JjO1xuICAgIH0sICdzb3VyY2UnKSxcbiAgICB0YXJnZXQ6IGNhY2hlKGZ1bmN0aW9uIHRhcmdldEltcGwoc2VsZWN0b3IpIHtcbiAgICAgIHZhciBlbGUgPSB0aGlzWzBdO1xuICAgICAgdmFyIHRndDtcblxuICAgICAgaWYgKGVsZSkge1xuICAgICAgICB0Z3QgPSBlbGUuX3ByaXZhdGUudGFyZ2V0IHx8IGVsZS5jeSgpLmNvbGxlY3Rpb24oKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRndCAmJiBzZWxlY3RvciA/IHRndC5maWx0ZXIoc2VsZWN0b3IpIDogdGd0O1xuICAgIH0sICd0YXJnZXQnKSxcbiAgICBzb3VyY2VzOiBkZWZpbmVTb3VyY2VGdW5jdGlvbih7XG4gICAgICBhdHRyOiAnc291cmNlJ1xuICAgIH0pLFxuICAgIHRhcmdldHM6IGRlZmluZVNvdXJjZUZ1bmN0aW9uKHtcbiAgICAgIGF0dHI6ICd0YXJnZXQnXG4gICAgfSlcbiAgfSk7XG5cbiAgZnVuY3Rpb24gZGVmaW5lU291cmNlRnVuY3Rpb24ocGFyYW1zKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIHNvdXJjZUltcGwoc2VsZWN0b3IpIHtcbiAgICAgIHZhciBzb3VyY2VzID0gW107XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWxlID0gdGhpc1tpXTtcbiAgICAgICAgdmFyIHNyYyA9IGVsZS5fcHJpdmF0ZVtwYXJhbXMuYXR0cl07XG5cbiAgICAgICAgaWYgKHNyYykge1xuICAgICAgICAgIHNvdXJjZXMucHVzaChzcmMpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzLnNwYXduKHNvdXJjZXMsIHRydWUpLmZpbHRlcihzZWxlY3Rvcik7XG4gICAgfTtcbiAgfVxuXG4gIGV4dGVuZChlbGVzZm4kMiwge1xuICAgIGVkZ2VzV2l0aDogY2FjaGUoZGVmaW5lRWRnZXNXaXRoRnVuY3Rpb24oKSwgJ2VkZ2VzV2l0aCcpLFxuICAgIGVkZ2VzVG86IGNhY2hlKGRlZmluZUVkZ2VzV2l0aEZ1bmN0aW9uKHtcbiAgICAgIHRoaXNJc1NyYzogdHJ1ZVxuICAgIH0pLCAnZWRnZXNUbycpXG4gIH0pO1xuXG4gIGZ1bmN0aW9uIGRlZmluZUVkZ2VzV2l0aEZ1bmN0aW9uKHBhcmFtcykge1xuICAgIHJldHVybiBmdW5jdGlvbiBlZGdlc1dpdGhJbXBsKG90aGVyTm9kZXMpIHtcbiAgICAgIHZhciBlbGVtZW50cyA9IFtdO1xuICAgICAgdmFyIGN5ID0gdGhpcy5fcHJpdmF0ZS5jeTtcbiAgICAgIHZhciBwID0gcGFyYW1zIHx8IHt9OyAvLyBnZXQgZWxlbWVudHMgaWYgYSBzZWxlY3RvciBpcyBzcGVjaWZpZWRcblxuICAgICAgaWYgKHN0cmluZyhvdGhlck5vZGVzKSkge1xuICAgICAgICBvdGhlck5vZGVzID0gY3kuJChvdGhlck5vZGVzKTtcbiAgICAgIH1cblxuICAgICAgZm9yICh2YXIgaCA9IDA7IGggPCBvdGhlck5vZGVzLmxlbmd0aDsgaCsrKSB7XG4gICAgICAgIHZhciBlZGdlcyA9IG90aGVyTm9kZXNbaF0uX3ByaXZhdGUuZWRnZXM7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBlZGdlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBlZGdlID0gZWRnZXNbaV07XG4gICAgICAgICAgdmFyIGVkZ2VEYXRhID0gZWRnZS5fcHJpdmF0ZS5kYXRhO1xuICAgICAgICAgIHZhciB0aGlzVG9PdGhlciA9IHRoaXMuaGFzRWxlbWVudFdpdGhJZChlZGdlRGF0YS5zb3VyY2UpICYmIG90aGVyTm9kZXMuaGFzRWxlbWVudFdpdGhJZChlZGdlRGF0YS50YXJnZXQpO1xuICAgICAgICAgIHZhciBvdGhlclRvVGhpcyA9IG90aGVyTm9kZXMuaGFzRWxlbWVudFdpdGhJZChlZGdlRGF0YS5zb3VyY2UpICYmIHRoaXMuaGFzRWxlbWVudFdpdGhJZChlZGdlRGF0YS50YXJnZXQpO1xuICAgICAgICAgIHZhciBlZGdlQ29ubmVjdHNUaGlzQW5kT3RoZXIgPSB0aGlzVG9PdGhlciB8fCBvdGhlclRvVGhpcztcblxuICAgICAgICAgIGlmICghZWRnZUNvbm5lY3RzVGhpc0FuZE90aGVyKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAocC50aGlzSXNTcmMgfHwgcC50aGlzSXNUZ3QpIHtcbiAgICAgICAgICAgIGlmIChwLnRoaXNJc1NyYyAmJiAhdGhpc1RvT3RoZXIpIHtcbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChwLnRoaXNJc1RndCAmJiAhb3RoZXJUb1RoaXMpIHtcbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZWxlbWVudHMucHVzaChlZGdlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcy5zcGF3bihlbGVtZW50cywgdHJ1ZSk7XG4gICAgfTtcbiAgfVxuXG4gIGV4dGVuZChlbGVzZm4kMiwge1xuICAgIGNvbm5lY3RlZEVkZ2VzOiBjYWNoZShmdW5jdGlvbiAoc2VsZWN0b3IpIHtcbiAgICAgIHZhciByZXRFbGVzID0gW107XG4gICAgICB2YXIgZWxlcyA9IHRoaXM7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgbm9kZSA9IGVsZXNbaV07XG5cbiAgICAgICAgaWYgKCFub2RlLmlzTm9kZSgpKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZWRnZXMgPSBub2RlLl9wcml2YXRlLmVkZ2VzO1xuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgZWRnZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICB2YXIgZWRnZSA9IGVkZ2VzW2pdO1xuICAgICAgICAgIHJldEVsZXMucHVzaChlZGdlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcy5zcGF3bihyZXRFbGVzLCB0cnVlKS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgIH0sICdjb25uZWN0ZWRFZGdlcycpLFxuICAgIGNvbm5lY3RlZE5vZGVzOiBjYWNoZShmdW5jdGlvbiAoc2VsZWN0b3IpIHtcbiAgICAgIHZhciByZXRFbGVzID0gW107XG4gICAgICB2YXIgZWxlcyA9IHRoaXM7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWRnZSA9IGVsZXNbaV07XG5cbiAgICAgICAgaWYgKCFlZGdlLmlzRWRnZSgpKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICByZXRFbGVzLnB1c2goZWRnZS5zb3VyY2UoKVswXSk7XG4gICAgICAgIHJldEVsZXMucHVzaChlZGdlLnRhcmdldCgpWzBdKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXMuc3Bhd24ocmV0RWxlcywgdHJ1ZSkuZmlsdGVyKHNlbGVjdG9yKTtcbiAgICB9LCAnY29ubmVjdGVkTm9kZXMnKSxcbiAgICBwYXJhbGxlbEVkZ2VzOiBjYWNoZShkZWZpbmVQYXJhbGxlbEVkZ2VzRnVuY3Rpb24oKSwgJ3BhcmFsbGVsRWRnZXMnKSxcbiAgICBjb2RpcmVjdGVkRWRnZXM6IGNhY2hlKGRlZmluZVBhcmFsbGVsRWRnZXNGdW5jdGlvbih7XG4gICAgICBjb2RpcmVjdGVkOiB0cnVlXG4gICAgfSksICdjb2RpcmVjdGVkRWRnZXMnKVxuICB9KTtcblxuICBmdW5jdGlvbiBkZWZpbmVQYXJhbGxlbEVkZ2VzRnVuY3Rpb24ocGFyYW1zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgY29kaXJlY3RlZDogZmFsc2VcbiAgICB9O1xuICAgIHBhcmFtcyA9IGV4dGVuZCh7fSwgZGVmYXVsdHMsIHBhcmFtcyk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIHBhcmFsbGVsRWRnZXNJbXBsKHNlbGVjdG9yKSB7XG4gICAgICAvLyBtaWNyby1vcHRpbWlzZWQgZm9yIHJlbmRlcmVyXG4gICAgICB2YXIgZWxlbWVudHMgPSBbXTtcbiAgICAgIHZhciBlZGdlcyA9IHRoaXMuZWRnZXMoKTtcbiAgICAgIHZhciBwID0gcGFyYW1zOyAvLyBsb29rIGF0IGFsbCB0aGUgZWRnZXMgaW4gdGhlIGNvbGxlY3Rpb25cblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBlZGdlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZWRnZTEgPSBlZGdlc1tpXTtcbiAgICAgICAgdmFyIGVkZ2UxX3AgPSBlZGdlMS5fcHJpdmF0ZTtcbiAgICAgICAgdmFyIHNyYzEgPSBlZGdlMV9wLnNvdXJjZTtcbiAgICAgICAgdmFyIHNyY2lkMSA9IHNyYzEuX3ByaXZhdGUuZGF0YS5pZDtcbiAgICAgICAgdmFyIHRndGlkMSA9IGVkZ2UxX3AuZGF0YS50YXJnZXQ7XG4gICAgICAgIHZhciBzcmNFZGdlczEgPSBzcmMxLl9wcml2YXRlLmVkZ2VzOyAvLyBsb29rIGF0IGVkZ2VzIGNvbm5lY3RlZCB0byB0aGUgc3JjIG5vZGUgb2YgdGhpcyBlZGdlXG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBzcmNFZGdlczEubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICB2YXIgZWRnZTIgPSBzcmNFZGdlczFbal07XG4gICAgICAgICAgdmFyIGVkZ2UyZGF0YSA9IGVkZ2UyLl9wcml2YXRlLmRhdGE7XG4gICAgICAgICAgdmFyIHRndGlkMiA9IGVkZ2UyZGF0YS50YXJnZXQ7XG4gICAgICAgICAgdmFyIHNyY2lkMiA9IGVkZ2UyZGF0YS5zb3VyY2U7XG4gICAgICAgICAgdmFyIGNvZGlyZWN0ZWQgPSB0Z3RpZDIgPT09IHRndGlkMSAmJiBzcmNpZDIgPT09IHNyY2lkMTtcbiAgICAgICAgICB2YXIgb3BwZGlyZWN0ZWQgPSBzcmNpZDEgPT09IHRndGlkMiAmJiB0Z3RpZDEgPT09IHNyY2lkMjtcblxuICAgICAgICAgIGlmIChwLmNvZGlyZWN0ZWQgJiYgY29kaXJlY3RlZCB8fCAhcC5jb2RpcmVjdGVkICYmIChjb2RpcmVjdGVkIHx8IG9wcGRpcmVjdGVkKSkge1xuICAgICAgICAgICAgZWxlbWVudHMucHVzaChlZGdlMik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzLnNwYXduKGVsZW1lbnRzLCB0cnVlKS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgIH07XG4gIH0gLy8gTWlzYyBmdW5jdGlvbnNcbiAgLy8vLy8vLy8vLy8vLy8vLy9cblxuXG4gIGV4dGVuZChlbGVzZm4kMiwge1xuICAgIGNvbXBvbmVudHM6IGZ1bmN0aW9uIGNvbXBvbmVudHMocm9vdCkge1xuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgdmFyIGN5ID0gc2VsZi5jeSgpO1xuICAgICAgdmFyIHZpc2l0ZWQgPSBjeS5jb2xsZWN0aW9uKCk7XG4gICAgICB2YXIgdW52aXNpdGVkID0gcm9vdCA9PSBudWxsID8gc2VsZi5ub2RlcygpIDogcm9vdC5ub2RlcygpO1xuICAgICAgdmFyIGNvbXBvbmVudHMgPSBbXTtcblxuICAgICAgaWYgKHJvb3QgIT0gbnVsbCAmJiB1bnZpc2l0ZWQuZW1wdHkoKSkge1xuICAgICAgICAvLyByb290IG1heSBjb250YWluIG9ubHkgZWRnZXNcbiAgICAgICAgdW52aXNpdGVkID0gcm9vdC5zb3VyY2VzKCk7IC8vIGRvZXNuJ3QgbWF0dGVyIHdoaWNoIG5vZGUgdG8gdXNlICh1bmRpcmVjdGVkKSwgc28ganVzdCB1c2UgdGhlIHNvdXJjZSBzaWRlc1xuICAgICAgfVxuXG4gICAgICB2YXIgdmlzaXRJbkNvbXBvbmVudCA9IGZ1bmN0aW9uIHZpc2l0SW5Db21wb25lbnQobm9kZSwgY29tcG9uZW50KSB7XG4gICAgICAgIHZpc2l0ZWQubWVyZ2Uobm9kZSk7XG4gICAgICAgIHVudmlzaXRlZC51bm1lcmdlKG5vZGUpO1xuICAgICAgICBjb21wb25lbnQubWVyZ2Uobm9kZSk7XG4gICAgICB9O1xuXG4gICAgICBpZiAodW52aXNpdGVkLmVtcHR5KCkpIHtcbiAgICAgICAgcmV0dXJuIHNlbGYuc3Bhd24oKTtcbiAgICAgIH1cblxuICAgICAgdmFyIF9sb29wID0gZnVuY3Rpb24gX2xvb3AoKSB7XG4gICAgICAgIC8vIGVhY2ggaXRlcmF0aW9uIHlpZWxkcyBhIGNvbXBvbmVudFxuICAgICAgICB2YXIgY21wdCA9IGN5LmNvbGxlY3Rpb24oKTtcbiAgICAgICAgY29tcG9uZW50cy5wdXNoKGNtcHQpO1xuICAgICAgICB2YXIgcm9vdCA9IHVudmlzaXRlZFswXTtcbiAgICAgICAgdmlzaXRJbkNvbXBvbmVudChyb290LCBjbXB0KTtcbiAgICAgICAgc2VsZi5iZnMoe1xuICAgICAgICAgIGRpcmVjdGVkOiBmYWxzZSxcbiAgICAgICAgICByb290czogcm9vdCxcbiAgICAgICAgICB2aXNpdDogZnVuY3Rpb24gdmlzaXQodikge1xuICAgICAgICAgICAgcmV0dXJuIHZpc2l0SW5Db21wb25lbnQodiwgY21wdCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgY21wdC5mb3JFYWNoKGZ1bmN0aW9uIChub2RlKSB7XG4gICAgICAgICAgbm9kZS5jb25uZWN0ZWRFZGdlcygpLmZvckVhY2goZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIC8vIGNvbm5lY3RlZEVkZ2VzKCkgdXN1YWxseSBjYWNoZWRcbiAgICAgICAgICAgIGlmIChzZWxmLmhhcyhlKSAmJiBjbXB0LmhhcyhlLnNvdXJjZSgpKSAmJiBjbXB0LmhhcyhlLnRhcmdldCgpKSkge1xuICAgICAgICAgICAgICAvLyBoYXMoKSBpcyBjaGVhcFxuICAgICAgICAgICAgICBjbXB0Lm1lcmdlKGUpOyAvLyBmb3JFYWNoKCkgb25seSBjb25zaWRlcnMgbm9kZXMgLS0gc2V0cyBOIGF0IGNhbGwgdGltZVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH07XG5cbiAgICAgIGRvIHtcbiAgICAgICAgX2xvb3AoKTtcbiAgICAgIH0gd2hpbGUgKHVudmlzaXRlZC5sZW5ndGggPiAwKTtcblxuICAgICAgcmV0dXJuIGNvbXBvbmVudHM7XG4gICAgfSxcbiAgICBjb21wb25lbnQ6IGZ1bmN0aW9uIGNvbXBvbmVudCgpIHtcbiAgICAgIHZhciBlbGUgPSB0aGlzWzBdO1xuICAgICAgcmV0dXJuIGVsZS5jeSgpLm11dGFibGVFbGVtZW50cygpLmNvbXBvbmVudHMoZWxlKVswXTtcbiAgICB9XG4gIH0pO1xuICBlbGVzZm4kMi5jb21wb25lbnRzT2YgPSBlbGVzZm4kMi5jb21wb25lbnRzO1xuXG4gIHZhciBDb2xsZWN0aW9uID0gZnVuY3Rpb24gQ29sbGVjdGlvbihjeSwgZWxlbWVudHMpIHtcbiAgICB2YXIgdW5pcXVlID0gYXJndW1lbnRzLmxlbmd0aCA+IDIgJiYgYXJndW1lbnRzWzJdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMl0gOiBmYWxzZTtcbiAgICB2YXIgcmVtb3ZlZCA9IGFyZ3VtZW50cy5sZW5ndGggPiAzICYmIGFyZ3VtZW50c1szXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzNdIDogZmFsc2U7XG5cbiAgICBpZiAoY3kgPT09IHVuZGVmaW5lZCkge1xuICAgICAgZXJyb3IoJ0EgY29sbGVjdGlvbiBtdXN0IGhhdmUgYSByZWZlcmVuY2UgdG8gdGhlIGNvcmUnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgbWFwID0gbmV3IE1hcCQyKCk7XG4gICAgdmFyIGNyZWF0ZWRFbGVtZW50cyA9IGZhbHNlO1xuXG4gICAgaWYgKCFlbGVtZW50cykge1xuICAgICAgZWxlbWVudHMgPSBbXTtcbiAgICB9IGVsc2UgaWYgKGVsZW1lbnRzLmxlbmd0aCA+IDAgJiYgcGxhaW5PYmplY3QoZWxlbWVudHNbMF0pICYmICFlbGVtZW50KGVsZW1lbnRzWzBdKSkge1xuICAgICAgY3JlYXRlZEVsZW1lbnRzID0gdHJ1ZTsgLy8gbWFrZSBlbGVtZW50cyBmcm9tIGpzb24gYW5kIHJlc3RvcmUgYWxsIGF0IG9uY2UgbGF0ZXJcblxuICAgICAgdmFyIGVsZXMgPSBbXTtcbiAgICAgIHZhciBlbGVzSWRzID0gbmV3IFNldCQxKCk7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gZWxlbWVudHMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgIHZhciBqc29uID0gZWxlbWVudHNbaV07XG5cbiAgICAgICAgaWYgKGpzb24uZGF0YSA9PSBudWxsKSB7XG4gICAgICAgICAganNvbi5kYXRhID0ge307XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgX2RhdGEgPSBqc29uLmRhdGE7IC8vIG1ha2Ugc3VyZSBuZXdseSBjcmVhdGVkIGVsZW1lbnRzIGhhdmUgdmFsaWQgaWRzXG5cbiAgICAgICAgaWYgKF9kYXRhLmlkID09IG51bGwpIHtcbiAgICAgICAgICBfZGF0YS5pZCA9IHV1aWQoKTtcbiAgICAgICAgfSBlbHNlIGlmIChjeS5oYXNFbGVtZW50V2l0aElkKF9kYXRhLmlkKSB8fCBlbGVzSWRzLmhhcyhfZGF0YS5pZCkpIHtcbiAgICAgICAgICBjb250aW51ZTsgLy8gY2FuJ3QgY3JlYXRlIGVsZW1lbnQgaWYgcHJpb3IgaWQgYWxyZWFkeSBleGlzdHNcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBlbGUgPSBuZXcgRWxlbWVudChjeSwganNvbiwgZmFsc2UpO1xuICAgICAgICBlbGVzLnB1c2goZWxlKTtcbiAgICAgICAgZWxlc0lkcy5hZGQoX2RhdGEuaWQpO1xuICAgICAgfVxuXG4gICAgICBlbGVtZW50cyA9IGVsZXM7XG4gICAgfVxuXG4gICAgdGhpcy5sZW5ndGggPSAwO1xuXG4gICAgZm9yICh2YXIgX2kgPSAwLCBfbCA9IGVsZW1lbnRzLmxlbmd0aDsgX2kgPCBfbDsgX2krKykge1xuICAgICAgdmFyIGVsZW1lbnQkMSA9IGVsZW1lbnRzW19pXVswXTsgLy8gWzBdIGluIGNhc2UgZWxlbWVudHMgaXMgYW4gYXJyYXkgb2YgY29sbGVjdGlvbnMsIHJhdGhlciB0aGFuIGFycmF5IG9mIGVsZW1lbnRzXG5cbiAgICAgIGlmIChlbGVtZW50JDEgPT0gbnVsbCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdmFyIGlkID0gZWxlbWVudCQxLl9wcml2YXRlLmRhdGEuaWQ7XG5cbiAgICAgIGlmICghdW5pcXVlIHx8ICFtYXAuaGFzKGlkKSkge1xuICAgICAgICBpZiAodW5pcXVlKSB7XG4gICAgICAgICAgbWFwLnNldChpZCwge1xuICAgICAgICAgICAgaW5kZXg6IHRoaXMubGVuZ3RoLFxuICAgICAgICAgICAgZWxlOiBlbGVtZW50JDFcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXNbdGhpcy5sZW5ndGhdID0gZWxlbWVudCQxO1xuICAgICAgICB0aGlzLmxlbmd0aCsrO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuX3ByaXZhdGUgPSB7XG4gICAgICBlbGVzOiB0aGlzLFxuICAgICAgY3k6IGN5LFxuXG4gICAgICBnZXQgbWFwKCkge1xuICAgICAgICBpZiAodGhpcy5sYXp5TWFwID09IG51bGwpIHtcbiAgICAgICAgICB0aGlzLnJlYnVpbGRNYXAoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLmxhenlNYXA7XG4gICAgICB9LFxuXG4gICAgICBzZXQgbWFwKG0pIHtcbiAgICAgICAgdGhpcy5sYXp5TWFwID0gbTtcbiAgICAgIH0sXG5cbiAgICAgIHJlYnVpbGRNYXA6IGZ1bmN0aW9uIHJlYnVpbGRNYXAoKSB7XG4gICAgICAgIHZhciBtID0gdGhpcy5sYXp5TWFwID0gbmV3IE1hcCQyKCk7XG4gICAgICAgIHZhciBlbGVzID0gdGhpcy5lbGVzO1xuXG4gICAgICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IGVsZXMubGVuZ3RoOyBfaTIrKykge1xuICAgICAgICAgIHZhciBfZWxlID0gZWxlc1tfaTJdO1xuICAgICAgICAgIG0uc2V0KF9lbGUuaWQoKSwge1xuICAgICAgICAgICAgaW5kZXg6IF9pMixcbiAgICAgICAgICAgIGVsZTogX2VsZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIGlmICh1bmlxdWUpIHtcbiAgICAgIHRoaXMuX3ByaXZhdGUubWFwID0gbWFwO1xuICAgIH0gLy8gcmVzdG9yZSB0aGUgZWxlbWVudHMgaWYgd2UgY3JlYXRlZCB0aGVtIGZyb20ganNvblxuXG5cbiAgICBpZiAoY3JlYXRlZEVsZW1lbnRzICYmICFyZW1vdmVkKSB7XG4gICAgICB0aGlzLnJlc3RvcmUoKTtcbiAgICB9XG4gIH07IC8vIEZ1bmN0aW9uc1xuICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4gIC8vIGtlZXAgdGhlIHByb3RvdHlwZXMgaW4gc3luYyAoYW4gZWxlbWVudCBoYXMgdGhlIHNhbWUgZnVuY3Rpb25zIGFzIGEgY29sbGVjdGlvbilcbiAgLy8gYW5kIHVzZSBlbGVmbiBhbmQgZWxlc2ZuIGFzIHNob3J0aGFuZHMgdG8gdGhlIHByb3RvdHlwZXNcblxuXG4gIHZhciBlbGVzZm4kMSA9IEVsZW1lbnQucHJvdG90eXBlID0gQ29sbGVjdGlvbi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFycmF5LnByb3RvdHlwZSk7XG5cbiAgZWxlc2ZuJDEuaW5zdGFuY2VTdHJpbmcgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICdjb2xsZWN0aW9uJztcbiAgfTtcblxuICBlbGVzZm4kMS5zcGF3biA9IGZ1bmN0aW9uIChlbGVzLCB1bmlxdWUpIHtcbiAgICByZXR1cm4gbmV3IENvbGxlY3Rpb24odGhpcy5jeSgpLCBlbGVzLCB1bmlxdWUpO1xuICB9O1xuXG4gIGVsZXNmbiQxLnNwYXduU2VsZiA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zcGF3bih0aGlzKTtcbiAgfTtcblxuICBlbGVzZm4kMS5jeSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5jeTtcbiAgfTtcblxuICBlbGVzZm4kMS5yZW5kZXJlciA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5jeS5yZW5kZXJlcigpO1xuICB9O1xuXG4gIGVsZXNmbiQxLmVsZW1lbnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXNbMF07XG4gIH07XG5cbiAgZWxlc2ZuJDEuY29sbGVjdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoY29sbGVjdGlvbih0aGlzKSkge1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGFuIGVsZW1lbnRcbiAgICAgIHJldHVybiBuZXcgQ29sbGVjdGlvbih0aGlzLl9wcml2YXRlLmN5LCBbdGhpc10pO1xuICAgIH1cbiAgfTtcblxuICBlbGVzZm4kMS51bmlxdWUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIG5ldyBDb2xsZWN0aW9uKHRoaXMuX3ByaXZhdGUuY3ksIHRoaXMsIHRydWUpO1xuICB9O1xuXG4gIGVsZXNmbiQxLmhhc0VsZW1lbnRXaXRoSWQgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICBpZCA9ICcnICsgaWQ7IC8vIGlkIG11c3QgYmUgc3RyaW5nXG5cbiAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5tYXAuaGFzKGlkKTtcbiAgfTtcblxuICBlbGVzZm4kMS5nZXRFbGVtZW50QnlJZCA9IGZ1bmN0aW9uIChpZCkge1xuICAgIGlkID0gJycgKyBpZDsgLy8gaWQgbXVzdCBiZSBzdHJpbmdcblxuICAgIHZhciBjeSA9IHRoaXMuX3ByaXZhdGUuY3k7XG5cbiAgICB2YXIgZW50cnkgPSB0aGlzLl9wcml2YXRlLm1hcC5nZXQoaWQpO1xuXG4gICAgcmV0dXJuIGVudHJ5ID8gZW50cnkuZWxlIDogbmV3IENvbGxlY3Rpb24oY3kpOyAvLyBnZXQgZWxlIG9yIGVtcHR5IGNvbGxlY3Rpb25cbiAgfTtcblxuICBlbGVzZm4kMS4kaWQgPSBlbGVzZm4kMS5nZXRFbGVtZW50QnlJZDtcblxuICBlbGVzZm4kMS5wb29sSW5kZXggPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGN5ID0gdGhpcy5fcHJpdmF0ZS5jeTtcbiAgICB2YXIgZWxlcyA9IGN5Ll9wcml2YXRlLmVsZW1lbnRzO1xuICAgIHZhciBpZCA9IHRoaXNbMF0uX3ByaXZhdGUuZGF0YS5pZDtcbiAgICByZXR1cm4gZWxlcy5fcHJpdmF0ZS5tYXAuZ2V0KGlkKS5pbmRleDtcbiAgfTtcblxuICBlbGVzZm4kMS5pbmRleE9mID0gZnVuY3Rpb24gKGVsZSkge1xuICAgIHZhciBpZCA9IGVsZVswXS5fcHJpdmF0ZS5kYXRhLmlkO1xuICAgIHJldHVybiB0aGlzLl9wcml2YXRlLm1hcC5nZXQoaWQpLmluZGV4O1xuICB9O1xuXG4gIGVsZXNmbiQxLmluZGV4T2ZJZCA9IGZ1bmN0aW9uIChpZCkge1xuICAgIGlkID0gJycgKyBpZDsgLy8gaWQgbXVzdCBiZSBzdHJpbmdcblxuICAgIHJldHVybiB0aGlzLl9wcml2YXRlLm1hcC5nZXQoaWQpLmluZGV4O1xuICB9O1xuXG4gIGVsZXNmbiQxLmpzb24gPSBmdW5jdGlvbiAob2JqKSB7XG4gICAgdmFyIGVsZSA9IHRoaXMuZWxlbWVudCgpO1xuICAgIHZhciBjeSA9IHRoaXMuY3koKTtcblxuICAgIGlmIChlbGUgPT0gbnVsbCAmJiBvYmopIHtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0gLy8gY2FuJ3Qgc2V0IHRvIG5vIGVsZXNcblxuXG4gICAgaWYgKGVsZSA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH0gLy8gY2FuJ3QgZ2V0IGZyb20gbm8gZWxlc1xuXG5cbiAgICB2YXIgcCA9IGVsZS5fcHJpdmF0ZTtcblxuICAgIGlmIChwbGFpbk9iamVjdChvYmopKSB7XG4gICAgICAvLyBzZXRcbiAgICAgIGN5LnN0YXJ0QmF0Y2goKTtcblxuICAgICAgaWYgKG9iai5kYXRhKSB7XG4gICAgICAgIGVsZS5kYXRhKG9iai5kYXRhKTtcbiAgICAgICAgdmFyIF9kYXRhMiA9IHAuZGF0YTtcblxuICAgICAgICBpZiAoZWxlLmlzRWRnZSgpKSB7XG4gICAgICAgICAgLy8gc291cmNlIGFuZCB0YXJnZXQgYXJlIGltbXV0YWJsZSB2aWEgZGF0YSgpXG4gICAgICAgICAgdmFyIG1vdmUgPSBmYWxzZTtcbiAgICAgICAgICB2YXIgc3BlYyA9IHt9O1xuICAgICAgICAgIHZhciBzcmMgPSBvYmouZGF0YS5zb3VyY2U7XG4gICAgICAgICAgdmFyIHRndCA9IG9iai5kYXRhLnRhcmdldDtcblxuICAgICAgICAgIGlmIChzcmMgIT0gbnVsbCAmJiBzcmMgIT0gX2RhdGEyLnNvdXJjZSkge1xuICAgICAgICAgICAgc3BlYy5zb3VyY2UgPSAnJyArIHNyYzsgLy8gaWQgbXVzdCBiZSBzdHJpbmdcblxuICAgICAgICAgICAgbW92ZSA9IHRydWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHRndCAhPSBudWxsICYmIHRndCAhPSBfZGF0YTIudGFyZ2V0KSB7XG4gICAgICAgICAgICBzcGVjLnRhcmdldCA9ICcnICsgdGd0OyAvLyBpZCBtdXN0IGJlIHN0cmluZ1xuXG4gICAgICAgICAgICBtb3ZlID0gdHJ1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAobW92ZSkge1xuICAgICAgICAgICAgZWxlID0gZWxlLm1vdmUoc3BlYyk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIHBhcmVudCBpcyBpbW11dGFibGUgdmlhIGRhdGEoKVxuICAgICAgICAgIHZhciBuZXdQYXJlbnRWYWxTcGVjZCA9ICgncGFyZW50JyBpbiBvYmouZGF0YSk7XG4gICAgICAgICAgdmFyIHBhcmVudCA9IG9iai5kYXRhLnBhcmVudDtcblxuICAgICAgICAgIGlmIChuZXdQYXJlbnRWYWxTcGVjZCAmJiAocGFyZW50ICE9IG51bGwgfHwgX2RhdGEyLnBhcmVudCAhPSBudWxsKSAmJiBwYXJlbnQgIT0gX2RhdGEyLnBhcmVudCkge1xuICAgICAgICAgICAgaWYgKHBhcmVudCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIC8vIGNhbid0IHNldCB1bmRlZmluZWQgaW1wZXJhdGl2ZWx5LCBzbyB1c2UgbnVsbFxuICAgICAgICAgICAgICBwYXJlbnQgPSBudWxsO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAocGFyZW50ICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgcGFyZW50ID0gJycgKyBwYXJlbnQ7IC8vIGlkIG11c3QgYmUgc3RyaW5nXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGVsZSA9IGVsZS5tb3ZlKHtcbiAgICAgICAgICAgICAgcGFyZW50OiBwYXJlbnRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAob2JqLnBvc2l0aW9uKSB7XG4gICAgICAgIGVsZS5wb3NpdGlvbihvYmoucG9zaXRpb24pO1xuICAgICAgfSAvLyBpZ25vcmUgZ3JvdXAgLS0gaW1tdXRhYmxlXG5cblxuICAgICAgdmFyIGNoZWNrU3dpdGNoID0gZnVuY3Rpb24gY2hlY2tTd2l0Y2goaywgdHJ1ZUZuTmFtZSwgZmFsc2VGbk5hbWUpIHtcbiAgICAgICAgdmFyIG9ial9rID0gb2JqW2tdO1xuXG4gICAgICAgIGlmIChvYmpfayAhPSBudWxsICYmIG9ial9rICE9PSBwW2tdKSB7XG4gICAgICAgICAgaWYgKG9ial9rKSB7XG4gICAgICAgICAgICBlbGVbdHJ1ZUZuTmFtZV0oKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZWxlW2ZhbHNlRm5OYW1lXSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgY2hlY2tTd2l0Y2goJ3JlbW92ZWQnLCAncmVtb3ZlJywgJ3Jlc3RvcmUnKTtcbiAgICAgIGNoZWNrU3dpdGNoKCdzZWxlY3RlZCcsICdzZWxlY3QnLCAndW5zZWxlY3QnKTtcbiAgICAgIGNoZWNrU3dpdGNoKCdzZWxlY3RhYmxlJywgJ3NlbGVjdGlmeScsICd1bnNlbGVjdGlmeScpO1xuICAgICAgY2hlY2tTd2l0Y2goJ2xvY2tlZCcsICdsb2NrJywgJ3VubG9jaycpO1xuICAgICAgY2hlY2tTd2l0Y2goJ2dyYWJiYWJsZScsICdncmFiaWZ5JywgJ3VuZ3JhYmlmeScpO1xuICAgICAgY2hlY2tTd2l0Y2goJ3Bhbm5hYmxlJywgJ3BhbmlmeScsICd1bnBhbmlmeScpO1xuXG4gICAgICBpZiAob2JqLmNsYXNzZXMgIT0gbnVsbCkge1xuICAgICAgICBlbGUuY2xhc3NlcyhvYmouY2xhc3Nlcyk7XG4gICAgICB9XG5cbiAgICAgIGN5LmVuZEJhdGNoKCk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9IGVsc2UgaWYgKG9iaiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAvLyBnZXRcbiAgICAgIHZhciBqc29uID0ge1xuICAgICAgICBkYXRhOiBjb3B5KHAuZGF0YSksXG4gICAgICAgIHBvc2l0aW9uOiBjb3B5KHAucG9zaXRpb24pLFxuICAgICAgICBncm91cDogcC5ncm91cCxcbiAgICAgICAgcmVtb3ZlZDogcC5yZW1vdmVkLFxuICAgICAgICBzZWxlY3RlZDogcC5zZWxlY3RlZCxcbiAgICAgICAgc2VsZWN0YWJsZTogcC5zZWxlY3RhYmxlLFxuICAgICAgICBsb2NrZWQ6IHAubG9ja2VkLFxuICAgICAgICBncmFiYmFibGU6IHAuZ3JhYmJhYmxlLFxuICAgICAgICBwYW5uYWJsZTogcC5wYW5uYWJsZSxcbiAgICAgICAgY2xhc3NlczogbnVsbFxuICAgICAgfTtcbiAgICAgIGpzb24uY2xhc3NlcyA9ICcnO1xuICAgICAgdmFyIGkgPSAwO1xuICAgICAgcC5jbGFzc2VzLmZvckVhY2goZnVuY3Rpb24gKGNscykge1xuICAgICAgICByZXR1cm4ganNvbi5jbGFzc2VzICs9IGkrKyA9PT0gMCA/IGNscyA6ICcgJyArIGNscztcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIGpzb247XG4gICAgfVxuICB9O1xuXG4gIGVsZXNmbiQxLmpzb25zID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBqc29ucyA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1tpXTtcbiAgICAgIHZhciBqc29uID0gZWxlLmpzb24oKTtcbiAgICAgIGpzb25zLnB1c2goanNvbik7XG4gICAgfVxuXG4gICAgcmV0dXJuIGpzb25zO1xuICB9O1xuXG4gIGVsZXNmbiQxLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBjeSA9IHRoaXMuY3koKTtcbiAgICB2YXIgZWxlc0FyciA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZWxlID0gdGhpc1tpXTtcbiAgICAgIHZhciBqc29uID0gZWxlLmpzb24oKTtcbiAgICAgIHZhciBjbG9uZSA9IG5ldyBFbGVtZW50KGN5LCBqc29uLCBmYWxzZSk7IC8vIE5CIG5vIHJlc3RvcmVcblxuICAgICAgZWxlc0Fyci5wdXNoKGNsb25lKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IENvbGxlY3Rpb24oY3ksIGVsZXNBcnIpO1xuICB9O1xuXG4gIGVsZXNmbiQxLmNvcHkgPSBlbGVzZm4kMS5jbG9uZTtcblxuICBlbGVzZm4kMS5yZXN0b3JlID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBub3RpZnlSZW5kZXJlciA9IGFyZ3VtZW50cy5sZW5ndGggPiAwICYmIGFyZ3VtZW50c1swXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzBdIDogdHJ1ZTtcbiAgICB2YXIgYWRkVG9Qb29sID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiB0cnVlO1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgY3kgPSBzZWxmLmN5KCk7XG4gICAgdmFyIGN5X3AgPSBjeS5fcHJpdmF0ZTsgLy8gY3JlYXRlIGFycmF5cyBvZiBub2RlcyBhbmQgZWRnZXMsIHNpbmNlIHdlIG5lZWQgdG9cbiAgICAvLyByZXN0b3JlIHRoZSBub2RlcyBmaXJzdFxuXG4gICAgdmFyIG5vZGVzID0gW107XG4gICAgdmFyIGVkZ2VzID0gW107XG4gICAgdmFyIGVsZW1lbnRzO1xuXG4gICAgZm9yICh2YXIgX2kzID0gMCwgbCA9IHNlbGYubGVuZ3RoOyBfaTMgPCBsOyBfaTMrKykge1xuICAgICAgdmFyIGVsZSA9IHNlbGZbX2kzXTtcblxuICAgICAgaWYgKGFkZFRvUG9vbCAmJiAhZWxlLnJlbW92ZWQoKSkge1xuICAgICAgICAvLyBkb24ndCBuZWVkIHRvIGhhbmRsZSB0aGlzIGVsZVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH0gLy8ga2VlcCBub2RlcyBmaXJzdCBpbiB0aGUgYXJyYXkgYW5kIGVkZ2VzIGFmdGVyXG5cblxuICAgICAgaWYgKGVsZS5pc05vZGUoKSkge1xuICAgICAgICAvLyBwdXQgdG8gZnJvbnQgb2YgYXJyYXkgaWYgbm9kZVxuICAgICAgICBub2Rlcy5wdXNoKGVsZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBwdXQgdG8gZW5kIG9mIGFycmF5IGlmIGVkZ2VcbiAgICAgICAgZWRnZXMucHVzaChlbGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGVsZW1lbnRzID0gbm9kZXMuY29uY2F0KGVkZ2VzKTtcbiAgICB2YXIgaTtcblxuICAgIHZhciByZW1vdmVGcm9tRWxlbWVudHMgPSBmdW5jdGlvbiByZW1vdmVGcm9tRWxlbWVudHMoKSB7XG4gICAgICBlbGVtZW50cy5zcGxpY2UoaSwgMSk7XG4gICAgICBpLS07XG4gICAgfTsgLy8gbm93LCByZXN0b3JlIGVhY2ggZWxlbWVudFxuXG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgZWxlbWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBfZWxlMiA9IGVsZW1lbnRzW2ldO1xuICAgICAgdmFyIF9wcml2YXRlID0gX2VsZTIuX3ByaXZhdGU7XG4gICAgICB2YXIgX2RhdGEzID0gX3ByaXZhdGUuZGF0YTsgLy8gdGhlIHRyYXZlcnNhbCBjYWNoZSBzaG91bGQgc3RhcnQgZnJlc2ggd2hlbiBlbGUgaXMgYWRkZWRcblxuICAgICAgX2VsZTIuY2xlYXJUcmF2ZXJzYWxDYWNoZSgpOyAvLyBzZXQgaWQgYW5kIHZhbGlkYXRlXG5cblxuICAgICAgaWYgKCFhZGRUb1Bvb2wgJiYgIV9wcml2YXRlLnJlbW92ZWQpIDsgZWxzZSBpZiAoX2RhdGEzLmlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgX2RhdGEzLmlkID0gdXVpZCgpO1xuICAgICAgfSBlbHNlIGlmIChudW1iZXIkMShfZGF0YTMuaWQpKSB7XG4gICAgICAgIF9kYXRhMy5pZCA9ICcnICsgX2RhdGEzLmlkOyAvLyBub3cgaXQncyBhIHN0cmluZ1xuICAgICAgfSBlbHNlIGlmIChlbXB0eVN0cmluZyhfZGF0YTMuaWQpIHx8ICFzdHJpbmcoX2RhdGEzLmlkKSkge1xuICAgICAgICBlcnJvcignQ2FuIG5vdCBjcmVhdGUgZWxlbWVudCB3aXRoIGludmFsaWQgc3RyaW5nIElEIGAnICsgX2RhdGEzLmlkICsgJ2AnKTsgLy8gY2FuJ3QgY3JlYXRlIGVsZW1lbnQgaWYgaXQgaGFzIGVtcHR5IHN0cmluZyBhcyBpZCBvciBub24tc3RyaW5nIGlkXG5cbiAgICAgICAgcmVtb3ZlRnJvbUVsZW1lbnRzKCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfSBlbHNlIGlmIChjeS5oYXNFbGVtZW50V2l0aElkKF9kYXRhMy5pZCkpIHtcbiAgICAgICAgZXJyb3IoJ0NhbiBub3QgY3JlYXRlIHNlY29uZCBlbGVtZW50IHdpdGggSUQgYCcgKyBfZGF0YTMuaWQgKyAnYCcpOyAvLyBjYW4ndCBjcmVhdGUgZWxlbWVudCBpZiBvbmUgYWxyZWFkeSBoYXMgdGhhdCBpZFxuXG4gICAgICAgIHJlbW92ZUZyb21FbGVtZW50cygpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdmFyIGlkID0gX2RhdGEzLmlkOyAvLyBpZCBpcyBmaW5hbGlzZWQsIG5vdyBsZXQncyBrZWVwIGEgcmVmXG5cbiAgICAgIGlmIChfZWxlMi5pc05vZGUoKSkge1xuICAgICAgICAvLyBleHRyYSBjaGVja3MgZm9yIG5vZGVzXG4gICAgICAgIHZhciBwb3MgPSBfcHJpdmF0ZS5wb3NpdGlvbjsgLy8gbWFrZSBzdXJlIHRoZSBub2RlcyBoYXZlIGEgZGVmaW5lZCBwb3NpdGlvblxuXG4gICAgICAgIGlmIChwb3MueCA9PSBudWxsKSB7XG4gICAgICAgICAgcG9zLnggPSAwO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBvcy55ID09IG51bGwpIHtcbiAgICAgICAgICBwb3MueSA9IDA7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKF9lbGUyLmlzRWRnZSgpKSB7XG4gICAgICAgIC8vIGV4dHJhIGNoZWNrcyBmb3IgZWRnZXNcbiAgICAgICAgdmFyIGVkZ2UgPSBfZWxlMjtcbiAgICAgICAgdmFyIGZpZWxkcyA9IFsnc291cmNlJywgJ3RhcmdldCddO1xuICAgICAgICB2YXIgZmllbGRzTGVuZ3RoID0gZmllbGRzLmxlbmd0aDtcbiAgICAgICAgdmFyIGJhZFNvdXJjZU9yVGFyZ2V0ID0gZmFsc2U7XG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBmaWVsZHNMZW5ndGg7IGorKykge1xuICAgICAgICAgIHZhciBmaWVsZCA9IGZpZWxkc1tqXTtcbiAgICAgICAgICB2YXIgdmFsID0gX2RhdGEzW2ZpZWxkXTtcblxuICAgICAgICAgIGlmIChudW1iZXIkMSh2YWwpKSB7XG4gICAgICAgICAgICB2YWwgPSBfZGF0YTNbZmllbGRdID0gJycgKyBfZGF0YTNbZmllbGRdOyAvLyBub3cgc3RyaW5nXG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHZhbCA9PSBudWxsIHx8IHZhbCA9PT0gJycpIHtcbiAgICAgICAgICAgIC8vIGNhbid0IGNyZWF0ZSBpZiBzb3VyY2Ugb3IgdGFyZ2V0IGlzIG5vdCBkZWZpbmVkIHByb3Blcmx5XG4gICAgICAgICAgICBlcnJvcignQ2FuIG5vdCBjcmVhdGUgZWRnZSBgJyArIGlkICsgJ2Agd2l0aCB1bnNwZWNpZmllZCAnICsgZmllbGQpO1xuICAgICAgICAgICAgYmFkU291cmNlT3JUYXJnZXQgPSB0cnVlO1xuICAgICAgICAgIH0gZWxzZSBpZiAoIWN5Lmhhc0VsZW1lbnRXaXRoSWQodmFsKSkge1xuICAgICAgICAgICAgLy8gY2FuJ3QgY3JlYXRlIGVkZ2UgaWYgb25lIG9mIGl0cyBub2RlcyBkb2Vzbid0IGV4aXN0XG4gICAgICAgICAgICBlcnJvcignQ2FuIG5vdCBjcmVhdGUgZWRnZSBgJyArIGlkICsgJ2Agd2l0aCBub25leGlzdGFudCAnICsgZmllbGQgKyAnIGAnICsgdmFsICsgJ2AnKTtcbiAgICAgICAgICAgIGJhZFNvdXJjZU9yVGFyZ2V0ID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYmFkU291cmNlT3JUYXJnZXQpIHtcbiAgICAgICAgICByZW1vdmVGcm9tRWxlbWVudHMoKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfSAvLyBjYW4ndCBjcmVhdGUgdGhpc1xuXG5cbiAgICAgICAgdmFyIHNyYyA9IGN5LmdldEVsZW1lbnRCeUlkKF9kYXRhMy5zb3VyY2UpO1xuICAgICAgICB2YXIgdGd0ID0gY3kuZ2V0RWxlbWVudEJ5SWQoX2RhdGEzLnRhcmdldCk7IC8vIG9ubHkgb25lIGVkZ2UgaW4gbm9kZSBpZiBsb29wXG5cbiAgICAgICAgaWYgKHNyYy5zYW1lKHRndCkpIHtcbiAgICAgICAgICBzcmMuX3ByaXZhdGUuZWRnZXMucHVzaChlZGdlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzcmMuX3ByaXZhdGUuZWRnZXMucHVzaChlZGdlKTtcblxuICAgICAgICAgIHRndC5fcHJpdmF0ZS5lZGdlcy5wdXNoKGVkZ2UpO1xuICAgICAgICB9XG5cbiAgICAgICAgZWRnZS5fcHJpdmF0ZS5zb3VyY2UgPSBzcmM7XG4gICAgICAgIGVkZ2UuX3ByaXZhdGUudGFyZ2V0ID0gdGd0O1xuICAgICAgfSAvLyBpZiBpcyBlZGdlXG4gICAgICAvLyBjcmVhdGUgbW9jayBpZHMgLyBpbmRleGVzIG1hcHMgZm9yIGVsZW1lbnQgc28gaXQgY2FuIGJlIHVzZWQgbGlrZSBjb2xsZWN0aW9uc1xuXG5cbiAgICAgIF9wcml2YXRlLm1hcCA9IG5ldyBNYXAkMigpO1xuXG4gICAgICBfcHJpdmF0ZS5tYXAuc2V0KGlkLCB7XG4gICAgICAgIGVsZTogX2VsZTIsXG4gICAgICAgIGluZGV4OiAwXG4gICAgICB9KTtcblxuICAgICAgX3ByaXZhdGUucmVtb3ZlZCA9IGZhbHNlO1xuXG4gICAgICBpZiAoYWRkVG9Qb29sKSB7XG4gICAgICAgIGN5LmFkZFRvUG9vbChfZWxlMik7XG4gICAgICB9XG4gICAgfSAvLyBmb3IgZWFjaCBlbGVtZW50XG4gICAgLy8gZG8gY29tcG91bmQgbm9kZSBzYW5pdHkgY2hlY2tzXG5cblxuICAgIGZvciAodmFyIF9pNCA9IDA7IF9pNCA8IG5vZGVzLmxlbmd0aDsgX2k0KyspIHtcbiAgICAgIC8vIGVhY2ggbm9kZVxuICAgICAgdmFyIG5vZGUgPSBub2Rlc1tfaTRdO1xuICAgICAgdmFyIF9kYXRhNCA9IG5vZGUuX3ByaXZhdGUuZGF0YTtcblxuICAgICAgaWYgKG51bWJlciQxKF9kYXRhNC5wYXJlbnQpKSB7XG4gICAgICAgIC8vIHRoZW4gYXV0b21ha2Ugc3RyaW5nXG4gICAgICAgIF9kYXRhNC5wYXJlbnQgPSAnJyArIF9kYXRhNC5wYXJlbnQ7XG4gICAgICB9XG5cbiAgICAgIHZhciBwYXJlbnRJZCA9IF9kYXRhNC5wYXJlbnQ7XG4gICAgICB2YXIgc3BlY2lmaWVkUGFyZW50ID0gcGFyZW50SWQgIT0gbnVsbDtcblxuICAgICAgaWYgKHNwZWNpZmllZFBhcmVudCB8fCBub2RlLl9wcml2YXRlLnBhcmVudCkge1xuICAgICAgICB2YXIgcGFyZW50ID0gbm9kZS5fcHJpdmF0ZS5wYXJlbnQgPyBjeS5jb2xsZWN0aW9uKCkubWVyZ2Uobm9kZS5fcHJpdmF0ZS5wYXJlbnQpIDogY3kuZ2V0RWxlbWVudEJ5SWQocGFyZW50SWQpO1xuXG4gICAgICAgIGlmIChwYXJlbnQuZW1wdHkoKSkge1xuICAgICAgICAgIC8vIG5vbi1leGlzdGFudCBwYXJlbnQ7IGp1c3QgcmVtb3ZlIGl0XG4gICAgICAgICAgX2RhdGE0LnBhcmVudCA9IHVuZGVmaW5lZDtcbiAgICAgICAgfSBlbHNlIGlmIChwYXJlbnRbMF0ucmVtb3ZlZCgpKSB7XG4gICAgICAgICAgd2FybignTm9kZSBhZGRlZCB3aXRoIG1pc3NpbmcgcGFyZW50LCByZWZlcmVuY2UgdG8gcGFyZW50IHJlbW92ZWQnKTtcbiAgICAgICAgICBfZGF0YTQucGFyZW50ID0gdW5kZWZpbmVkO1xuICAgICAgICAgIG5vZGUuX3ByaXZhdGUucGFyZW50ID0gbnVsbDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB2YXIgc2VsZkFzUGFyZW50ID0gZmFsc2U7XG4gICAgICAgICAgdmFyIGFuY2VzdG9yID0gcGFyZW50O1xuXG4gICAgICAgICAgd2hpbGUgKCFhbmNlc3Rvci5lbXB0eSgpKSB7XG4gICAgICAgICAgICBpZiAobm9kZS5zYW1lKGFuY2VzdG9yKSkge1xuICAgICAgICAgICAgICAvLyBtYXJrIHNlbGYgYXMgcGFyZW50IGFuZCByZW1vdmUgZnJvbSBkYXRhXG4gICAgICAgICAgICAgIHNlbGZBc1BhcmVudCA9IHRydWU7XG4gICAgICAgICAgICAgIF9kYXRhNC5wYXJlbnQgPSB1bmRlZmluZWQ7IC8vIHJlbW92ZSBwYXJlbnQgcmVmZXJlbmNlXG4gICAgICAgICAgICAgIC8vIGV4aXQgb3Igd2UgbG9vcCBmb3JldmVyXG5cbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGFuY2VzdG9yID0gYW5jZXN0b3IucGFyZW50KCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFzZWxmQXNQYXJlbnQpIHtcbiAgICAgICAgICAgIC8vIGNvbm5lY3Qgd2l0aCBjaGlsZHJlblxuICAgICAgICAgICAgcGFyZW50WzBdLl9wcml2YXRlLmNoaWxkcmVuLnB1c2gobm9kZSk7XG5cbiAgICAgICAgICAgIG5vZGUuX3ByaXZhdGUucGFyZW50ID0gcGFyZW50WzBdOyAvLyBsZXQgdGhlIGNvcmUga25vdyB3ZSBoYXZlIGEgY29tcG91bmQgZ3JhcGhcblxuICAgICAgICAgICAgY3lfcC5oYXNDb21wb3VuZE5vZGVzID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gLy8gZWxzZVxuXG4gICAgICB9IC8vIGlmIHNwZWNpZmllZCBwYXJlbnRcblxuICAgIH0gLy8gZm9yIGVhY2ggbm9kZVxuXG5cbiAgICBpZiAoZWxlbWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgdmFyIHJlc3RvcmVkID0gZWxlbWVudHMubGVuZ3RoID09PSBzZWxmLmxlbmd0aCA/IHNlbGYgOiBuZXcgQ29sbGVjdGlvbihjeSwgZWxlbWVudHMpO1xuXG4gICAgICBmb3IgKHZhciBfaTUgPSAwOyBfaTUgPCByZXN0b3JlZC5sZW5ndGg7IF9pNSsrKSB7XG4gICAgICAgIHZhciBfZWxlMyA9IHJlc3RvcmVkW19pNV07XG5cbiAgICAgICAgaWYgKF9lbGUzLmlzTm9kZSgpKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH0gLy8gYWRkaW5nIGFuIGVkZ2UgaW52YWxpZGF0ZXMgdGhlIHRyYXZlcnNhbCBjYWNoZXMgZm9yIHRoZSBwYXJhbGxlbCBlZGdlc1xuXG5cbiAgICAgICAgX2VsZTMucGFyYWxsZWxFZGdlcygpLmNsZWFyVHJhdmVyc2FsQ2FjaGUoKTsgLy8gYWRkaW5nIGFuIGVkZ2UgaW52YWxpZGF0ZXMgdGhlIHRyYXZlcnNhbCBjYWNoZSBmb3IgdGhlIGNvbm5lY3RlZCBub2Rlc1xuXG5cbiAgICAgICAgX2VsZTMuc291cmNlKCkuY2xlYXJUcmF2ZXJzYWxDYWNoZSgpO1xuXG4gICAgICAgIF9lbGUzLnRhcmdldCgpLmNsZWFyVHJhdmVyc2FsQ2FjaGUoKTtcbiAgICAgIH1cblxuICAgICAgdmFyIHRvVXBkYXRlU3R5bGU7XG5cbiAgICAgIGlmIChjeV9wLmhhc0NvbXBvdW5kTm9kZXMpIHtcbiAgICAgICAgdG9VcGRhdGVTdHlsZSA9IGN5LmNvbGxlY3Rpb24oKS5tZXJnZShyZXN0b3JlZCkubWVyZ2UocmVzdG9yZWQuY29ubmVjdGVkTm9kZXMoKSkubWVyZ2UocmVzdG9yZWQucGFyZW50KCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdG9VcGRhdGVTdHlsZSA9IHJlc3RvcmVkO1xuICAgICAgfVxuXG4gICAgICB0b1VwZGF0ZVN0eWxlLmRpcnR5Q29tcG91bmRCb3VuZHNDYWNoZSgpLmRpcnR5Qm91bmRpbmdCb3hDYWNoZSgpLnVwZGF0ZVN0eWxlKG5vdGlmeVJlbmRlcmVyKTtcblxuICAgICAgaWYgKG5vdGlmeVJlbmRlcmVyKSB7XG4gICAgICAgIHJlc3RvcmVkLmVtaXRBbmROb3RpZnkoJ2FkZCcpO1xuICAgICAgfSBlbHNlIGlmIChhZGRUb1Bvb2wpIHtcbiAgICAgICAgcmVzdG9yZWQuZW1pdCgnYWRkJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlbGY7IC8vIGNoYWluYWJpbGl0eVxuICB9O1xuXG4gIGVsZXNmbiQxLnJlbW92ZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGVsZSA9IHRoaXNbMF07XG4gICAgcmV0dXJuIGVsZSAmJiBlbGUuX3ByaXZhdGUucmVtb3ZlZDtcbiAgfTtcblxuICBlbGVzZm4kMS5pbnNpZGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGVsZSA9IHRoaXNbMF07XG4gICAgcmV0dXJuIGVsZSAmJiAhZWxlLl9wcml2YXRlLnJlbW92ZWQ7XG4gIH07XG5cbiAgZWxlc2ZuJDEucmVtb3ZlID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBub3RpZnlSZW5kZXJlciA9IGFyZ3VtZW50cy5sZW5ndGggPiAwICYmIGFyZ3VtZW50c1swXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzBdIDogdHJ1ZTtcbiAgICB2YXIgcmVtb3ZlRnJvbVBvb2wgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IHRydWU7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBlbGVzVG9SZW1vdmUgPSBbXTtcbiAgICB2YXIgZWxlc1RvUmVtb3ZlSWRzID0ge307XG4gICAgdmFyIGN5ID0gc2VsZi5fcHJpdmF0ZS5jeTsgLy8gYWRkIGNvbm5lY3RlZCBlZGdlc1xuXG4gICAgZnVuY3Rpb24gYWRkQ29ubmVjdGVkRWRnZXMobm9kZSkge1xuICAgICAgdmFyIGVkZ2VzID0gbm9kZS5fcHJpdmF0ZS5lZGdlcztcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBlZGdlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBhZGQoZWRnZXNbaV0pO1xuICAgICAgfVxuICAgIH0gLy8gYWRkIGRlc2NlbmRhbnQgbm9kZXNcblxuXG4gICAgZnVuY3Rpb24gYWRkQ2hpbGRyZW4obm9kZSkge1xuICAgICAgdmFyIGNoaWxkcmVuID0gbm9kZS5fcHJpdmF0ZS5jaGlsZHJlbjtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgICAgICBhZGQoY2hpbGRyZW5baV0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFkZChlbGUpIHtcbiAgICAgIHZhciBhbHJlYWR5QWRkZWQgPSBlbGVzVG9SZW1vdmVJZHNbZWxlLmlkKCldO1xuXG4gICAgICBpZiAocmVtb3ZlRnJvbVBvb2wgJiYgZWxlLnJlbW92ZWQoKSB8fCBhbHJlYWR5QWRkZWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWxlc1RvUmVtb3ZlSWRzW2VsZS5pZCgpXSA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbGUuaXNOb2RlKCkpIHtcbiAgICAgICAgZWxlc1RvUmVtb3ZlLnB1c2goZWxlKTsgLy8gbm9kZXMgYXJlIHJlbW92ZWQgbGFzdFxuXG4gICAgICAgIGFkZENvbm5lY3RlZEVkZ2VzKGVsZSk7XG4gICAgICAgIGFkZENoaWxkcmVuKGVsZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlbGVzVG9SZW1vdmUudW5zaGlmdChlbGUpOyAvLyBlZGdlcyBhcmUgcmVtb3ZlZCBmaXJzdFxuICAgICAgfVxuICAgIH0gLy8gbWFrZSB0aGUgbGlzdCBvZiBlbGVtZW50cyB0byByZW1vdmVcbiAgICAvLyAobWF5IGJlIHJlbW92aW5nIG1vcmUgdGhhbiBzcGVjaWZpZWQgZHVlIHRvIGNvbm5lY3RlZCBlZGdlcyBldGMpXG5cblxuICAgIGZvciAodmFyIGkgPSAwLCBsID0gc2VsZi5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgIHZhciBlbGUgPSBzZWxmW2ldO1xuICAgICAgYWRkKGVsZSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVtb3ZlRWRnZVJlZihub2RlLCBlZGdlKSB7XG4gICAgICB2YXIgY29ubmVjdGVkRWRnZXMgPSBub2RlLl9wcml2YXRlLmVkZ2VzO1xuICAgICAgcmVtb3ZlRnJvbUFycmF5KGNvbm5lY3RlZEVkZ2VzLCBlZGdlKTsgLy8gcmVtb3ZpbmcgYW4gZWRnZXMgaW52YWxpZGF0ZXMgdGhlIHRyYXZlcnNhbCBjYWNoZSBmb3IgaXRzIG5vZGVzXG5cbiAgICAgIG5vZGUuY2xlYXJUcmF2ZXJzYWxDYWNoZSgpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlbW92ZVBhcmFsbGVsUmVmKHBsbEVkZ2UpIHtcbiAgICAgIC8vIHJlbW92aW5nIGFuIGVkZ2UgaW52YWxpZGF0ZXMgdGhlIHRyYXZlcnNhbCBjYWNoZXMgZm9yIHRoZSBwYXJhbGxlbCBlZGdlc1xuICAgICAgcGxsRWRnZS5jbGVhclRyYXZlcnNhbENhY2hlKCk7XG4gICAgfVxuXG4gICAgdmFyIGFsdGVyZWRQYXJlbnRzID0gW107XG4gICAgYWx0ZXJlZFBhcmVudHMuaWRzID0ge307XG5cbiAgICBmdW5jdGlvbiByZW1vdmVDaGlsZFJlZihwYXJlbnQsIGVsZSkge1xuICAgICAgZWxlID0gZWxlWzBdO1xuICAgICAgcGFyZW50ID0gcGFyZW50WzBdO1xuICAgICAgdmFyIGNoaWxkcmVuID0gcGFyZW50Ll9wcml2YXRlLmNoaWxkcmVuO1xuICAgICAgdmFyIHBpZCA9IHBhcmVudC5pZCgpO1xuICAgICAgcmVtb3ZlRnJvbUFycmF5KGNoaWxkcmVuLCBlbGUpOyAvLyByZW1vdmUgcGFyZW50ID0+IGNoaWxkIHJlZlxuXG4gICAgICBlbGUuX3ByaXZhdGUucGFyZW50ID0gbnVsbDsgLy8gcmVtb3ZlIGNoaWxkID0+IHBhcmVudCByZWZcblxuICAgICAgaWYgKCFhbHRlcmVkUGFyZW50cy5pZHNbcGlkXSkge1xuICAgICAgICBhbHRlcmVkUGFyZW50cy5pZHNbcGlkXSA9IHRydWU7XG4gICAgICAgIGFsdGVyZWRQYXJlbnRzLnB1c2gocGFyZW50KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBzZWxmLmRpcnR5Q29tcG91bmRCb3VuZHNDYWNoZSgpO1xuXG4gICAgaWYgKHJlbW92ZUZyb21Qb29sKSB7XG4gICAgICBjeS5yZW1vdmVGcm9tUG9vbChlbGVzVG9SZW1vdmUpOyAvLyByZW1vdmUgZnJvbSBjb3JlIHBvb2xcbiAgICB9XG5cbiAgICBmb3IgKHZhciBfaTYgPSAwOyBfaTYgPCBlbGVzVG9SZW1vdmUubGVuZ3RoOyBfaTYrKykge1xuICAgICAgdmFyIF9lbGU0ID0gZWxlc1RvUmVtb3ZlW19pNl07XG5cbiAgICAgIGlmIChfZWxlNC5pc0VkZ2UoKSkge1xuICAgICAgICAvLyByZW1vdmUgcmVmZXJlbmNlcyB0byB0aGlzIGVkZ2UgaW4gaXRzIGNvbm5lY3RlZCBub2Rlc1xuICAgICAgICB2YXIgc3JjID0gX2VsZTQuc291cmNlKClbMF07XG5cbiAgICAgICAgdmFyIHRndCA9IF9lbGU0LnRhcmdldCgpWzBdO1xuXG4gICAgICAgIHJlbW92ZUVkZ2VSZWYoc3JjLCBfZWxlNCk7XG4gICAgICAgIHJlbW92ZUVkZ2VSZWYodGd0LCBfZWxlNCk7XG5cbiAgICAgICAgdmFyIHBsbEVkZ2VzID0gX2VsZTQucGFyYWxsZWxFZGdlcygpO1xuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgcGxsRWRnZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICB2YXIgcGxsRWRnZSA9IHBsbEVkZ2VzW2pdO1xuICAgICAgICAgIHJlbW92ZVBhcmFsbGVsUmVmKHBsbEVkZ2UpO1xuXG4gICAgICAgICAgaWYgKHBsbEVkZ2UuaXNCdW5kbGVkQmV6aWVyKCkpIHtcbiAgICAgICAgICAgIHBsbEVkZ2UuZGlydHlCb3VuZGluZ0JveENhY2hlKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyByZW1vdmUgcmVmZXJlbmNlIHRvIHBhcmVudFxuICAgICAgICB2YXIgcGFyZW50ID0gX2VsZTQucGFyZW50KCk7XG5cbiAgICAgICAgaWYgKHBhcmVudC5sZW5ndGggIT09IDApIHtcbiAgICAgICAgICByZW1vdmVDaGlsZFJlZihwYXJlbnQsIF9lbGU0KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAocmVtb3ZlRnJvbVBvb2wpIHtcbiAgICAgICAgLy8gbWFyayBhcyByZW1vdmVkXG4gICAgICAgIF9lbGU0Ll9wcml2YXRlLnJlbW92ZWQgPSB0cnVlO1xuICAgICAgfVxuICAgIH0gLy8gY2hlY2sgdG8gc2VlIGlmIHdlIGhhdmUgYSBjb21wb3VuZCBncmFwaCBvciBub3RcblxuXG4gICAgdmFyIGVsZXNTdGlsbEluc2lkZSA9IGN5Ll9wcml2YXRlLmVsZW1lbnRzO1xuICAgIGN5Ll9wcml2YXRlLmhhc0NvbXBvdW5kTm9kZXMgPSBmYWxzZTtcblxuICAgIGZvciAodmFyIF9pNyA9IDA7IF9pNyA8IGVsZXNTdGlsbEluc2lkZS5sZW5ndGg7IF9pNysrKSB7XG4gICAgICB2YXIgX2VsZTUgPSBlbGVzU3RpbGxJbnNpZGVbX2k3XTtcblxuICAgICAgaWYgKF9lbGU1LmlzUGFyZW50KCkpIHtcbiAgICAgICAgY3kuX3ByaXZhdGUuaGFzQ29tcG91bmROb2RlcyA9IHRydWU7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciByZW1vdmVkRWxlbWVudHMgPSBuZXcgQ29sbGVjdGlvbih0aGlzLmN5KCksIGVsZXNUb1JlbW92ZSk7XG5cbiAgICBpZiAocmVtb3ZlZEVsZW1lbnRzLnNpemUoKSA+IDApIHtcbiAgICAgIC8vIG11c3QgbWFudWFsbHkgbm90aWZ5IHNpbmNlIHRyaWdnZXIgd29uJ3QgZG8gdGhpcyBhdXRvbWF0aWNhbGx5IG9uY2UgcmVtb3ZlZFxuICAgICAgaWYgKG5vdGlmeVJlbmRlcmVyKSB7XG4gICAgICAgIHJlbW92ZWRFbGVtZW50cy5lbWl0QW5kTm90aWZ5KCdyZW1vdmUnKTtcbiAgICAgIH0gZWxzZSBpZiAocmVtb3ZlRnJvbVBvb2wpIHtcbiAgICAgICAgcmVtb3ZlZEVsZW1lbnRzLmVtaXQoJ3JlbW92ZScpO1xuICAgICAgfVxuICAgIH0gLy8gdGhlIHBhcmVudHMgd2hvIHdlcmUgbW9kaWZpZWQgYnkgdGhlIHJlbW92YWwgbmVlZCB0aGVpciBzdHlsZSB1cGRhdGVkXG5cblxuICAgIGZvciAodmFyIF9pOCA9IDA7IF9pOCA8IGFsdGVyZWRQYXJlbnRzLmxlbmd0aDsgX2k4KyspIHtcbiAgICAgIHZhciBfZWxlNiA9IGFsdGVyZWRQYXJlbnRzW19pOF07XG5cbiAgICAgIGlmICghcmVtb3ZlRnJvbVBvb2wgfHwgIV9lbGU2LnJlbW92ZWQoKSkge1xuICAgICAgICBfZWxlNi51cGRhdGVTdHlsZSgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZW1vdmVkRWxlbWVudHM7XG4gIH07XG5cbiAgZWxlc2ZuJDEubW92ZSA9IGZ1bmN0aW9uIChzdHJ1Y3QpIHtcbiAgICB2YXIgY3kgPSB0aGlzLl9wcml2YXRlLmN5O1xuICAgIHZhciBlbGVzID0gdGhpczsgLy8ganVzdCBjbGVhbiB1cCByZWZzLCBjYWNoZXMsIGV0Yy4gaW4gdGhlIHNhbWUgd2F5IGFzIHdoZW4gcmVtb3ZpbmcgYW5kIHRoZW4gcmVzdG9yaW5nXG4gICAgLy8gKG91ciBjYWxscyB0byByZW1vdmUvcmVzdG9yZSBkbyBub3QgcmVtb3ZlIGZyb20gdGhlIGdyYXBoIG9yIG1ha2UgZXZlbnRzKVxuXG4gICAgdmFyIG5vdGlmeVJlbmRlcmVyID0gZmFsc2U7XG4gICAgdmFyIG1vZGlmeVBvb2wgPSBmYWxzZTtcblxuICAgIHZhciB0b1N0cmluZyA9IGZ1bmN0aW9uIHRvU3RyaW5nKGlkKSB7XG4gICAgICByZXR1cm4gaWQgPT0gbnVsbCA/IGlkIDogJycgKyBpZDtcbiAgICB9OyAvLyBpZCBtdXN0IGJlIHN0cmluZ1xuXG5cbiAgICBpZiAoc3RydWN0LnNvdXJjZSAhPT0gdW5kZWZpbmVkIHx8IHN0cnVjdC50YXJnZXQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdmFyIHNyY0lkID0gdG9TdHJpbmcoc3RydWN0LnNvdXJjZSk7XG4gICAgICB2YXIgdGd0SWQgPSB0b1N0cmluZyhzdHJ1Y3QudGFyZ2V0KTtcbiAgICAgIHZhciBzcmNFeGlzdHMgPSBzcmNJZCAhPSBudWxsICYmIGN5Lmhhc0VsZW1lbnRXaXRoSWQoc3JjSWQpO1xuICAgICAgdmFyIHRndEV4aXN0cyA9IHRndElkICE9IG51bGwgJiYgY3kuaGFzRWxlbWVudFdpdGhJZCh0Z3RJZCk7XG5cbiAgICAgIGlmIChzcmNFeGlzdHMgfHwgdGd0RXhpc3RzKSB7XG4gICAgICAgIGN5LmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAvLyBhdm9pZCBkdXBsaWNhdGUgc3R5bGUgdXBkYXRlc1xuICAgICAgICAgIGVsZXMucmVtb3ZlKG5vdGlmeVJlbmRlcmVyLCBtb2RpZnlQb29sKTsgLy8gY2xlYW4gdXAgcmVmcyBldGMuXG5cbiAgICAgICAgICBlbGVzLmVtaXRBbmROb3RpZnkoJ21vdmVvdXQnKTtcblxuICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG4gICAgICAgICAgICB2YXIgX2RhdGE1ID0gZWxlLl9wcml2YXRlLmRhdGE7XG5cbiAgICAgICAgICAgIGlmIChlbGUuaXNFZGdlKCkpIHtcbiAgICAgICAgICAgICAgaWYgKHNyY0V4aXN0cykge1xuICAgICAgICAgICAgICAgIF9kYXRhNS5zb3VyY2UgPSBzcmNJZDtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGlmICh0Z3RFeGlzdHMpIHtcbiAgICAgICAgICAgICAgICBfZGF0YTUudGFyZ2V0ID0gdGd0SWQ7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBlbGVzLnJlc3RvcmUobm90aWZ5UmVuZGVyZXIsIG1vZGlmeVBvb2wpOyAvLyBtYWtlIG5ldyByZWZzLCBzdHlsZSwgZXRjLlxuICAgICAgICB9KTtcbiAgICAgICAgZWxlcy5lbWl0QW5kTm90aWZ5KCdtb3ZlJyk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChzdHJ1Y3QucGFyZW50ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIC8vIG1vdmUgbm9kZSB0byBuZXcgcGFyZW50XG4gICAgICB2YXIgcGFyZW50SWQgPSB0b1N0cmluZyhzdHJ1Y3QucGFyZW50KTtcbiAgICAgIHZhciBwYXJlbnRFeGlzdHMgPSBwYXJlbnRJZCA9PT0gbnVsbCB8fCBjeS5oYXNFbGVtZW50V2l0aElkKHBhcmVudElkKTtcblxuICAgICAgaWYgKHBhcmVudEV4aXN0cykge1xuICAgICAgICB2YXIgcGlkVG9Bc3NpZ24gPSBwYXJlbnRJZCA9PT0gbnVsbCA/IHVuZGVmaW5lZCA6IHBhcmVudElkO1xuICAgICAgICBjeS5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgLy8gYXZvaWQgZHVwbGljYXRlIHN0eWxlIHVwZGF0ZXNcbiAgICAgICAgICB2YXIgdXBkYXRlZCA9IGVsZXMucmVtb3ZlKG5vdGlmeVJlbmRlcmVyLCBtb2RpZnlQb29sKTsgLy8gY2xlYW4gdXAgcmVmcyBldGMuXG5cbiAgICAgICAgICB1cGRhdGVkLmVtaXRBbmROb3RpZnkoJ21vdmVvdXQnKTtcblxuICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG4gICAgICAgICAgICB2YXIgX2RhdGE2ID0gZWxlLl9wcml2YXRlLmRhdGE7XG5cbiAgICAgICAgICAgIGlmIChlbGUuaXNOb2RlKCkpIHtcbiAgICAgICAgICAgICAgX2RhdGE2LnBhcmVudCA9IHBpZFRvQXNzaWduO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHVwZGF0ZWQucmVzdG9yZShub3RpZnlSZW5kZXJlciwgbW9kaWZ5UG9vbCk7IC8vIG1ha2UgbmV3IHJlZnMsIHN0eWxlLCBldGMuXG4gICAgICAgIH0pO1xuICAgICAgICBlbGVzLmVtaXRBbmROb3RpZnkoJ21vdmUnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfTtcblxuICBbZWxlc2ZuJGosIGVsZXNmbiRpLCBlbGVzZm4kaCwgZWxlc2ZuJGcsIGVsZXNmbiRmLCBkYXRhLCBlbGVzZm4kZCwgZGltZW5zaW9ucywgZWxlc2ZuJDksIGVsZXNmbiQ4LCBlbGVzZm4kNywgZWxlc2ZuJDYsIGVsZXNmbiQ1LCBlbGVzZm4kNCwgZWxlc2ZuJDMsIGVsZXNmbiQyXS5mb3JFYWNoKGZ1bmN0aW9uIChwcm9wcykge1xuICAgIGV4dGVuZChlbGVzZm4kMSwgcHJvcHMpO1xuICB9KTtcblxuICB2YXIgY29yZWZuJDkgPSB7XG4gICAgYWRkOiBmdW5jdGlvbiBhZGQob3B0cykge1xuICAgICAgdmFyIGVsZW1lbnRzO1xuICAgICAgdmFyIGN5ID0gdGhpczsgLy8gYWRkIHRoZSBlbGVtZW50c1xuXG4gICAgICBpZiAoZWxlbWVudE9yQ29sbGVjdGlvbihvcHRzKSkge1xuICAgICAgICB2YXIgZWxlcyA9IG9wdHM7XG5cbiAgICAgICAgaWYgKGVsZXMuX3ByaXZhdGUuY3kgPT09IGN5KSB7XG4gICAgICAgICAgLy8gc2FtZSBpbnN0YW5jZSA9PiBqdXN0IHJlc3RvcmVcbiAgICAgICAgICBlbGVtZW50cyA9IGVsZXMucmVzdG9yZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIG90aGVyd2lzZSwgY29weSBmcm9tIGpzb25cbiAgICAgICAgICB2YXIganNvbnMgPSBbXTtcblxuICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG4gICAgICAgICAgICBqc29ucy5wdXNoKGVsZS5qc29uKCkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGVsZW1lbnRzID0gbmV3IENvbGxlY3Rpb24oY3ksIGpzb25zKTtcbiAgICAgICAgfVxuICAgICAgfSAvLyBzcGVjaWZ5IGFuIGFycmF5IG9mIG9wdGlvbnNcbiAgICAgIGVsc2UgaWYgKGFycmF5KG9wdHMpKSB7XG4gICAgICAgIHZhciBfanNvbnMgPSBvcHRzO1xuICAgICAgICBlbGVtZW50cyA9IG5ldyBDb2xsZWN0aW9uKGN5LCBfanNvbnMpO1xuICAgICAgfSAvLyBzcGVjaWZ5IHZpYSBvcHRzLm5vZGVzIGFuZCBvcHRzLmVkZ2VzXG4gICAgICBlbHNlIGlmIChwbGFpbk9iamVjdChvcHRzKSAmJiAoYXJyYXkob3B0cy5ub2RlcykgfHwgYXJyYXkob3B0cy5lZGdlcykpKSB7XG4gICAgICAgIHZhciBlbGVzQnlHcm91cCA9IG9wdHM7XG4gICAgICAgIHZhciBfanNvbnMyID0gW107XG4gICAgICAgIHZhciBncnMgPSBbJ25vZGVzJywgJ2VkZ2VzJ107XG5cbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBpbCA9IGdycy5sZW5ndGg7IF9pIDwgaWw7IF9pKyspIHtcbiAgICAgICAgICB2YXIgZ3JvdXAgPSBncnNbX2ldO1xuICAgICAgICAgIHZhciBlbGVzQXJyYXkgPSBlbGVzQnlHcm91cFtncm91cF07XG5cbiAgICAgICAgICBpZiAoYXJyYXkoZWxlc0FycmF5KSkge1xuICAgICAgICAgICAgZm9yICh2YXIgaiA9IDAsIGpsID0gZWxlc0FycmF5Lmxlbmd0aDsgaiA8IGpsOyBqKyspIHtcbiAgICAgICAgICAgICAgdmFyIGpzb24gPSBleHRlbmQoe1xuICAgICAgICAgICAgICAgIGdyb3VwOiBncm91cFxuICAgICAgICAgICAgICB9LCBlbGVzQXJyYXlbal0pO1xuXG4gICAgICAgICAgICAgIF9qc29uczIucHVzaChqc29uKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBlbGVtZW50cyA9IG5ldyBDb2xsZWN0aW9uKGN5LCBfanNvbnMyKTtcbiAgICAgIH0gLy8gc3BlY2lmeSBvcHRpb25zIGZvciBvbmUgZWxlbWVudFxuICAgICAgZWxzZSB7XG4gICAgICAgIHZhciBfanNvbiA9IG9wdHM7XG4gICAgICAgIGVsZW1lbnRzID0gbmV3IEVsZW1lbnQoY3ksIF9qc29uKS5jb2xsZWN0aW9uKCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBlbGVtZW50cztcbiAgICB9LFxuICAgIHJlbW92ZTogZnVuY3Rpb24gcmVtb3ZlKGNvbGxlY3Rpb24pIHtcbiAgICAgIGlmIChlbGVtZW50T3JDb2xsZWN0aW9uKGNvbGxlY3Rpb24pKSA7IGVsc2UgaWYgKHN0cmluZyhjb2xsZWN0aW9uKSkge1xuICAgICAgICB2YXIgc2VsZWN0b3IgPSBjb2xsZWN0aW9uO1xuICAgICAgICBjb2xsZWN0aW9uID0gdGhpcy4kKHNlbGVjdG9yKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGNvbGxlY3Rpb24ucmVtb3ZlKCk7XG4gICAgfVxuICB9O1xuXG4gIC8qIGdsb2JhbCBGbG9hdDMyQXJyYXkgKi9cblxuICAvKiEgQmV6aWVyIGN1cnZlIGZ1bmN0aW9uIGdlbmVyYXRvci4gQ29weXJpZ2h0IEdhZXRhbiBSZW5hdWRlYXUuIE1JVCBMaWNlbnNlOiBodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01JVF9MaWNlbnNlICovXG4gIGZ1bmN0aW9uIGdlbmVyYXRlQ3ViaWNCZXppZXIobVgxLCBtWTEsIG1YMiwgbVkyKSB7XG4gICAgdmFyIE5FV1RPTl9JVEVSQVRJT05TID0gNCxcbiAgICAgICAgTkVXVE9OX01JTl9TTE9QRSA9IDAuMDAxLFxuICAgICAgICBTVUJESVZJU0lPTl9QUkVDSVNJT04gPSAwLjAwMDAwMDEsXG4gICAgICAgIFNVQkRJVklTSU9OX01BWF9JVEVSQVRJT05TID0gMTAsXG4gICAgICAgIGtTcGxpbmVUYWJsZVNpemUgPSAxMSxcbiAgICAgICAga1NhbXBsZVN0ZXBTaXplID0gMS4wIC8gKGtTcGxpbmVUYWJsZVNpemUgLSAxLjApLFxuICAgICAgICBmbG9hdDMyQXJyYXlTdXBwb3J0ZWQgPSB0eXBlb2YgRmxvYXQzMkFycmF5ICE9PSAndW5kZWZpbmVkJztcbiAgICAvKiBNdXN0IGNvbnRhaW4gZm91ciBhcmd1bWVudHMuICovXG5cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCAhPT0gNCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICAvKiBBcmd1bWVudHMgbXVzdCBiZSBudW1iZXJzLiAqL1xuXG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IDQ7ICsraSkge1xuICAgICAgaWYgKHR5cGVvZiBhcmd1bWVudHNbaV0gIT09IFwibnVtYmVyXCIgfHwgaXNOYU4oYXJndW1lbnRzW2ldKSB8fCAhaXNGaW5pdGUoYXJndW1lbnRzW2ldKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIC8qIFggdmFsdWVzIG11c3QgYmUgaW4gdGhlIFswLCAxXSByYW5nZS4gKi9cblxuXG4gICAgbVgxID0gTWF0aC5taW4obVgxLCAxKTtcbiAgICBtWDIgPSBNYXRoLm1pbihtWDIsIDEpO1xuICAgIG1YMSA9IE1hdGgubWF4KG1YMSwgMCk7XG4gICAgbVgyID0gTWF0aC5tYXgobVgyLCAwKTtcbiAgICB2YXIgbVNhbXBsZVZhbHVlcyA9IGZsb2F0MzJBcnJheVN1cHBvcnRlZCA/IG5ldyBGbG9hdDMyQXJyYXkoa1NwbGluZVRhYmxlU2l6ZSkgOiBuZXcgQXJyYXkoa1NwbGluZVRhYmxlU2l6ZSk7XG5cbiAgICBmdW5jdGlvbiBBKGFBMSwgYUEyKSB7XG4gICAgICByZXR1cm4gMS4wIC0gMy4wICogYUEyICsgMy4wICogYUExO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIEIoYUExLCBhQTIpIHtcbiAgICAgIHJldHVybiAzLjAgKiBhQTIgLSA2LjAgKiBhQTE7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gQyhhQTEpIHtcbiAgICAgIHJldHVybiAzLjAgKiBhQTE7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY2FsY0JlemllcihhVCwgYUExLCBhQTIpIHtcbiAgICAgIHJldHVybiAoKEEoYUExLCBhQTIpICogYVQgKyBCKGFBMSwgYUEyKSkgKiBhVCArIEMoYUExKSkgKiBhVDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRTbG9wZShhVCwgYUExLCBhQTIpIHtcbiAgICAgIHJldHVybiAzLjAgKiBBKGFBMSwgYUEyKSAqIGFUICogYVQgKyAyLjAgKiBCKGFBMSwgYUEyKSAqIGFUICsgQyhhQTEpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG5ld3RvblJhcGhzb25JdGVyYXRlKGFYLCBhR3Vlc3NUKSB7XG4gICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgTkVXVE9OX0lURVJBVElPTlM7ICsrX2kpIHtcbiAgICAgICAgdmFyIGN1cnJlbnRTbG9wZSA9IGdldFNsb3BlKGFHdWVzc1QsIG1YMSwgbVgyKTtcblxuICAgICAgICBpZiAoY3VycmVudFNsb3BlID09PSAwLjApIHtcbiAgICAgICAgICByZXR1cm4gYUd1ZXNzVDtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBjdXJyZW50WCA9IGNhbGNCZXppZXIoYUd1ZXNzVCwgbVgxLCBtWDIpIC0gYVg7XG4gICAgICAgIGFHdWVzc1QgLT0gY3VycmVudFggLyBjdXJyZW50U2xvcGU7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhR3Vlc3NUO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNhbGNTYW1wbGVWYWx1ZXMoKSB7XG4gICAgICBmb3IgKHZhciBfaTIgPSAwOyBfaTIgPCBrU3BsaW5lVGFibGVTaXplOyArK19pMikge1xuICAgICAgICBtU2FtcGxlVmFsdWVzW19pMl0gPSBjYWxjQmV6aWVyKF9pMiAqIGtTYW1wbGVTdGVwU2l6ZSwgbVgxLCBtWDIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGJpbmFyeVN1YmRpdmlkZShhWCwgYUEsIGFCKSB7XG4gICAgICB2YXIgY3VycmVudFgsXG4gICAgICAgICAgY3VycmVudFQsXG4gICAgICAgICAgaSA9IDA7XG5cbiAgICAgIGRvIHtcbiAgICAgICAgY3VycmVudFQgPSBhQSArIChhQiAtIGFBKSAvIDIuMDtcbiAgICAgICAgY3VycmVudFggPSBjYWxjQmV6aWVyKGN1cnJlbnRULCBtWDEsIG1YMikgLSBhWDtcblxuICAgICAgICBpZiAoY3VycmVudFggPiAwLjApIHtcbiAgICAgICAgICBhQiA9IGN1cnJlbnRUO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGFBID0gY3VycmVudFQ7XG4gICAgICAgIH1cbiAgICAgIH0gd2hpbGUgKE1hdGguYWJzKGN1cnJlbnRYKSA+IFNVQkRJVklTSU9OX1BSRUNJU0lPTiAmJiArK2kgPCBTVUJESVZJU0lPTl9NQVhfSVRFUkFUSU9OUyk7XG5cbiAgICAgIHJldHVybiBjdXJyZW50VDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRURm9yWChhWCkge1xuICAgICAgdmFyIGludGVydmFsU3RhcnQgPSAwLjAsXG4gICAgICAgICAgY3VycmVudFNhbXBsZSA9IDEsXG4gICAgICAgICAgbGFzdFNhbXBsZSA9IGtTcGxpbmVUYWJsZVNpemUgLSAxO1xuXG4gICAgICBmb3IgKDsgY3VycmVudFNhbXBsZSAhPT0gbGFzdFNhbXBsZSAmJiBtU2FtcGxlVmFsdWVzW2N1cnJlbnRTYW1wbGVdIDw9IGFYOyArK2N1cnJlbnRTYW1wbGUpIHtcbiAgICAgICAgaW50ZXJ2YWxTdGFydCArPSBrU2FtcGxlU3RlcFNpemU7XG4gICAgICB9XG5cbiAgICAgIC0tY3VycmVudFNhbXBsZTtcbiAgICAgIHZhciBkaXN0ID0gKGFYIC0gbVNhbXBsZVZhbHVlc1tjdXJyZW50U2FtcGxlXSkgLyAobVNhbXBsZVZhbHVlc1tjdXJyZW50U2FtcGxlICsgMV0gLSBtU2FtcGxlVmFsdWVzW2N1cnJlbnRTYW1wbGVdKSxcbiAgICAgICAgICBndWVzc0ZvclQgPSBpbnRlcnZhbFN0YXJ0ICsgZGlzdCAqIGtTYW1wbGVTdGVwU2l6ZSxcbiAgICAgICAgICBpbml0aWFsU2xvcGUgPSBnZXRTbG9wZShndWVzc0ZvclQsIG1YMSwgbVgyKTtcblxuICAgICAgaWYgKGluaXRpYWxTbG9wZSA+PSBORVdUT05fTUlOX1NMT1BFKSB7XG4gICAgICAgIHJldHVybiBuZXd0b25SYXBoc29uSXRlcmF0ZShhWCwgZ3Vlc3NGb3JUKTtcbiAgICAgIH0gZWxzZSBpZiAoaW5pdGlhbFNsb3BlID09PSAwLjApIHtcbiAgICAgICAgcmV0dXJuIGd1ZXNzRm9yVDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBiaW5hcnlTdWJkaXZpZGUoYVgsIGludGVydmFsU3RhcnQsIGludGVydmFsU3RhcnQgKyBrU2FtcGxlU3RlcFNpemUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBfcHJlY29tcHV0ZWQgPSBmYWxzZTtcblxuICAgIGZ1bmN0aW9uIHByZWNvbXB1dGUoKSB7XG4gICAgICBfcHJlY29tcHV0ZWQgPSB0cnVlO1xuXG4gICAgICBpZiAobVgxICE9PSBtWTEgfHwgbVgyICE9PSBtWTIpIHtcbiAgICAgICAgY2FsY1NhbXBsZVZhbHVlcygpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBmID0gZnVuY3Rpb24gZihhWCkge1xuICAgICAgaWYgKCFfcHJlY29tcHV0ZWQpIHtcbiAgICAgICAgcHJlY29tcHV0ZSgpO1xuICAgICAgfVxuXG4gICAgICBpZiAobVgxID09PSBtWTEgJiYgbVgyID09PSBtWTIpIHtcbiAgICAgICAgcmV0dXJuIGFYO1xuICAgICAgfVxuXG4gICAgICBpZiAoYVggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9XG5cbiAgICAgIGlmIChhWCA9PT0gMSkge1xuICAgICAgICByZXR1cm4gMTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGNhbGNCZXppZXIoZ2V0VEZvclgoYVgpLCBtWTEsIG1ZMik7XG4gICAgfTtcblxuICAgIGYuZ2V0Q29udHJvbFBvaW50cyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBbe1xuICAgICAgICB4OiBtWDEsXG4gICAgICAgIHk6IG1ZMVxuICAgICAgfSwge1xuICAgICAgICB4OiBtWDIsXG4gICAgICAgIHk6IG1ZMlxuICAgICAgfV07XG4gICAgfTtcblxuICAgIHZhciBzdHIgPSBcImdlbmVyYXRlQmV6aWVyKFwiICsgW21YMSwgbVkxLCBtWDIsIG1ZMl0gKyBcIilcIjtcblxuICAgIGYudG9TdHJpbmcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gc3RyO1xuICAgIH07XG5cbiAgICByZXR1cm4gZjtcbiAgfVxuXG4gIC8qISBSdW5nZS1LdXR0YSBzcHJpbmcgcGh5c2ljcyBmdW5jdGlvbiBnZW5lcmF0b3IuIEFkYXB0ZWQgZnJvbSBGcmFtZXIuanMsIGNvcHlyaWdodCBLb2VuIEJvay4gTUlUIExpY2Vuc2U6IGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTUlUX0xpY2Vuc2UgKi9cblxuICAvKiBHaXZlbiBhIHRlbnNpb24sIGZyaWN0aW9uLCBhbmQgZHVyYXRpb24sIGEgc2ltdWxhdGlvbiBhdCA2MEZQUyB3aWxsIGZpcnN0IHJ1biB3aXRob3V0IGEgZGVmaW5lZCBkdXJhdGlvbiBpbiBvcmRlciB0byBjYWxjdWxhdGUgdGhlIGZ1bGwgcGF0aC4gQSBzZWNvbmQgcGFzc1xuICAgICB0aGVuIGFkanVzdHMgdGhlIHRpbWUgZGVsdGEgLS0gdXNpbmcgdGhlIHJlbGF0aW9uIGJldHdlZW4gYWN0dWFsIHRpbWUgYW5kIGR1cmF0aW9uIC0tIHRvIGNhbGN1bGF0ZSB0aGUgcGF0aCBmb3IgdGhlIGR1cmF0aW9uLWNvbnN0cmFpbmVkIGFuaW1hdGlvbi4gKi9cbiAgdmFyIGdlbmVyYXRlU3ByaW5nUks0ID0gZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIHNwcmluZ0FjY2VsZXJhdGlvbkZvclN0YXRlKHN0YXRlKSB7XG4gICAgICByZXR1cm4gLXN0YXRlLnRlbnNpb24gKiBzdGF0ZS54IC0gc3RhdGUuZnJpY3Rpb24gKiBzdGF0ZS52O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHNwcmluZ0V2YWx1YXRlU3RhdGVXaXRoRGVyaXZhdGl2ZShpbml0aWFsU3RhdGUsIGR0LCBkZXJpdmF0aXZlKSB7XG4gICAgICB2YXIgc3RhdGUgPSB7XG4gICAgICAgIHg6IGluaXRpYWxTdGF0ZS54ICsgZGVyaXZhdGl2ZS5keCAqIGR0LFxuICAgICAgICB2OiBpbml0aWFsU3RhdGUudiArIGRlcml2YXRpdmUuZHYgKiBkdCxcbiAgICAgICAgdGVuc2lvbjogaW5pdGlhbFN0YXRlLnRlbnNpb24sXG4gICAgICAgIGZyaWN0aW9uOiBpbml0aWFsU3RhdGUuZnJpY3Rpb25cbiAgICAgIH07XG4gICAgICByZXR1cm4ge1xuICAgICAgICBkeDogc3RhdGUudixcbiAgICAgICAgZHY6IHNwcmluZ0FjY2VsZXJhdGlvbkZvclN0YXRlKHN0YXRlKVxuICAgICAgfTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzcHJpbmdJbnRlZ3JhdGVTdGF0ZShzdGF0ZSwgZHQpIHtcbiAgICAgIHZhciBhID0ge1xuICAgICAgICBkeDogc3RhdGUudixcbiAgICAgICAgZHY6IHNwcmluZ0FjY2VsZXJhdGlvbkZvclN0YXRlKHN0YXRlKVxuICAgICAgfSxcbiAgICAgICAgICBiID0gc3ByaW5nRXZhbHVhdGVTdGF0ZVdpdGhEZXJpdmF0aXZlKHN0YXRlLCBkdCAqIDAuNSwgYSksXG4gICAgICAgICAgYyA9IHNwcmluZ0V2YWx1YXRlU3RhdGVXaXRoRGVyaXZhdGl2ZShzdGF0ZSwgZHQgKiAwLjUsIGIpLFxuICAgICAgICAgIGQgPSBzcHJpbmdFdmFsdWF0ZVN0YXRlV2l0aERlcml2YXRpdmUoc3RhdGUsIGR0LCBjKSxcbiAgICAgICAgICBkeGR0ID0gMS4wIC8gNi4wICogKGEuZHggKyAyLjAgKiAoYi5keCArIGMuZHgpICsgZC5keCksXG4gICAgICAgICAgZHZkdCA9IDEuMCAvIDYuMCAqIChhLmR2ICsgMi4wICogKGIuZHYgKyBjLmR2KSArIGQuZHYpO1xuICAgICAgc3RhdGUueCA9IHN0YXRlLnggKyBkeGR0ICogZHQ7XG4gICAgICBzdGF0ZS52ID0gc3RhdGUudiArIGR2ZHQgKiBkdDtcbiAgICAgIHJldHVybiBzdGF0ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gc3ByaW5nUks0RmFjdG9yeSh0ZW5zaW9uLCBmcmljdGlvbiwgZHVyYXRpb24pIHtcbiAgICAgIHZhciBpbml0U3RhdGUgPSB7XG4gICAgICAgIHg6IC0xLFxuICAgICAgICB2OiAwLFxuICAgICAgICB0ZW5zaW9uOiBudWxsLFxuICAgICAgICBmcmljdGlvbjogbnVsbFxuICAgICAgfSxcbiAgICAgICAgICBwYXRoID0gWzBdLFxuICAgICAgICAgIHRpbWVfbGFwc2VkID0gMCxcbiAgICAgICAgICB0b2xlcmFuY2UgPSAxIC8gMTAwMDAsXG4gICAgICAgICAgRFQgPSAxNiAvIDEwMDAsXG4gICAgICAgICAgaGF2ZV9kdXJhdGlvbixcbiAgICAgICAgICBkdCxcbiAgICAgICAgICBsYXN0X3N0YXRlO1xuICAgICAgdGVuc2lvbiA9IHBhcnNlRmxvYXQodGVuc2lvbikgfHwgNTAwO1xuICAgICAgZnJpY3Rpb24gPSBwYXJzZUZsb2F0KGZyaWN0aW9uKSB8fCAyMDtcbiAgICAgIGR1cmF0aW9uID0gZHVyYXRpb24gfHwgbnVsbDtcbiAgICAgIGluaXRTdGF0ZS50ZW5zaW9uID0gdGVuc2lvbjtcbiAgICAgIGluaXRTdGF0ZS5mcmljdGlvbiA9IGZyaWN0aW9uO1xuICAgICAgaGF2ZV9kdXJhdGlvbiA9IGR1cmF0aW9uICE9PSBudWxsO1xuICAgICAgLyogQ2FsY3VsYXRlIHRoZSBhY3R1YWwgdGltZSBpdCB0YWtlcyBmb3IgdGhpcyBhbmltYXRpb24gdG8gY29tcGxldGUgd2l0aCB0aGUgcHJvdmlkZWQgY29uZGl0aW9ucy4gKi9cblxuICAgICAgaWYgKGhhdmVfZHVyYXRpb24pIHtcbiAgICAgICAgLyogUnVuIHRoZSBzaW11bGF0aW9uIHdpdGhvdXQgYSBkdXJhdGlvbi4gKi9cbiAgICAgICAgdGltZV9sYXBzZWQgPSBzcHJpbmdSSzRGYWN0b3J5KHRlbnNpb24sIGZyaWN0aW9uKTtcbiAgICAgICAgLyogQ29tcHV0ZSB0aGUgYWRqdXN0ZWQgdGltZSBkZWx0YS4gKi9cblxuICAgICAgICBkdCA9IHRpbWVfbGFwc2VkIC8gZHVyYXRpb24gKiBEVDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGR0ID0gRFQ7XG4gICAgICB9XG5cbiAgICAgIGZvciAoOzspIHtcbiAgICAgICAgLyogTmV4dC9zdGVwIGZ1bmN0aW9uIC4qL1xuICAgICAgICBsYXN0X3N0YXRlID0gc3ByaW5nSW50ZWdyYXRlU3RhdGUobGFzdF9zdGF0ZSB8fCBpbml0U3RhdGUsIGR0KTtcbiAgICAgICAgLyogU3RvcmUgdGhlIHBvc2l0aW9uLiAqL1xuXG4gICAgICAgIHBhdGgucHVzaCgxICsgbGFzdF9zdGF0ZS54KTtcbiAgICAgICAgdGltZV9sYXBzZWQgKz0gMTY7XG4gICAgICAgIC8qIElmIHRoZSBjaGFuZ2UgdGhyZXNob2xkIGlzIHJlYWNoZWQsIGJyZWFrLiAqL1xuXG4gICAgICAgIGlmICghKE1hdGguYWJzKGxhc3Rfc3RhdGUueCkgPiB0b2xlcmFuY2UgJiYgTWF0aC5hYnMobGFzdF9zdGF0ZS52KSA+IHRvbGVyYW5jZSkpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLyogSWYgZHVyYXRpb24gaXMgbm90IGRlZmluZWQsIHJldHVybiB0aGUgYWN0dWFsIHRpbWUgcmVxdWlyZWQgZm9yIGNvbXBsZXRpbmcgdGhpcyBhbmltYXRpb24uIE90aGVyd2lzZSwgcmV0dXJuIGEgY2xvc3VyZSB0aGF0IGhvbGRzIHRoZVxuICAgICAgICAgY29tcHV0ZWQgcGF0aCBhbmQgcmV0dXJucyBhIHNuYXBzaG90IG9mIHRoZSBwb3NpdGlvbiBhY2NvcmRpbmcgdG8gYSBnaXZlbiBwZXJjZW50Q29tcGxldGUuICovXG5cblxuICAgICAgcmV0dXJuICFoYXZlX2R1cmF0aW9uID8gdGltZV9sYXBzZWQgOiBmdW5jdGlvbiAocGVyY2VudENvbXBsZXRlKSB7XG4gICAgICAgIHJldHVybiBwYXRoW3BlcmNlbnRDb21wbGV0ZSAqIChwYXRoLmxlbmd0aCAtIDEpIHwgMF07XG4gICAgICB9O1xuICAgIH07XG4gIH0oKTtcblxuICB2YXIgY3ViaWNCZXppZXIgPSBmdW5jdGlvbiBjdWJpY0Jlemllcih0MSwgcDEsIHQyLCBwMikge1xuICAgIHZhciBiZXppZXIgPSBnZW5lcmF0ZUN1YmljQmV6aWVyKHQxLCBwMSwgdDIsIHAyKTtcbiAgICByZXR1cm4gZnVuY3Rpb24gKHN0YXJ0LCBlbmQsIHBlcmNlbnQpIHtcbiAgICAgIHJldHVybiBzdGFydCArIChlbmQgLSBzdGFydCkgKiBiZXppZXIocGVyY2VudCk7XG4gICAgfTtcbiAgfTtcblxuICB2YXIgZWFzaW5ncyA9IHtcbiAgICAnbGluZWFyJzogZnVuY3Rpb24gbGluZWFyKHN0YXJ0LCBlbmQsIHBlcmNlbnQpIHtcbiAgICAgIHJldHVybiBzdGFydCArIChlbmQgLSBzdGFydCkgKiBwZXJjZW50O1xuICAgIH0sXG4gICAgLy8gZGVmYXVsdCBlYXNpbmdzXG4gICAgJ2Vhc2UnOiBjdWJpY0JlemllcigwLjI1LCAwLjEsIDAuMjUsIDEpLFxuICAgICdlYXNlLWluJzogY3ViaWNCZXppZXIoMC40MiwgMCwgMSwgMSksXG4gICAgJ2Vhc2Utb3V0JzogY3ViaWNCZXppZXIoMCwgMCwgMC41OCwgMSksXG4gICAgJ2Vhc2UtaW4tb3V0JzogY3ViaWNCZXppZXIoMC40MiwgMCwgMC41OCwgMSksXG4gICAgLy8gc2luZVxuICAgICdlYXNlLWluLXNpbmUnOiBjdWJpY0JlemllcigwLjQ3LCAwLCAwLjc0NSwgMC43MTUpLFxuICAgICdlYXNlLW91dC1zaW5lJzogY3ViaWNCZXppZXIoMC4zOSwgMC41NzUsIDAuNTY1LCAxKSxcbiAgICAnZWFzZS1pbi1vdXQtc2luZSc6IGN1YmljQmV6aWVyKDAuNDQ1LCAwLjA1LCAwLjU1LCAwLjk1KSxcbiAgICAvLyBxdWFkXG4gICAgJ2Vhc2UtaW4tcXVhZCc6IGN1YmljQmV6aWVyKDAuNTUsIDAuMDg1LCAwLjY4LCAwLjUzKSxcbiAgICAnZWFzZS1vdXQtcXVhZCc6IGN1YmljQmV6aWVyKDAuMjUsIDAuNDYsIDAuNDUsIDAuOTQpLFxuICAgICdlYXNlLWluLW91dC1xdWFkJzogY3ViaWNCZXppZXIoMC40NTUsIDAuMDMsIDAuNTE1LCAwLjk1NSksXG4gICAgLy8gY3ViaWNcbiAgICAnZWFzZS1pbi1jdWJpYyc6IGN1YmljQmV6aWVyKDAuNTUsIDAuMDU1LCAwLjY3NSwgMC4xOSksXG4gICAgJ2Vhc2Utb3V0LWN1YmljJzogY3ViaWNCZXppZXIoMC4yMTUsIDAuNjEsIDAuMzU1LCAxKSxcbiAgICAnZWFzZS1pbi1vdXQtY3ViaWMnOiBjdWJpY0JlemllcigwLjY0NSwgMC4wNDUsIDAuMzU1LCAxKSxcbiAgICAvLyBxdWFydFxuICAgICdlYXNlLWluLXF1YXJ0JzogY3ViaWNCZXppZXIoMC44OTUsIDAuMDMsIDAuNjg1LCAwLjIyKSxcbiAgICAnZWFzZS1vdXQtcXVhcnQnOiBjdWJpY0JlemllcigwLjE2NSwgMC44NCwgMC40NCwgMSksXG4gICAgJ2Vhc2UtaW4tb3V0LXF1YXJ0JzogY3ViaWNCZXppZXIoMC43NywgMCwgMC4xNzUsIDEpLFxuICAgIC8vIHF1aW50XG4gICAgJ2Vhc2UtaW4tcXVpbnQnOiBjdWJpY0JlemllcigwLjc1NSwgMC4wNSwgMC44NTUsIDAuMDYpLFxuICAgICdlYXNlLW91dC1xdWludCc6IGN1YmljQmV6aWVyKDAuMjMsIDEsIDAuMzIsIDEpLFxuICAgICdlYXNlLWluLW91dC1xdWludCc6IGN1YmljQmV6aWVyKDAuODYsIDAsIDAuMDcsIDEpLFxuICAgIC8vIGV4cG9cbiAgICAnZWFzZS1pbi1leHBvJzogY3ViaWNCZXppZXIoMC45NSwgMC4wNSwgMC43OTUsIDAuMDM1KSxcbiAgICAnZWFzZS1vdXQtZXhwbyc6IGN1YmljQmV6aWVyKDAuMTksIDEsIDAuMjIsIDEpLFxuICAgICdlYXNlLWluLW91dC1leHBvJzogY3ViaWNCZXppZXIoMSwgMCwgMCwgMSksXG4gICAgLy8gY2lyY1xuICAgICdlYXNlLWluLWNpcmMnOiBjdWJpY0JlemllcigwLjYsIDAuMDQsIDAuOTgsIDAuMzM1KSxcbiAgICAnZWFzZS1vdXQtY2lyYyc6IGN1YmljQmV6aWVyKDAuMDc1LCAwLjgyLCAwLjE2NSwgMSksXG4gICAgJ2Vhc2UtaW4tb3V0LWNpcmMnOiBjdWJpY0JlemllcigwLjc4NSwgMC4xMzUsIDAuMTUsIDAuODYpLFxuICAgIC8vIHVzZXIgcGFyYW0gZWFzaW5ncy4uLlxuICAgICdzcHJpbmcnOiBmdW5jdGlvbiBzcHJpbmcodGVuc2lvbiwgZnJpY3Rpb24sIGR1cmF0aW9uKSB7XG4gICAgICBpZiAoZHVyYXRpb24gPT09IDApIHtcbiAgICAgICAgLy8gY2FuJ3QgZ2V0IGEgc3ByaW5nIHcvIGR1cmF0aW9uIDBcbiAgICAgICAgcmV0dXJuIGVhc2luZ3MubGluZWFyOyAvLyBkdXJhdGlvbiAwID0+IGp1bXAgdG8gZW5kIHNvIGltcGwgZG9lc24ndCBtYXR0ZXJcbiAgICAgIH1cblxuICAgICAgdmFyIHNwcmluZyA9IGdlbmVyYXRlU3ByaW5nUks0KHRlbnNpb24sIGZyaWN0aW9uLCBkdXJhdGlvbik7XG4gICAgICByZXR1cm4gZnVuY3Rpb24gKHN0YXJ0LCBlbmQsIHBlcmNlbnQpIHtcbiAgICAgICAgcmV0dXJuIHN0YXJ0ICsgKGVuZCAtIHN0YXJ0KSAqIHNwcmluZyhwZXJjZW50KTtcbiAgICAgIH07XG4gICAgfSxcbiAgICAnY3ViaWMtYmV6aWVyJzogY3ViaWNCZXppZXJcbiAgfTtcblxuICBmdW5jdGlvbiBnZXRFYXNlZFZhbHVlKHR5cGUsIHN0YXJ0LCBlbmQsIHBlcmNlbnQsIGVhc2luZ0ZuKSB7XG4gICAgaWYgKHBlcmNlbnQgPT09IDEpIHtcbiAgICAgIHJldHVybiBlbmQ7XG4gICAgfVxuXG4gICAgaWYgKHN0YXJ0ID09PSBlbmQpIHtcbiAgICAgIHJldHVybiBlbmQ7XG4gICAgfVxuXG4gICAgdmFyIHZhbCA9IGVhc2luZ0ZuKHN0YXJ0LCBlbmQsIHBlcmNlbnQpO1xuXG4gICAgaWYgKHR5cGUgPT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHZhbDtcbiAgICB9XG5cbiAgICBpZiAodHlwZS5yb3VuZFZhbHVlIHx8IHR5cGUuY29sb3IpIHtcbiAgICAgIHZhbCA9IE1hdGgucm91bmQodmFsKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZS5taW4gIT09IHVuZGVmaW5lZCkge1xuICAgICAgdmFsID0gTWF0aC5tYXgodmFsLCB0eXBlLm1pbik7XG4gICAgfVxuXG4gICAgaWYgKHR5cGUubWF4ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHZhbCA9IE1hdGgubWluKHZhbCwgdHlwZS5tYXgpO1xuICAgIH1cblxuICAgIHJldHVybiB2YWw7XG4gIH1cblxuICBmdW5jdGlvbiBnZXRWYWx1ZShwcm9wLCBzcGVjKSB7XG4gICAgaWYgKHByb3AucGZWYWx1ZSAhPSBudWxsIHx8IHByb3AudmFsdWUgIT0gbnVsbCkge1xuICAgICAgaWYgKHByb3AucGZWYWx1ZSAhPSBudWxsICYmIChzcGVjID09IG51bGwgfHwgc3BlYy50eXBlLnVuaXRzICE9PSAnJScpKSB7XG4gICAgICAgIHJldHVybiBwcm9wLnBmVmFsdWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gcHJvcC52YWx1ZTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHByb3A7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gZWFzZShzdGFydFByb3AsIGVuZFByb3AsIHBlcmNlbnQsIGVhc2luZ0ZuLCBwcm9wU3BlYykge1xuICAgIHZhciB0eXBlID0gcHJvcFNwZWMgIT0gbnVsbCA/IHByb3BTcGVjLnR5cGUgOiBudWxsO1xuXG4gICAgaWYgKHBlcmNlbnQgPCAwKSB7XG4gICAgICBwZXJjZW50ID0gMDtcbiAgICB9IGVsc2UgaWYgKHBlcmNlbnQgPiAxKSB7XG4gICAgICBwZXJjZW50ID0gMTtcbiAgICB9XG5cbiAgICB2YXIgc3RhcnQgPSBnZXRWYWx1ZShzdGFydFByb3AsIHByb3BTcGVjKTtcbiAgICB2YXIgZW5kID0gZ2V0VmFsdWUoZW5kUHJvcCwgcHJvcFNwZWMpO1xuXG4gICAgaWYgKG51bWJlciQxKHN0YXJ0KSAmJiBudW1iZXIkMShlbmQpKSB7XG4gICAgICByZXR1cm4gZ2V0RWFzZWRWYWx1ZSh0eXBlLCBzdGFydCwgZW5kLCBwZXJjZW50LCBlYXNpbmdGbik7XG4gICAgfSBlbHNlIGlmIChhcnJheShzdGFydCkgJiYgYXJyYXkoZW5kKSkge1xuICAgICAgdmFyIGVhc2VkQXJyID0gW107XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZW5kLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBzaSA9IHN0YXJ0W2ldO1xuICAgICAgICB2YXIgZWkgPSBlbmRbaV07XG5cbiAgICAgICAgaWYgKHNpICE9IG51bGwgJiYgZWkgIT0gbnVsbCkge1xuICAgICAgICAgIHZhciB2YWwgPSBnZXRFYXNlZFZhbHVlKHR5cGUsIHNpLCBlaSwgcGVyY2VudCwgZWFzaW5nRm4pO1xuICAgICAgICAgIGVhc2VkQXJyLnB1c2godmFsKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBlYXNlZEFyci5wdXNoKGVpKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gZWFzZWRBcnI7XG4gICAgfVxuXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHN0ZXAkMShzZWxmLCBhbmksIG5vdywgaXNDb3JlKSB7XG4gICAgdmFyIGlzRWxlcyA9ICFpc0NvcmU7XG4gICAgdmFyIF9wID0gc2VsZi5fcHJpdmF0ZTtcbiAgICB2YXIgYW5pX3AgPSBhbmkuX3ByaXZhdGU7XG4gICAgdmFyIHBFYXNpbmcgPSBhbmlfcC5lYXNpbmc7XG4gICAgdmFyIHN0YXJ0VGltZSA9IGFuaV9wLnN0YXJ0VGltZTtcbiAgICB2YXIgY3kgPSBpc0NvcmUgPyBzZWxmIDogc2VsZi5jeSgpO1xuICAgIHZhciBzdHlsZSA9IGN5LnN0eWxlKCk7XG5cbiAgICBpZiAoIWFuaV9wLmVhc2luZ0ltcGwpIHtcbiAgICAgIGlmIChwRWFzaW5nID09IG51bGwpIHtcbiAgICAgICAgLy8gdXNlIGRlZmF1bHRcbiAgICAgICAgYW5pX3AuZWFzaW5nSW1wbCA9IGVhc2luZ3NbJ2xpbmVhciddO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gdGhlbiBkZWZpbmUgdy8gbmFtZVxuICAgICAgICB2YXIgZWFzaW5nVmFscztcblxuICAgICAgICBpZiAoc3RyaW5nKHBFYXNpbmcpKSB7XG4gICAgICAgICAgdmFyIGVhc2luZ1Byb3AgPSBzdHlsZS5wYXJzZSgndHJhbnNpdGlvbi10aW1pbmctZnVuY3Rpb24nLCBwRWFzaW5nKTtcbiAgICAgICAgICBlYXNpbmdWYWxzID0gZWFzaW5nUHJvcC52YWx1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyB0aGVuIGFzc3VtZSBwcmVwYXJzZWQgYXJyYXlcbiAgICAgICAgICBlYXNpbmdWYWxzID0gcEVhc2luZztcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBuYW1lLCBhcmdzO1xuXG4gICAgICAgIGlmIChzdHJpbmcoZWFzaW5nVmFscykpIHtcbiAgICAgICAgICBuYW1lID0gZWFzaW5nVmFscztcbiAgICAgICAgICBhcmdzID0gW107XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbmFtZSA9IGVhc2luZ1ZhbHNbMV07XG4gICAgICAgICAgYXJncyA9IGVhc2luZ1ZhbHMuc2xpY2UoMikubWFwKGZ1bmN0aW9uIChuKSB7XG4gICAgICAgICAgICByZXR1cm4gK247XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYXJncy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgLy8gY3JlYXRlIHdpdGggYXJnc1xuICAgICAgICAgIGlmIChuYW1lID09PSAnc3ByaW5nJykge1xuICAgICAgICAgICAgYXJncy5wdXNoKGFuaV9wLmR1cmF0aW9uKTsgLy8gbmVlZCBkdXJhdGlvbiB0byBnZW5lcmF0ZSBzcHJpbmdcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBhbmlfcC5lYXNpbmdJbXBsID0gZWFzaW5nc1tuYW1lXS5hcHBseShudWxsLCBhcmdzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBzdGF0aWMgaW1wbCBieSBuYW1lXG4gICAgICAgICAgYW5pX3AuZWFzaW5nSW1wbCA9IGVhc2luZ3NbbmFtZV07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgZWFzaW5nID0gYW5pX3AuZWFzaW5nSW1wbDtcbiAgICB2YXIgcGVyY2VudDtcblxuICAgIGlmIChhbmlfcC5kdXJhdGlvbiA9PT0gMCkge1xuICAgICAgcGVyY2VudCA9IDE7XG4gICAgfSBlbHNlIHtcbiAgICAgIHBlcmNlbnQgPSAobm93IC0gc3RhcnRUaW1lKSAvIGFuaV9wLmR1cmF0aW9uO1xuICAgIH1cblxuICAgIGlmIChhbmlfcC5hcHBseWluZykge1xuICAgICAgcGVyY2VudCA9IGFuaV9wLnByb2dyZXNzO1xuICAgIH1cblxuICAgIGlmIChwZXJjZW50IDwgMCkge1xuICAgICAgcGVyY2VudCA9IDA7XG4gICAgfSBlbHNlIGlmIChwZXJjZW50ID4gMSkge1xuICAgICAgcGVyY2VudCA9IDE7XG4gICAgfVxuXG4gICAgaWYgKGFuaV9wLmRlbGF5ID09IG51bGwpIHtcbiAgICAgIC8vIHRoZW4gdXBkYXRlXG4gICAgICB2YXIgc3RhcnRQb3MgPSBhbmlfcC5zdGFydFBvc2l0aW9uO1xuICAgICAgdmFyIGVuZFBvcyA9IGFuaV9wLnBvc2l0aW9uO1xuXG4gICAgICBpZiAoZW5kUG9zICYmIGlzRWxlcyAmJiAhc2VsZi5sb2NrZWQoKSkge1xuICAgICAgICB2YXIgbmV3UG9zID0ge307XG5cbiAgICAgICAgaWYgKHZhbGlkKHN0YXJ0UG9zLngsIGVuZFBvcy54KSkge1xuICAgICAgICAgIG5ld1Bvcy54ID0gZWFzZShzdGFydFBvcy54LCBlbmRQb3MueCwgcGVyY2VudCwgZWFzaW5nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh2YWxpZChzdGFydFBvcy55LCBlbmRQb3MueSkpIHtcbiAgICAgICAgICBuZXdQb3MueSA9IGVhc2Uoc3RhcnRQb3MueSwgZW5kUG9zLnksIHBlcmNlbnQsIGVhc2luZyk7XG4gICAgICAgIH1cblxuICAgICAgICBzZWxmLnBvc2l0aW9uKG5ld1Bvcyk7XG4gICAgICB9XG5cbiAgICAgIHZhciBzdGFydFBhbiA9IGFuaV9wLnN0YXJ0UGFuO1xuICAgICAgdmFyIGVuZFBhbiA9IGFuaV9wLnBhbjtcbiAgICAgIHZhciBwYW4gPSBfcC5wYW47XG4gICAgICB2YXIgYW5pbWF0aW5nUGFuID0gZW5kUGFuICE9IG51bGwgJiYgaXNDb3JlO1xuXG4gICAgICBpZiAoYW5pbWF0aW5nUGFuKSB7XG4gICAgICAgIGlmICh2YWxpZChzdGFydFBhbi54LCBlbmRQYW4ueCkpIHtcbiAgICAgICAgICBwYW4ueCA9IGVhc2Uoc3RhcnRQYW4ueCwgZW5kUGFuLngsIHBlcmNlbnQsIGVhc2luZyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodmFsaWQoc3RhcnRQYW4ueSwgZW5kUGFuLnkpKSB7XG4gICAgICAgICAgcGFuLnkgPSBlYXNlKHN0YXJ0UGFuLnksIGVuZFBhbi55LCBwZXJjZW50LCBlYXNpbmcpO1xuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5lbWl0KCdwYW4nKTtcbiAgICAgIH1cblxuICAgICAgdmFyIHN0YXJ0Wm9vbSA9IGFuaV9wLnN0YXJ0Wm9vbTtcbiAgICAgIHZhciBlbmRab29tID0gYW5pX3Auem9vbTtcbiAgICAgIHZhciBhbmltYXRpbmdab29tID0gZW5kWm9vbSAhPSBudWxsICYmIGlzQ29yZTtcblxuICAgICAgaWYgKGFuaW1hdGluZ1pvb20pIHtcbiAgICAgICAgaWYgKHZhbGlkKHN0YXJ0Wm9vbSwgZW5kWm9vbSkpIHtcbiAgICAgICAgICBfcC56b29tID0gYm91bmQoX3AubWluWm9vbSwgZWFzZShzdGFydFpvb20sIGVuZFpvb20sIHBlcmNlbnQsIGVhc2luZyksIF9wLm1heFpvb20pO1xuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5lbWl0KCd6b29tJyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChhbmltYXRpbmdQYW4gfHwgYW5pbWF0aW5nWm9vbSkge1xuICAgICAgICBzZWxmLmVtaXQoJ3ZpZXdwb3J0Jyk7XG4gICAgICB9XG5cbiAgICAgIHZhciBwcm9wcyA9IGFuaV9wLnN0eWxlO1xuXG4gICAgICBpZiAocHJvcHMgJiYgcHJvcHMubGVuZ3RoID4gMCAmJiBpc0VsZXMpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBwcm9wID0gcHJvcHNbaV07XG4gICAgICAgICAgdmFyIF9uYW1lID0gcHJvcC5uYW1lO1xuICAgICAgICAgIHZhciBlbmQgPSBwcm9wO1xuICAgICAgICAgIHZhciBzdGFydCA9IGFuaV9wLnN0YXJ0U3R5bGVbX25hbWVdO1xuICAgICAgICAgIHZhciBwcm9wU3BlYyA9IHN0eWxlLnByb3BlcnRpZXNbc3RhcnQubmFtZV07XG4gICAgICAgICAgdmFyIGVhc2VkVmFsID0gZWFzZShzdGFydCwgZW5kLCBwZXJjZW50LCBlYXNpbmcsIHByb3BTcGVjKTtcbiAgICAgICAgICBzdHlsZS5vdmVycmlkZUJ5cGFzcyhzZWxmLCBfbmFtZSwgZWFzZWRWYWwpO1xuICAgICAgICB9IC8vIGZvciBwcm9wc1xuXG5cbiAgICAgICAgc2VsZi5lbWl0KCdzdHlsZScpO1xuICAgICAgfSAvLyBpZlxuXG4gICAgfVxuXG4gICAgYW5pX3AucHJvZ3Jlc3MgPSBwZXJjZW50O1xuICAgIHJldHVybiBwZXJjZW50O1xuICB9XG5cbiAgZnVuY3Rpb24gdmFsaWQoc3RhcnQsIGVuZCkge1xuICAgIGlmIChzdGFydCA9PSBudWxsIHx8IGVuZCA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKG51bWJlciQxKHN0YXJ0KSAmJiBudW1iZXIkMShlbmQpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKHN0YXJ0ICYmIGVuZCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgZnVuY3Rpb24gc3RhcnRBbmltYXRpb24oc2VsZiwgYW5pLCBub3csIGlzQ29yZSkge1xuICAgIHZhciBhbmlfcCA9IGFuaS5fcHJpdmF0ZTtcbiAgICBhbmlfcC5zdGFydGVkID0gdHJ1ZTtcbiAgICBhbmlfcC5zdGFydFRpbWUgPSBub3cgLSBhbmlfcC5wcm9ncmVzcyAqIGFuaV9wLmR1cmF0aW9uO1xuICB9XG5cbiAgZnVuY3Rpb24gc3RlcEFsbChub3csIGN5KSB7XG4gICAgdmFyIGVsZXMgPSBjeS5fcHJpdmF0ZS5hbmlFbGVzO1xuICAgIHZhciBkb25lRWxlcyA9IFtdO1xuXG4gICAgZnVuY3Rpb24gc3RlcE9uZShlbGUsIGlzQ29yZSkge1xuICAgICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgICAgdmFyIGN1cnJlbnQgPSBfcC5hbmltYXRpb24uY3VycmVudDtcbiAgICAgIHZhciBxdWV1ZSA9IF9wLmFuaW1hdGlvbi5xdWV1ZTtcbiAgICAgIHZhciByYW5BbmlzID0gZmFsc2U7IC8vIGlmIG5vdGhpbmcgY3VycmVudGx5IGFuaW1hdGluZywgZ2V0IHNvbWV0aGluZyBmcm9tIHRoZSBxdWV1ZVxuXG4gICAgICBpZiAoY3VycmVudC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgdmFyIG5leHQgPSBxdWV1ZS5zaGlmdCgpO1xuXG4gICAgICAgIGlmIChuZXh0KSB7XG4gICAgICAgICAgY3VycmVudC5wdXNoKG5leHQpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHZhciBjYWxsYmFja3MgPSBmdW5jdGlvbiBjYWxsYmFja3MoX2NhbGxiYWNrcykge1xuICAgICAgICBmb3IgKHZhciBqID0gX2NhbGxiYWNrcy5sZW5ndGggLSAxOyBqID49IDA7IGotLSkge1xuICAgICAgICAgIHZhciBjYiA9IF9jYWxsYmFja3Nbal07XG4gICAgICAgICAgY2IoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIF9jYWxsYmFja3Muc3BsaWNlKDAsIF9jYWxsYmFja3MubGVuZ3RoKTtcbiAgICAgIH07IC8vIHN0ZXAgYW5kIHJlbW92ZSBpZiBkb25lXG5cblxuICAgICAgZm9yICh2YXIgaSA9IGN1cnJlbnQubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgICAgdmFyIGFuaSA9IGN1cnJlbnRbaV07XG4gICAgICAgIHZhciBhbmlfcCA9IGFuaS5fcHJpdmF0ZTtcblxuICAgICAgICBpZiAoYW5pX3Auc3RvcHBlZCkge1xuICAgICAgICAgIGN1cnJlbnQuc3BsaWNlKGksIDEpO1xuICAgICAgICAgIGFuaV9wLmhvb2tlZCA9IGZhbHNlO1xuICAgICAgICAgIGFuaV9wLnBsYXlpbmcgPSBmYWxzZTtcbiAgICAgICAgICBhbmlfcC5zdGFydGVkID0gZmFsc2U7XG4gICAgICAgICAgY2FsbGJhY2tzKGFuaV9wLmZyYW1lcyk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWFuaV9wLnBsYXlpbmcgJiYgIWFuaV9wLmFwcGx5aW5nKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH0gLy8gYW4gYXBwbHkoKSB3aGlsZSBwbGF5aW5nIHNob3VsZG4ndCBkbyBhbnl0aGluZ1xuXG5cbiAgICAgICAgaWYgKGFuaV9wLnBsYXlpbmcgJiYgYW5pX3AuYXBwbHlpbmcpIHtcbiAgICAgICAgICBhbmlfcC5hcHBseWluZyA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFhbmlfcC5zdGFydGVkKSB7XG4gICAgICAgICAgc3RhcnRBbmltYXRpb24oZWxlLCBhbmksIG5vdyk7XG4gICAgICAgIH1cblxuICAgICAgICBzdGVwJDEoZWxlLCBhbmksIG5vdywgaXNDb3JlKTtcblxuICAgICAgICBpZiAoYW5pX3AuYXBwbHlpbmcpIHtcbiAgICAgICAgICBhbmlfcC5hcHBseWluZyA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgY2FsbGJhY2tzKGFuaV9wLmZyYW1lcyk7XG5cbiAgICAgICAgaWYgKGFuaV9wLnN0ZXAgIT0gbnVsbCkge1xuICAgICAgICAgIGFuaV9wLnN0ZXAobm93KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChhbmkuY29tcGxldGVkKCkpIHtcbiAgICAgICAgICBjdXJyZW50LnNwbGljZShpLCAxKTtcbiAgICAgICAgICBhbmlfcC5ob29rZWQgPSBmYWxzZTtcbiAgICAgICAgICBhbmlfcC5wbGF5aW5nID0gZmFsc2U7XG4gICAgICAgICAgYW5pX3Auc3RhcnRlZCA9IGZhbHNlO1xuICAgICAgICAgIGNhbGxiYWNrcyhhbmlfcC5jb21wbGV0ZXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmFuQW5pcyA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIGlmICghaXNDb3JlICYmIGN1cnJlbnQubGVuZ3RoID09PSAwICYmIHF1ZXVlLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBkb25lRWxlcy5wdXNoKGVsZSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiByYW5BbmlzO1xuICAgIH0gLy8gc3RlcEVsZW1lbnRcbiAgICAvLyBoYW5kbGUgYWxsIGVsZXNcblxuXG4gICAgdmFyIHJhbkVsZUFuaSA9IGZhbHNlO1xuXG4gICAgZm9yICh2YXIgZSA9IDA7IGUgPCBlbGVzLmxlbmd0aDsgZSsrKSB7XG4gICAgICB2YXIgZWxlID0gZWxlc1tlXTtcbiAgICAgIHZhciBoYW5kbGVkVGhpc0VsZSA9IHN0ZXBPbmUoZWxlKTtcbiAgICAgIHJhbkVsZUFuaSA9IHJhbkVsZUFuaSB8fCBoYW5kbGVkVGhpc0VsZTtcbiAgICB9IC8vIGVhY2ggZWxlbWVudFxuXG5cbiAgICB2YXIgcmFuQ29yZUFuaSA9IHN0ZXBPbmUoY3ksIHRydWUpOyAvLyBub3RpZnkgcmVuZGVyZXJcblxuICAgIGlmIChyYW5FbGVBbmkgfHwgcmFuQ29yZUFuaSkge1xuICAgICAgaWYgKGVsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBjeS5ub3RpZnkoJ2RyYXcnLCBlbGVzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGN5Lm5vdGlmeSgnZHJhdycpO1xuICAgICAgfVxuICAgIH0gLy8gcmVtb3ZlIGVsZW1lbnRzIGZyb20gbGlzdCBvZiBjdXJyZW50bHkgYW5pbWF0aW5nIGlmIGl0cyBxdWV1ZXMgYXJlIGVtcHR5XG5cblxuICAgIGVsZXMudW5tZXJnZShkb25lRWxlcyk7XG4gICAgY3kuZW1pdCgnc3RlcCcpO1xuICB9IC8vIHN0ZXBBbGxcblxuICB2YXIgY29yZWZuJDggPSB7XG4gICAgLy8gcHVsbCBpbiBhbmltYXRpb24gZnVuY3Rpb25zXG4gICAgYW5pbWF0ZTogZGVmaW5lLmFuaW1hdGUoKSxcbiAgICBhbmltYXRpb246IGRlZmluZS5hbmltYXRpb24oKSxcbiAgICBhbmltYXRlZDogZGVmaW5lLmFuaW1hdGVkKCksXG4gICAgY2xlYXJRdWV1ZTogZGVmaW5lLmNsZWFyUXVldWUoKSxcbiAgICBkZWxheTogZGVmaW5lLmRlbGF5KCksXG4gICAgZGVsYXlBbmltYXRpb246IGRlZmluZS5kZWxheUFuaW1hdGlvbigpLFxuICAgIHN0b3A6IGRlZmluZS5zdG9wKCksXG4gICAgYWRkVG9BbmltYXRpb25Qb29sOiBmdW5jdGlvbiBhZGRUb0FuaW1hdGlvblBvb2woZWxlcykge1xuICAgICAgdmFyIGN5ID0gdGhpcztcblxuICAgICAgaWYgKCFjeS5zdHlsZUVuYWJsZWQoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHNhdmUgY3ljbGVzIHdoZW4gbm8gc3R5bGUgdXNlZFxuXG5cbiAgICAgIGN5Ll9wcml2YXRlLmFuaUVsZXMubWVyZ2UoZWxlcyk7XG4gICAgfSxcbiAgICBzdG9wQW5pbWF0aW9uTG9vcDogZnVuY3Rpb24gc3RvcEFuaW1hdGlvbkxvb3AoKSB7XG4gICAgICB0aGlzLl9wcml2YXRlLmFuaW1hdGlvbnNSdW5uaW5nID0gZmFsc2U7XG4gICAgfSxcbiAgICBzdGFydEFuaW1hdGlvbkxvb3A6IGZ1bmN0aW9uIHN0YXJ0QW5pbWF0aW9uTG9vcCgpIHtcbiAgICAgIHZhciBjeSA9IHRoaXM7XG4gICAgICBjeS5fcHJpdmF0ZS5hbmltYXRpb25zUnVubmluZyA9IHRydWU7XG5cbiAgICAgIGlmICghY3kuc3R5bGVFbmFibGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBzYXZlIGN5Y2xlcyB3aGVuIG5vIHN0eWxlIHVzZWRcbiAgICAgIC8vIE5CIHRoZSBhbmltYXRpb24gbG9vcCB3aWxsIGV4ZWMgaW4gaGVhZGxlc3MgZW52aXJvbm1lbnRzIGlmIHN0eWxlIGVuYWJsZWRcbiAgICAgIC8vIGFuZCBleHBsaWNpdCBjeS5kZXN0cm95KCkgaXMgbmVjZXNzYXJ5IHRvIHN0b3AgdGhlIGxvb3BcblxuXG4gICAgICBmdW5jdGlvbiBoZWFkbGVzc1N0ZXAoKSB7XG4gICAgICAgIGlmICghY3kuX3ByaXZhdGUuYW5pbWF0aW9uc1J1bm5pbmcpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24gYW5pbWF0aW9uU3RlcChub3cpIHtcbiAgICAgICAgICBzdGVwQWxsKG5vdywgY3kpO1xuICAgICAgICAgIGhlYWRsZXNzU3RlcCgpO1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdmFyIHJlbmRlcmVyID0gY3kucmVuZGVyZXIoKTtcblxuICAgICAgaWYgKHJlbmRlcmVyICYmIHJlbmRlcmVyLmJlZm9yZVJlbmRlcikge1xuICAgICAgICAvLyBsZXQgdGhlIHJlbmRlcmVyIHNjaGVkdWxlIGFuaW1hdGlvbnNcbiAgICAgICAgcmVuZGVyZXIuYmVmb3JlUmVuZGVyKGZ1bmN0aW9uIHJlbmRlcmVyQW5pbWF0aW9uU3RlcCh3aWxsRHJhdywgbm93KSB7XG4gICAgICAgICAgc3RlcEFsbChub3csIGN5KTtcbiAgICAgICAgfSwgcmVuZGVyZXIuYmVmb3JlUmVuZGVyUHJpb3JpdGllcy5hbmltYXRpb25zKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIG1hbmFnZSB0aGUgYW5pbWF0aW9uIGxvb3Agb3Vyc2VsdmVzXG4gICAgICAgIGhlYWRsZXNzU3RlcCgpOyAvLyBmaXJzdCBjYWxsXG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIHZhciBlbWl0dGVyT3B0aW9ucyA9IHtcbiAgICBxdWFsaWZpZXJDb21wYXJlOiBmdW5jdGlvbiBxdWFsaWZpZXJDb21wYXJlKHNlbGVjdG9yMSwgc2VsZWN0b3IyKSB7XG4gICAgICBpZiAoc2VsZWN0b3IxID09IG51bGwgfHwgc2VsZWN0b3IyID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHNlbGVjdG9yMSA9PSBudWxsICYmIHNlbGVjdG9yMiA9PSBudWxsO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHNlbGVjdG9yMS5zYW1lVGV4dChzZWxlY3RvcjIpO1xuICAgICAgfVxuICAgIH0sXG4gICAgZXZlbnRNYXRjaGVzOiBmdW5jdGlvbiBldmVudE1hdGNoZXMoY3ksIGxpc3RlbmVyLCBldmVudE9iaikge1xuICAgICAgdmFyIHNlbGVjdG9yID0gbGlzdGVuZXIucXVhbGlmaWVyO1xuXG4gICAgICBpZiAoc2VsZWN0b3IgIT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gY3kgIT09IGV2ZW50T2JqLnRhcmdldCAmJiBlbGVtZW50KGV2ZW50T2JqLnRhcmdldCkgJiYgc2VsZWN0b3IubWF0Y2hlcyhldmVudE9iai50YXJnZXQpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuICAgIGFkZEV2ZW50RmllbGRzOiBmdW5jdGlvbiBhZGRFdmVudEZpZWxkcyhjeSwgZXZ0KSB7XG4gICAgICBldnQuY3kgPSBjeTtcbiAgICAgIGV2dC50YXJnZXQgPSBjeTtcbiAgICB9LFxuICAgIGNhbGxiYWNrQ29udGV4dDogZnVuY3Rpb24gY2FsbGJhY2tDb250ZXh0KGN5LCBsaXN0ZW5lciwgZXZlbnRPYmopIHtcbiAgICAgIHJldHVybiBsaXN0ZW5lci5xdWFsaWZpZXIgIT0gbnVsbCA/IGV2ZW50T2JqLnRhcmdldCA6IGN5O1xuICAgIH1cbiAgfTtcblxuICB2YXIgYXJnU2VsZWN0b3IgPSBmdW5jdGlvbiBhcmdTZWxlY3RvcihhcmcpIHtcbiAgICBpZiAoc3RyaW5nKGFyZykpIHtcbiAgICAgIHJldHVybiBuZXcgU2VsZWN0b3IoYXJnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGFyZztcbiAgICB9XG4gIH07XG5cbiAgdmFyIGVsZXNmbiA9IHtcbiAgICBjcmVhdGVFbWl0dGVyOiBmdW5jdGlvbiBjcmVhdGVFbWl0dGVyKCkge1xuICAgICAgdmFyIF9wID0gdGhpcy5fcHJpdmF0ZTtcblxuICAgICAgaWYgKCFfcC5lbWl0dGVyKSB7XG4gICAgICAgIF9wLmVtaXR0ZXIgPSBuZXcgRW1pdHRlcihlbWl0dGVyT3B0aW9ucywgdGhpcyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgZW1pdHRlcjogZnVuY3Rpb24gZW1pdHRlcigpIHtcbiAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLmVtaXR0ZXI7XG4gICAgfSxcbiAgICBvbjogZnVuY3Rpb24gb24oZXZlbnRzLCBzZWxlY3RvciwgY2FsbGJhY2spIHtcbiAgICAgIHRoaXMuZW1pdHRlcigpLm9uKGV2ZW50cywgYXJnU2VsZWN0b3Ioc2VsZWN0b3IpLCBjYWxsYmFjayk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIHJlbW92ZUxpc3RlbmVyOiBmdW5jdGlvbiByZW1vdmVMaXN0ZW5lcihldmVudHMsIHNlbGVjdG9yLCBjYWxsYmFjaykge1xuICAgICAgdGhpcy5lbWl0dGVyKCkucmVtb3ZlTGlzdGVuZXIoZXZlbnRzLCBhcmdTZWxlY3RvcihzZWxlY3RvciksIGNhbGxiYWNrKTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgcmVtb3ZlQWxsTGlzdGVuZXJzOiBmdW5jdGlvbiByZW1vdmVBbGxMaXN0ZW5lcnMoKSB7XG4gICAgICB0aGlzLmVtaXR0ZXIoKS5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgb25lOiBmdW5jdGlvbiBvbmUoZXZlbnRzLCBzZWxlY3RvciwgY2FsbGJhY2spIHtcbiAgICAgIHRoaXMuZW1pdHRlcigpLm9uZShldmVudHMsIGFyZ1NlbGVjdG9yKHNlbGVjdG9yKSwgY2FsbGJhY2spO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICBvbmNlOiBmdW5jdGlvbiBvbmNlKGV2ZW50cywgc2VsZWN0b3IsIGNhbGxiYWNrKSB7XG4gICAgICB0aGlzLmVtaXR0ZXIoKS5vbmUoZXZlbnRzLCBhcmdTZWxlY3RvcihzZWxlY3RvciksIGNhbGxiYWNrKTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgZW1pdDogZnVuY3Rpb24gZW1pdChldmVudHMsIGV4dHJhUGFyYW1zKSB7XG4gICAgICB0aGlzLmVtaXR0ZXIoKS5lbWl0KGV2ZW50cywgZXh0cmFQYXJhbXMpO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICBlbWl0QW5kTm90aWZ5OiBmdW5jdGlvbiBlbWl0QW5kTm90aWZ5KGV2ZW50LCBlbGVzKSB7XG4gICAgICB0aGlzLmVtaXQoZXZlbnQpO1xuICAgICAgdGhpcy5ub3RpZnkoZXZlbnQsIGVsZXMpO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICB9O1xuICBkZWZpbmUuZXZlbnRBbGlhc2VzT24oZWxlc2ZuKTtcblxuICB2YXIgY29yZWZuJDcgPSB7XG4gICAgcG5nOiBmdW5jdGlvbiBwbmcob3B0aW9ucykge1xuICAgICAgdmFyIHJlbmRlcmVyID0gdGhpcy5fcHJpdmF0ZS5yZW5kZXJlcjtcbiAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgcmV0dXJuIHJlbmRlcmVyLnBuZyhvcHRpb25zKTtcbiAgICB9LFxuICAgIGpwZzogZnVuY3Rpb24ganBnKG9wdGlvbnMpIHtcbiAgICAgIHZhciByZW5kZXJlciA9IHRoaXMuX3ByaXZhdGUucmVuZGVyZXI7XG4gICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgIG9wdGlvbnMuYmcgPSBvcHRpb25zLmJnIHx8ICcjZmZmJztcbiAgICAgIHJldHVybiByZW5kZXJlci5qcGcob3B0aW9ucyk7XG4gICAgfVxuICB9O1xuICBjb3JlZm4kNy5qcGVnID0gY29yZWZuJDcuanBnO1xuXG4gIHZhciBjb3JlZm4kNiA9IHtcbiAgICBsYXlvdXQ6IGZ1bmN0aW9uIGxheW91dChvcHRpb25zKSB7XG4gICAgICB2YXIgY3kgPSB0aGlzO1xuXG4gICAgICBpZiAob3B0aW9ucyA9PSBudWxsKSB7XG4gICAgICAgIGVycm9yKCdMYXlvdXQgb3B0aW9ucyBtdXN0IGJlIHNwZWNpZmllZCB0byBtYWtlIGEgbGF5b3V0Jyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKG9wdGlvbnMubmFtZSA9PSBudWxsKSB7XG4gICAgICAgIGVycm9yKCdBIGBuYW1lYCBtdXN0IGJlIHNwZWNpZmllZCB0byBtYWtlIGEgbGF5b3V0Jyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIG5hbWUgPSBvcHRpb25zLm5hbWU7XG4gICAgICB2YXIgTGF5b3V0ID0gY3kuZXh0ZW5zaW9uKCdsYXlvdXQnLCBuYW1lKTtcblxuICAgICAgaWYgKExheW91dCA9PSBudWxsKSB7XG4gICAgICAgIGVycm9yKCdObyBzdWNoIGxheW91dCBgJyArIG5hbWUgKyAnYCBmb3VuZC4gIERpZCB5b3UgZm9yZ2V0IHRvIGltcG9ydCBpdCBhbmQgYGN5dG9zY2FwZS51c2UoKWAgaXQ/Jyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGVsZXM7XG5cbiAgICAgIGlmIChzdHJpbmcob3B0aW9ucy5lbGVzKSkge1xuICAgICAgICBlbGVzID0gY3kuJChvcHRpb25zLmVsZXMpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWxlcyA9IG9wdGlvbnMuZWxlcyAhPSBudWxsID8gb3B0aW9ucy5lbGVzIDogY3kuJCgpO1xuICAgICAgfVxuXG4gICAgICB2YXIgbGF5b3V0ID0gbmV3IExheW91dChleHRlbmQoe30sIG9wdGlvbnMsIHtcbiAgICAgICAgY3k6IGN5LFxuICAgICAgICBlbGVzOiBlbGVzXG4gICAgICB9KSk7XG4gICAgICByZXR1cm4gbGF5b3V0O1xuICAgIH1cbiAgfTtcbiAgY29yZWZuJDYuY3JlYXRlTGF5b3V0ID0gY29yZWZuJDYubWFrZUxheW91dCA9IGNvcmVmbiQ2LmxheW91dDtcblxuICB2YXIgY29yZWZuJDUgPSB7XG4gICAgbm90aWZ5OiBmdW5jdGlvbiBub3RpZnkoZXZlbnROYW1lLCBldmVudEVsZXMpIHtcbiAgICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG5cbiAgICAgIGlmICh0aGlzLmJhdGNoaW5nKCkpIHtcbiAgICAgICAgX3AuYmF0Y2hOb3RpZmljYXRpb25zID0gX3AuYmF0Y2hOb3RpZmljYXRpb25zIHx8IHt9O1xuICAgICAgICB2YXIgZWxlcyA9IF9wLmJhdGNoTm90aWZpY2F0aW9uc1tldmVudE5hbWVdID0gX3AuYmF0Y2hOb3RpZmljYXRpb25zW2V2ZW50TmFtZV0gfHwgdGhpcy5jb2xsZWN0aW9uKCk7XG5cbiAgICAgICAgaWYgKGV2ZW50RWxlcyAhPSBudWxsKSB7XG4gICAgICAgICAgZWxlcy5tZXJnZShldmVudEVsZXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuOyAvLyBub3RpZmljYXRpb25zIGFyZSBkaXNhYmxlZCBkdXJpbmcgYmF0Y2hpbmdcbiAgICAgIH1cblxuICAgICAgaWYgKCFfcC5ub3RpZmljYXRpb25zRW5hYmxlZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIGV4aXQgb24gZGlzYWJsZWRcblxuXG4gICAgICB2YXIgcmVuZGVyZXIgPSB0aGlzLnJlbmRlcmVyKCk7IC8vIGV4aXQgaWYgZGVzdHJveSgpIGNhbGxlZCBvbiBjb3JlIG9yIHJlbmRlcmVyIGluIGJldHdlZW4gZnJhbWVzICMxNDk5ICMxNTI4XG5cbiAgICAgIGlmICh0aGlzLmRlc3Ryb3llZCgpIHx8ICFyZW5kZXJlcikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHJlbmRlcmVyLm5vdGlmeShldmVudE5hbWUsIGV2ZW50RWxlcyk7XG4gICAgfSxcbiAgICBub3RpZmljYXRpb25zOiBmdW5jdGlvbiBub3RpZmljYXRpb25zKGJvb2wpIHtcbiAgICAgIHZhciBwID0gdGhpcy5fcHJpdmF0ZTtcblxuICAgICAgaWYgKGJvb2wgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gcC5ub3RpZmljYXRpb25zRW5hYmxlZDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHAubm90aWZpY2F0aW9uc0VuYWJsZWQgPSBib29sID8gdHJ1ZSA6IGZhbHNlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIG5vTm90aWZpY2F0aW9uczogZnVuY3Rpb24gbm9Ob3RpZmljYXRpb25zKGNhbGxiYWNrKSB7XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvbnMoZmFsc2UpO1xuICAgICAgY2FsbGJhY2soKTtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9ucyh0cnVlKTtcbiAgICB9LFxuICAgIGJhdGNoaW5nOiBmdW5jdGlvbiBiYXRjaGluZygpIHtcbiAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLmJhdGNoQ291bnQgPiAwO1xuICAgIH0sXG4gICAgc3RhcnRCYXRjaDogZnVuY3Rpb24gc3RhcnRCYXRjaCgpIHtcbiAgICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG5cbiAgICAgIGlmIChfcC5iYXRjaENvdW50ID09IG51bGwpIHtcbiAgICAgICAgX3AuYmF0Y2hDb3VudCA9IDA7XG4gICAgICB9XG5cbiAgICAgIGlmIChfcC5iYXRjaENvdW50ID09PSAwKSB7XG4gICAgICAgIF9wLmJhdGNoU3R5bGVFbGVzID0gdGhpcy5jb2xsZWN0aW9uKCk7XG4gICAgICAgIF9wLmJhdGNoTm90aWZpY2F0aW9ucyA9IHt9O1xuICAgICAgfVxuXG4gICAgICBfcC5iYXRjaENvdW50Kys7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIGVuZEJhdGNoOiBmdW5jdGlvbiBlbmRCYXRjaCgpIHtcbiAgICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG5cbiAgICAgIGlmIChfcC5iYXRjaENvdW50ID09PSAwKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuXG4gICAgICBfcC5iYXRjaENvdW50LS07XG5cbiAgICAgIGlmIChfcC5iYXRjaENvdW50ID09PSAwKSB7XG4gICAgICAgIC8vIHVwZGF0ZSBzdHlsZSBmb3IgZGlydHkgZWxlc1xuICAgICAgICBfcC5iYXRjaFN0eWxlRWxlcy51cGRhdGVTdHlsZSgpO1xuXG4gICAgICAgIHZhciByZW5kZXJlciA9IHRoaXMucmVuZGVyZXIoKTsgLy8gbm90aWZ5IHRoZSByZW5kZXJlciBvZiBxdWV1ZWQgZWxlcyBhbmQgZXZlbnQgdHlwZXNcblxuICAgICAgICBPYmplY3Qua2V5cyhfcC5iYXRjaE5vdGlmaWNhdGlvbnMpLmZvckVhY2goZnVuY3Rpb24gKGV2ZW50TmFtZSkge1xuICAgICAgICAgIHZhciBlbGVzID0gX3AuYmF0Y2hOb3RpZmljYXRpb25zW2V2ZW50TmFtZV07XG5cbiAgICAgICAgICBpZiAoZWxlcy5lbXB0eSgpKSB7XG4gICAgICAgICAgICByZW5kZXJlci5ub3RpZnkoZXZlbnROYW1lKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVuZGVyZXIubm90aWZ5KGV2ZW50TmFtZSwgZWxlcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICBiYXRjaDogZnVuY3Rpb24gYmF0Y2goY2FsbGJhY2spIHtcbiAgICAgIHRoaXMuc3RhcnRCYXRjaCgpO1xuICAgICAgY2FsbGJhY2soKTtcbiAgICAgIHRoaXMuZW5kQmF0Y2goKTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgLy8gZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XG4gICAgYmF0Y2hEYXRhOiBmdW5jdGlvbiBiYXRjaERhdGEobWFwKSB7XG4gICAgICB2YXIgY3kgPSB0aGlzO1xuICAgICAgcmV0dXJuIHRoaXMuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgaWRzID0gT2JqZWN0LmtleXMobWFwKTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGlkcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBpZCA9IGlkc1tpXTtcbiAgICAgICAgICB2YXIgZGF0YSA9IG1hcFtpZF07XG4gICAgICAgICAgdmFyIGVsZSA9IGN5LmdldEVsZW1lbnRCeUlkKGlkKTtcbiAgICAgICAgICBlbGUuZGF0YShkYXRhKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9O1xuXG4gIHZhciByZW5kZXJlckRlZmF1bHRzID0gZGVmYXVsdHMkZyh7XG4gICAgaGlkZUVkZ2VzT25WaWV3cG9ydDogZmFsc2UsXG4gICAgdGV4dHVyZU9uVmlld3BvcnQ6IGZhbHNlLFxuICAgIG1vdGlvbkJsdXI6IGZhbHNlLFxuICAgIG1vdGlvbkJsdXJPcGFjaXR5OiAwLjA1LFxuICAgIHBpeGVsUmF0aW86IHVuZGVmaW5lZCxcbiAgICBkZXNrdG9wVGFwVGhyZXNob2xkOiA0LFxuICAgIHRvdWNoVGFwVGhyZXNob2xkOiA4LFxuICAgIHdoZWVsU2Vuc2l0aXZpdHk6IDEsXG4gICAgZGVidWc6IGZhbHNlLFxuICAgIHNob3dGcHM6IGZhbHNlXG4gIH0pO1xuICB2YXIgY29yZWZuJDQgPSB7XG4gICAgcmVuZGVyVG86IGZ1bmN0aW9uIHJlbmRlclRvKGNvbnRleHQsIHpvb20sIHBhbiwgcHhSYXRpbykge1xuICAgICAgdmFyIHIgPSB0aGlzLl9wcml2YXRlLnJlbmRlcmVyO1xuICAgICAgci5yZW5kZXJUbyhjb250ZXh0LCB6b29tLCBwYW4sIHB4UmF0aW8pO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICByZW5kZXJlcjogZnVuY3Rpb24gcmVuZGVyZXIoKSB7XG4gICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5yZW5kZXJlcjtcbiAgICB9LFxuICAgIGZvcmNlUmVuZGVyOiBmdW5jdGlvbiBmb3JjZVJlbmRlcigpIHtcbiAgICAgIHRoaXMubm90aWZ5KCdkcmF3Jyk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIHJlc2l6ZTogZnVuY3Rpb24gcmVzaXplKCkge1xuICAgICAgdGhpcy5pbnZhbGlkYXRlU2l6ZSgpO1xuICAgICAgdGhpcy5lbWl0QW5kTm90aWZ5KCdyZXNpemUnKTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgaW5pdFJlbmRlcmVyOiBmdW5jdGlvbiBpbml0UmVuZGVyZXIob3B0aW9ucykge1xuICAgICAgdmFyIGN5ID0gdGhpcztcbiAgICAgIHZhciBSZW5kZXJlclByb3RvID0gY3kuZXh0ZW5zaW9uKCdyZW5kZXJlcicsIG9wdGlvbnMubmFtZSk7XG5cbiAgICAgIGlmIChSZW5kZXJlclByb3RvID09IG51bGwpIHtcbiAgICAgICAgZXJyb3IoXCJDYW4gbm90IGluaXRpYWxpc2U6IE5vIHN1Y2ggcmVuZGVyZXIgYFwiLmNvbmNhdChvcHRpb25zLm5hbWUsIFwiYCBmb3VuZC4gRGlkIHlvdSBmb3JnZXQgdG8gaW1wb3J0IGl0IGFuZCBgY3l0b3NjYXBlLnVzZSgpYCBpdD9cIikpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChvcHRpb25zLndoZWVsU2Vuc2l0aXZpdHkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB3YXJuKFwiWW91IGhhdmUgc2V0IGEgY3VzdG9tIHdoZWVsIHNlbnNpdGl2aXR5LiAgVGhpcyB3aWxsIG1ha2UgeW91ciBhcHAgem9vbSB1bm5hdHVyYWxseSB3aGVuIHVzaW5nIG1haW5zdHJlYW0gbWljZS4gIFlvdSBzaG91bGQgY2hhbmdlIHRoaXMgdmFsdWUgZnJvbSB0aGUgZGVmYXVsdCBvbmx5IGlmIHlvdSBjYW4gZ3VhcmFudGVlIHRoYXQgYWxsIHlvdXIgdXNlcnMgd2lsbCB1c2UgdGhlIHNhbWUgaGFyZHdhcmUgYW5kIE9TIGNvbmZpZ3VyYXRpb24gYXMgeW91ciBjdXJyZW50IG1hY2hpbmUuXCIpO1xuICAgICAgfVxuXG4gICAgICB2YXIgck9wdHMgPSByZW5kZXJlckRlZmF1bHRzKG9wdGlvbnMpO1xuICAgICAgck9wdHMuY3kgPSBjeTtcbiAgICAgIGN5Ll9wcml2YXRlLnJlbmRlcmVyID0gbmV3IFJlbmRlcmVyUHJvdG8ock9wdHMpO1xuICAgICAgdGhpcy5ub3RpZnkoJ2luaXQnKTtcbiAgICB9LFxuICAgIGRlc3Ryb3lSZW5kZXJlcjogZnVuY3Rpb24gZGVzdHJveVJlbmRlcmVyKCkge1xuICAgICAgdmFyIGN5ID0gdGhpcztcbiAgICAgIGN5Lm5vdGlmeSgnZGVzdHJveScpOyAvLyBkZXN0cm95IHRoZSByZW5kZXJlclxuXG4gICAgICB2YXIgZG9tRWxlID0gY3kuY29udGFpbmVyKCk7XG5cbiAgICAgIGlmIChkb21FbGUpIHtcbiAgICAgICAgZG9tRWxlLl9jeXJlZyA9IG51bGw7XG5cbiAgICAgICAgd2hpbGUgKGRvbUVsZS5jaGlsZE5vZGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBkb21FbGUucmVtb3ZlQ2hpbGQoZG9tRWxlLmNoaWxkTm9kZXNbMF0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGN5Ll9wcml2YXRlLnJlbmRlcmVyID0gbnVsbDsgLy8gdG8gYmUgZXh0cmEgc2FmZSwgcmVtb3ZlIHRoZSByZWZcblxuICAgICAgY3kubXV0YWJsZUVsZW1lbnRzKCkuZm9yRWFjaChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICAgICAgX3AucnNjcmF0Y2ggPSB7fTtcbiAgICAgICAgX3AucnN0eWxlID0ge307XG4gICAgICAgIF9wLmFuaW1hdGlvbi5jdXJyZW50ID0gW107XG4gICAgICAgIF9wLmFuaW1hdGlvbi5xdWV1ZSA9IFtdO1xuICAgICAgfSk7XG4gICAgfSxcbiAgICBvblJlbmRlcjogZnVuY3Rpb24gb25SZW5kZXIoZm4pIHtcbiAgICAgIHJldHVybiB0aGlzLm9uKCdyZW5kZXInLCBmbik7XG4gICAgfSxcbiAgICBvZmZSZW5kZXI6IGZ1bmN0aW9uIG9mZlJlbmRlcihmbikge1xuICAgICAgcmV0dXJuIHRoaXMub2ZmKCdyZW5kZXInLCBmbik7XG4gICAgfVxuICB9O1xuICBjb3JlZm4kNC5pbnZhbGlkYXRlRGltZW5zaW9ucyA9IGNvcmVmbiQ0LnJlc2l6ZTtcblxuICB2YXIgY29yZWZuJDMgPSB7XG4gICAgLy8gZ2V0IGEgY29sbGVjdGlvblxuICAgIC8vIC0gZW1wdHkgY29sbGVjdGlvbiBvbiBubyBhcmdzXG4gICAgLy8gLSBjb2xsZWN0aW9uIG9mIGVsZW1lbnRzIGluIHRoZSBncmFwaCBvbiBzZWxlY3RvciBhcmdcbiAgICAvLyAtIGd1YXJhbnRlZSBhIHJldHVybmVkIGNvbGxlY3Rpb24gd2hlbiBlbGVtZW50cyBvciBjb2xsZWN0aW9uIHNwZWNpZmllZFxuICAgIGNvbGxlY3Rpb246IGZ1bmN0aW9uIGNvbGxlY3Rpb24oZWxlcywgb3B0cykge1xuICAgICAgaWYgKHN0cmluZyhlbGVzKSkge1xuICAgICAgICByZXR1cm4gdGhpcy4kKGVsZXMpO1xuICAgICAgfSBlbHNlIGlmIChlbGVtZW50T3JDb2xsZWN0aW9uKGVsZXMpKSB7XG4gICAgICAgIHJldHVybiBlbGVzLmNvbGxlY3Rpb24oKTtcbiAgICAgIH0gZWxzZSBpZiAoYXJyYXkoZWxlcykpIHtcbiAgICAgICAgaWYgKCFvcHRzKSB7XG4gICAgICAgICAgb3B0cyA9IHt9O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyBDb2xsZWN0aW9uKHRoaXMsIGVsZXMsIG9wdHMudW5pcXVlLCBvcHRzLnJlbW92ZWQpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gbmV3IENvbGxlY3Rpb24odGhpcyk7XG4gICAgfSxcbiAgICBub2RlczogZnVuY3Rpb24gbm9kZXMoc2VsZWN0b3IpIHtcbiAgICAgIHZhciBub2RlcyA9IHRoaXMuJChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgIHJldHVybiBlbGUuaXNOb2RlKCk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHNlbGVjdG9yKSB7XG4gICAgICAgIHJldHVybiBub2Rlcy5maWx0ZXIoc2VsZWN0b3IpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gbm9kZXM7XG4gICAgfSxcbiAgICBlZGdlczogZnVuY3Rpb24gZWRnZXMoc2VsZWN0b3IpIHtcbiAgICAgIHZhciBlZGdlcyA9IHRoaXMuJChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgIHJldHVybiBlbGUuaXNFZGdlKCk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHNlbGVjdG9yKSB7XG4gICAgICAgIHJldHVybiBlZGdlcy5maWx0ZXIoc2VsZWN0b3IpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZWRnZXM7XG4gICAgfSxcbiAgICAvLyBzZWFyY2ggdGhlIGdyYXBoIGxpa2UgalF1ZXJ5XG4gICAgJDogZnVuY3Rpb24gJChzZWxlY3Rvcikge1xuICAgICAgdmFyIGVsZXMgPSB0aGlzLl9wcml2YXRlLmVsZW1lbnRzO1xuXG4gICAgICBpZiAoc2VsZWN0b3IpIHtcbiAgICAgICAgcmV0dXJuIGVsZXMuZmlsdGVyKHNlbGVjdG9yKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBlbGVzLnNwYXduU2VsZigpO1xuICAgICAgfVxuICAgIH0sXG4gICAgbXV0YWJsZUVsZW1lbnRzOiBmdW5jdGlvbiBtdXRhYmxlRWxlbWVudHMoKSB7XG4gICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5lbGVtZW50cztcbiAgICB9XG4gIH07IC8vIGFsaWFzZXNcblxuICBjb3JlZm4kMy5lbGVtZW50cyA9IGNvcmVmbiQzLmZpbHRlciA9IGNvcmVmbiQzLiQ7XG5cbiAgdmFyIHN0eWZuJDggPSB7fTsgLy8ga2V5cyBmb3Igc3R5bGUgYmxvY2tzLCBlLmcuIHR0ZmZ0dFxuXG4gIHZhciBUUlVFID0gJ3QnO1xuICB2YXIgRkFMU0UgPSAnZic7IC8vIChwb3RlbnRpYWxseSBleHBlbnNpdmUgY2FsY3VsYXRpb24pXG4gIC8vIGFwcGx5IHRoZSBzdHlsZSB0byB0aGUgZWxlbWVudCBiYXNlZCBvblxuICAvLyAtIGl0cyBieXBhc3NcbiAgLy8gLSB3aGF0IHNlbGVjdG9ycyBtYXRjaCBpdFxuXG4gIHN0eWZuJDguYXBwbHkgPSBmdW5jdGlvbiAoZWxlcykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgX3AgPSBzZWxmLl9wcml2YXRlO1xuICAgIHZhciBjeSA9IF9wLmN5O1xuICAgIHZhciB1cGRhdGVkRWxlcyA9IGN5LmNvbGxlY3Rpb24oKTtcblxuICAgIGZvciAodmFyIGllID0gMDsgaWUgPCBlbGVzLmxlbmd0aDsgaWUrKykge1xuICAgICAgdmFyIGVsZSA9IGVsZXNbaWVdO1xuICAgICAgdmFyIGN4dE1ldGEgPSBzZWxmLmdldENvbnRleHRNZXRhKGVsZSk7XG5cbiAgICAgIGlmIChjeHRNZXRhLmVtcHR5KSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICB2YXIgY3h0U3R5bGUgPSBzZWxmLmdldENvbnRleHRTdHlsZShjeHRNZXRhKTtcbiAgICAgIHZhciBhcHAgPSBzZWxmLmFwcGx5Q29udGV4dFN0eWxlKGN4dE1ldGEsIGN4dFN0eWxlLCBlbGUpO1xuXG4gICAgICBpZiAoZWxlLl9wcml2YXRlLmFwcGxpZWRJbml0U3R5bGUpIHtcbiAgICAgICAgc2VsZi51cGRhdGVUcmFuc2l0aW9ucyhlbGUsIGFwcC5kaWZmUHJvcHMpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWxlLl9wcml2YXRlLmFwcGxpZWRJbml0U3R5bGUgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICB2YXIgaGludHNEaWZmID0gc2VsZi51cGRhdGVTdHlsZUhpbnRzKGVsZSk7XG5cbiAgICAgIGlmIChoaW50c0RpZmYpIHtcbiAgICAgICAgdXBkYXRlZEVsZXMucHVzaChlbGUpO1xuICAgICAgfVxuICAgIH0gLy8gZm9yIGVsZW1lbnRzXG5cblxuICAgIHJldHVybiB1cGRhdGVkRWxlcztcbiAgfTtcblxuICBzdHlmbiQ4LmdldFByb3BlcnRpZXNEaWZmID0gZnVuY3Rpb24gKG9sZEN4dEtleSwgbmV3Q3h0S2V5KSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBjYWNoZSA9IHNlbGYuX3ByaXZhdGUucHJvcERpZmZzID0gc2VsZi5fcHJpdmF0ZS5wcm9wRGlmZnMgfHwge307XG4gICAgdmFyIGR1YWxDeHRLZXkgPSBvbGRDeHRLZXkgKyAnLScgKyBuZXdDeHRLZXk7XG4gICAgdmFyIGNhY2hlZFZhbCA9IGNhY2hlW2R1YWxDeHRLZXldO1xuXG4gICAgaWYgKGNhY2hlZFZhbCkge1xuICAgICAgcmV0dXJuIGNhY2hlZFZhbDtcbiAgICB9XG5cbiAgICB2YXIgZGlmZlByb3BzID0gW107XG4gICAgdmFyIGFkZGVkUHJvcCA9IHt9O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzZWxmLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgY3h0ID0gc2VsZltpXTtcbiAgICAgIHZhciBvbGRIYXNDeHQgPSBvbGRDeHRLZXlbaV0gPT09IFRSVUU7XG4gICAgICB2YXIgbmV3SGFzQ3h0ID0gbmV3Q3h0S2V5W2ldID09PSBUUlVFO1xuICAgICAgdmFyIGN4dEhhc0RpZmZlZCA9IG9sZEhhc0N4dCAhPT0gbmV3SGFzQ3h0O1xuICAgICAgdmFyIGN4dEhhc01hcHBlZFByb3BzID0gY3h0Lm1hcHBlZFByb3BlcnRpZXMubGVuZ3RoID4gMDtcblxuICAgICAgaWYgKGN4dEhhc0RpZmZlZCB8fCBuZXdIYXNDeHQgJiYgY3h0SGFzTWFwcGVkUHJvcHMpIHtcbiAgICAgICAgdmFyIHByb3BzID0gdm9pZCAwO1xuXG4gICAgICAgIGlmIChjeHRIYXNEaWZmZWQgJiYgY3h0SGFzTWFwcGVkUHJvcHMpIHtcbiAgICAgICAgICBwcm9wcyA9IGN4dC5wcm9wZXJ0aWVzOyAvLyBzdWZmaWNlcyBiL2MgbWFwcGVkUHJvcGVydGllcyBpcyBhIHN1YnNldCBvZiBwcm9wZXJ0aWVzXG4gICAgICAgIH0gZWxzZSBpZiAoY3h0SGFzRGlmZmVkKSB7XG4gICAgICAgICAgcHJvcHMgPSBjeHQucHJvcGVydGllczsgLy8gbmVlZCB0byBjaGVjayB0aGVtIGFsbFxuICAgICAgICB9IGVsc2UgaWYgKGN4dEhhc01hcHBlZFByb3BzKSB7XG4gICAgICAgICAgcHJvcHMgPSBjeHQubWFwcGVkUHJvcGVydGllczsgLy8gb25seSBuZWVkIHRvIGNoZWNrIG1hcHBlZFxuICAgICAgICB9XG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBwcm9wcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgIHZhciBwcm9wID0gcHJvcHNbal07XG4gICAgICAgICAgdmFyIG5hbWUgPSBwcm9wLm5hbWU7IC8vIGlmIGEgbGF0ZXIgY29udGV4dCBvdmVycmlkZXMgdGhpcyBwcm9wZXJ0eSwgdGhlbiB0aGUgZmFjdCB0aGF0IHRoaXMgY29udGV4dCBoYXMgc3dpdGNoZWQvZGlmZmVkIGRvZXNuJ3QgbWF0dGVyXG4gICAgICAgICAgLy8gKHNlbWkgZXhwZW5zaXZlIGNoZWNrIHNpbmNlIGl0IG1ha2VzIHRoaXMgZnVuY3Rpb24gTyhuXjIpIG9uIGNvbnRleHQgbGVuZ3RoLCBidXQgd29ydGggaXQgc2luY2Ugb3ZlcmFsbCByZXN1bHRcbiAgICAgICAgICAvLyBpcyBjYWNoZWQpXG5cbiAgICAgICAgICB2YXIgbGF0ZXJDeHRPdmVycmlkZXMgPSBmYWxzZTtcblxuICAgICAgICAgIGZvciAodmFyIGsgPSBpICsgMTsgayA8IHNlbGYubGVuZ3RoOyBrKyspIHtcbiAgICAgICAgICAgIHZhciBsYXRlckN4dCA9IHNlbGZba107XG4gICAgICAgICAgICB2YXIgaGFzTGF0ZXJDeHQgPSBuZXdDeHRLZXlba10gPT09IFRSVUU7XG5cbiAgICAgICAgICAgIGlmICghaGFzTGF0ZXJDeHQpIHtcbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9IC8vIGNhbid0IG92ZXJyaWRlIHVubGVzcyB0aGUgY29udGV4dCBpcyBhY3RpdmVcblxuXG4gICAgICAgICAgICBsYXRlckN4dE92ZXJyaWRlcyA9IGxhdGVyQ3h0LnByb3BlcnRpZXNbcHJvcC5uYW1lXSAhPSBudWxsO1xuXG4gICAgICAgICAgICBpZiAobGF0ZXJDeHRPdmVycmlkZXMpIHtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9IC8vIGV4aXQgZWFybHkgYXMgbG9uZyBhcyBvbmUgbGF0ZXIgY29udGV4dCBvdmVycmlkZXNcblxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghYWRkZWRQcm9wW25hbWVdICYmICFsYXRlckN4dE92ZXJyaWRlcykge1xuICAgICAgICAgICAgYWRkZWRQcm9wW25hbWVdID0gdHJ1ZTtcbiAgICAgICAgICAgIGRpZmZQcm9wcy5wdXNoKG5hbWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSAvLyBmb3IgcHJvcHNcblxuICAgICAgfSAvLyBpZlxuXG4gICAgfSAvLyBmb3IgY29udGV4dHNcblxuXG4gICAgY2FjaGVbZHVhbEN4dEtleV0gPSBkaWZmUHJvcHM7XG4gICAgcmV0dXJuIGRpZmZQcm9wcztcbiAgfTtcblxuICBzdHlmbiQ4LmdldENvbnRleHRNZXRhID0gZnVuY3Rpb24gKGVsZSkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgY3h0S2V5ID0gJyc7XG4gICAgdmFyIGRpZmZQcm9wcztcbiAgICB2YXIgcHJldktleSA9IGVsZS5fcHJpdmF0ZS5zdHlsZUN4dEtleSB8fCAnJzsgLy8gZ2V0IHRoZSBjeHQga2V5XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGYubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBjb250ZXh0ID0gc2VsZltpXTtcbiAgICAgIHZhciBjb250ZXh0U2VsZWN0b3JNYXRjaGVzID0gY29udGV4dC5zZWxlY3RvciAmJiBjb250ZXh0LnNlbGVjdG9yLm1hdGNoZXMoZWxlKTsgLy8gTkI6IGNvbnRleHQuc2VsZWN0b3IgbWF5IGJlIG51bGwgZm9yICdjb3JlJ1xuXG4gICAgICBpZiAoY29udGV4dFNlbGVjdG9yTWF0Y2hlcykge1xuICAgICAgICBjeHRLZXkgKz0gVFJVRTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGN4dEtleSArPSBGQUxTRTtcbiAgICAgIH1cbiAgICB9IC8vIGZvciBjb250ZXh0XG5cblxuICAgIGRpZmZQcm9wcyA9IHNlbGYuZ2V0UHJvcGVydGllc0RpZmYocHJldktleSwgY3h0S2V5KTtcbiAgICBlbGUuX3ByaXZhdGUuc3R5bGVDeHRLZXkgPSBjeHRLZXk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGtleTogY3h0S2V5LFxuICAgICAgZGlmZlByb3BOYW1lczogZGlmZlByb3BzLFxuICAgICAgZW1wdHk6IGRpZmZQcm9wcy5sZW5ndGggPT09IDBcbiAgICB9O1xuICB9OyAvLyBnZXRzIGEgY29tcHV0ZWQgZWxlIHN0eWxlIG9iamVjdCBiYXNlZCBvbiBtYXRjaGVkIGNvbnRleHRzXG5cblxuICBzdHlmbiQ4LmdldENvbnRleHRTdHlsZSA9IGZ1bmN0aW9uIChjeHRNZXRhKSB7XG4gICAgdmFyIGN4dEtleSA9IGN4dE1ldGEua2V5O1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgY3h0U3R5bGVzID0gdGhpcy5fcHJpdmF0ZS5jb250ZXh0U3R5bGVzID0gdGhpcy5fcHJpdmF0ZS5jb250ZXh0U3R5bGVzIHx8IHt9OyAvLyBpZiBhbHJlYWR5IGNvbXB1dGVkIHN0eWxlLCByZXR1cm5lZCBjYWNoZWQgY29weVxuXG4gICAgaWYgKGN4dFN0eWxlc1tjeHRLZXldKSB7XG4gICAgICByZXR1cm4gY3h0U3R5bGVzW2N4dEtleV07XG4gICAgfVxuXG4gICAgdmFyIHN0eWxlID0ge1xuICAgICAgX3ByaXZhdGU6IHtcbiAgICAgICAga2V5OiBjeHRLZXlcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzZWxmLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgY3h0ID0gc2VsZltpXTtcbiAgICAgIHZhciBoYXNDeHQgPSBjeHRLZXlbaV0gPT09IFRSVUU7XG5cbiAgICAgIGlmICghaGFzQ3h0KSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGN4dC5wcm9wZXJ0aWVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHZhciBwcm9wID0gY3h0LnByb3BlcnRpZXNbal07XG4gICAgICAgIHN0eWxlW3Byb3AubmFtZV0gPSBwcm9wO1xuICAgICAgfVxuICAgIH1cblxuICAgIGN4dFN0eWxlc1tjeHRLZXldID0gc3R5bGU7XG4gICAgcmV0dXJuIHN0eWxlO1xuICB9O1xuXG4gIHN0eWZuJDguYXBwbHlDb250ZXh0U3R5bGUgPSBmdW5jdGlvbiAoY3h0TWV0YSwgY3h0U3R5bGUsIGVsZSkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgZGlmZlByb3BzID0gY3h0TWV0YS5kaWZmUHJvcE5hbWVzO1xuICAgIHZhciByZXREaWZmUHJvcHMgPSB7fTtcbiAgICB2YXIgdHlwZXMgPSBzZWxmLnR5cGVzO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkaWZmUHJvcHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBkaWZmUHJvcE5hbWUgPSBkaWZmUHJvcHNbaV07XG4gICAgICB2YXIgY3h0UHJvcCA9IGN4dFN0eWxlW2RpZmZQcm9wTmFtZV07XG4gICAgICB2YXIgZWxlUHJvcCA9IGVsZS5wc3R5bGUoZGlmZlByb3BOYW1lKTtcblxuICAgICAgaWYgKCFjeHRQcm9wKSB7XG4gICAgICAgIC8vIG5vIGNvbnRleHQgcHJvcCBtZWFucyBkZWxldGVcbiAgICAgICAgaWYgKCFlbGVQcm9wKSB7XG4gICAgICAgICAgY29udGludWU7IC8vIG5vIGV4aXN0aW5nIHByb3AgbWVhbnMgbm90aGluZyBuZWVkcyB0byBiZSByZW1vdmVkXG4gICAgICAgICAgLy8gbmIgYWZmZWN0cyBpbml0aWFsIGFwcGxpY2F0aW9uIG9uIG1hcHBlZCB2YWx1ZXMgbGlrZSBjb250cm9sLXBvaW50LWRpc3RhbmNlc1xuICAgICAgICB9IGVsc2UgaWYgKGVsZVByb3AuYnlwYXNzKSB7XG4gICAgICAgICAgY3h0UHJvcCA9IHtcbiAgICAgICAgICAgIG5hbWU6IGRpZmZQcm9wTmFtZSxcbiAgICAgICAgICAgIGRlbGV0ZUJ5cGFzc2VkOiB0cnVlXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjeHRQcm9wID0ge1xuICAgICAgICAgICAgbmFtZTogZGlmZlByb3BOYW1lLFxuICAgICAgICAgICAgXCJkZWxldGVcIjogdHJ1ZVxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0gLy8gc2F2ZSBjeWNsZXMgd2hlbiB0aGUgY29udGV4dCBwcm9wIGRvZXNuJ3QgbmVlZCB0byBiZSBhcHBsaWVkXG5cblxuICAgICAgaWYgKGVsZVByb3AgPT09IGN4dFByb3ApIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9IC8vIHNhdmUgY3ljbGVzIHdoZW4gYSBtYXBwZWQgY29udGV4dCBwcm9wIGRvZXNuJ3QgbmVlZCB0byBiZSBhcHBsaWVkXG5cblxuICAgICAgaWYgKGN4dFByb3AubWFwcGVkID09PSB0eXBlcy5mbiAvLyBjb250ZXh0IHByb3AgaXMgZnVuY3Rpb24gbWFwcGVyXG4gICAgICAmJiBlbGVQcm9wICE9IG51bGwgLy8gc29tZSBwcm9wcyBjYW4gYmUgbnVsbCBldmVuIGJ5IGRlZmF1bHQgKGUuZy4gYSBwcm9wIHRoYXQgb3ZlcnJpZGVzIGFub3RoZXIgb25lKVxuICAgICAgJiYgZWxlUHJvcC5tYXBwaW5nICE9IG51bGwgLy8gZWxlIHByb3AgaXMgYSBjb25jcmV0ZSB2YWx1ZSBmcm9tIGZyb20gYSBtYXBwZXJcbiAgICAgICYmIGVsZVByb3AubWFwcGluZy52YWx1ZSA9PT0gY3h0UHJvcC52YWx1ZSAvLyB0aGUgY3VycmVudCBwcm9wIG9uIHRoZSBlbGUgaXMgYSBmbGF0IHByb3AgdmFsdWUgZm9yIHRoZSBmdW5jdGlvbiBtYXBwZXJcbiAgICAgICkge1xuICAgICAgICAvLyBOQiBkb24ndCB3cml0ZSB0byBjeHRQcm9wLCBhcyBpdCdzIHNoYXJlZCBhbW9uZyBlbGVzIChzdG9yZWQgaW4gc3R5bGVzaGVldClcbiAgICAgICAgdmFyIG1hcHBpbmcgPSBlbGVQcm9wLm1hcHBpbmc7IC8vIGNhbiB3cml0ZSB0byBtYXBwaW5nLCBhcyBpdCdzIGEgcGVyLWVsZSBjb3B5XG5cbiAgICAgICAgdmFyIGZuVmFsdWUgPSBtYXBwaW5nLmZuVmFsdWUgPSBjeHRQcm9wLnZhbHVlKGVsZSk7IC8vIHRlbXBvcmFyaWx5IGNhY2hlIHRoZSB2YWx1ZSBpbiBjYXNlIG9mIGEgbWlzc1xuXG4gICAgICAgIGlmIChmblZhbHVlID09PSBtYXBwaW5nLnByZXZGblZhbHVlKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdmFyIHJldERpZmZQcm9wID0gcmV0RGlmZlByb3BzW2RpZmZQcm9wTmFtZV0gPSB7XG4gICAgICAgIHByZXY6IGVsZVByb3BcbiAgICAgIH07XG4gICAgICBzZWxmLmFwcGx5UGFyc2VkUHJvcGVydHkoZWxlLCBjeHRQcm9wKTtcbiAgICAgIHJldERpZmZQcm9wLm5leHQgPSBlbGUucHN0eWxlKGRpZmZQcm9wTmFtZSk7XG5cbiAgICAgIGlmIChyZXREaWZmUHJvcC5uZXh0ICYmIHJldERpZmZQcm9wLm5leHQuYnlwYXNzKSB7XG4gICAgICAgIHJldERpZmZQcm9wLm5leHQgPSByZXREaWZmUHJvcC5uZXh0LmJ5cGFzc2VkO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBkaWZmUHJvcHM6IHJldERpZmZQcm9wc1xuICAgIH07XG4gIH07XG5cbiAgc3R5Zm4kOC51cGRhdGVTdHlsZUhpbnRzID0gZnVuY3Rpb24gKGVsZSkge1xuICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHByb3BOYW1lcyA9IHNlbGYucHJvcGVydHlHcm91cE5hbWVzO1xuICAgIHZhciBwcm9wR3JLZXlzID0gc2VsZi5wcm9wZXJ0eUdyb3VwS2V5cztcblxuICAgIHZhciBwcm9wSGFzaCA9IGZ1bmN0aW9uIHByb3BIYXNoKGVsZSwgcHJvcE5hbWVzLCBzZWVkS2V5KSB7XG4gICAgICByZXR1cm4gc2VsZi5nZXRQcm9wZXJ0aWVzSGFzaChlbGUsIHByb3BOYW1lcywgc2VlZEtleSk7XG4gICAgfTtcblxuICAgIHZhciBvbGRTdHlsZUtleSA9IF9wLnN0eWxlS2V5O1xuXG4gICAgaWYgKGVsZS5yZW1vdmVkKCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB2YXIgaXNOb2RlID0gX3AuZ3JvdXAgPT09ICdub2Rlcyc7IC8vIGdldCB0aGUgc3R5bGUga2V5IGhhc2hlcyBwZXIgcHJvcCBncm91cFxuICAgIC8vIGJ1dCBsYXppbHkgLS0gb25seSB1c2Ugbm9uLWRlZmF1bHQgcHJvcCB2YWx1ZXMgdG8gcmVkdWNlIHRoZSBudW1iZXIgb2YgaGFzaGVzXG4gICAgLy9cblxuICAgIHZhciBvdmVycmlkZGVuU3R5bGVzID0gZWxlLl9wcml2YXRlLnN0eWxlO1xuICAgIHByb3BOYW1lcyA9IE9iamVjdC5rZXlzKG92ZXJyaWRkZW5TdHlsZXMpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wR3JLZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZ3JLZXkgPSBwcm9wR3JLZXlzW2ldO1xuICAgICAgX3Auc3R5bGVLZXlzW2dyS2V5XSA9IFtERUZBVUxUX0hBU0hfU0VFRCwgREVGQVVMVF9IQVNIX1NFRURfQUxUXTtcbiAgICB9XG5cbiAgICB2YXIgdXBkYXRlR3JLZXkxID0gZnVuY3Rpb24gdXBkYXRlR3JLZXkxKHZhbCwgZ3JLZXkpIHtcbiAgICAgIHJldHVybiBfcC5zdHlsZUtleXNbZ3JLZXldWzBdID0gaGFzaEludCh2YWwsIF9wLnN0eWxlS2V5c1tncktleV1bMF0pO1xuICAgIH07XG5cbiAgICB2YXIgdXBkYXRlR3JLZXkyID0gZnVuY3Rpb24gdXBkYXRlR3JLZXkyKHZhbCwgZ3JLZXkpIHtcbiAgICAgIHJldHVybiBfcC5zdHlsZUtleXNbZ3JLZXldWzFdID0gaGFzaEludEFsdCh2YWwsIF9wLnN0eWxlS2V5c1tncktleV1bMV0pO1xuICAgIH07XG5cbiAgICB2YXIgdXBkYXRlR3JLZXkgPSBmdW5jdGlvbiB1cGRhdGVHcktleSh2YWwsIGdyS2V5KSB7XG4gICAgICB1cGRhdGVHcktleTEodmFsLCBncktleSk7XG4gICAgICB1cGRhdGVHcktleTIodmFsLCBncktleSk7XG4gICAgfTtcblxuICAgIHZhciB1cGRhdGVHcktleVdTdHIgPSBmdW5jdGlvbiB1cGRhdGVHcktleVdTdHIoc3RyVmFsLCBncktleSkge1xuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBzdHJWYWwubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdmFyIGNoID0gc3RyVmFsLmNoYXJDb2RlQXQoaik7XG4gICAgICAgIHVwZGF0ZUdyS2V5MShjaCwgZ3JLZXkpO1xuICAgICAgICB1cGRhdGVHcktleTIoY2gsIGdyS2V5KTtcbiAgICAgIH1cbiAgICB9OyAvLyAtIGhhc2hpbmcgd29ya3Mgb24gMzIgYml0IGludHMgYi9jIHdlIHVzZSBiaXR3aXNlIG9wc1xuICAgIC8vIC0gc21hbGwgbnVtYmVycyBnZXQgY3V0IG9mZiAoZS5nLiAwLjEyMyBpcyBzZWVuIGFzIDAgYnkgdGhlIGhhc2hpbmcgZnVuY3Rpb24pXG4gICAgLy8gLSByYWlzZSB1cCBzbWFsbCBudW1iZXJzIHNvIG1vcmUgc2lnbmlmaWNhbnQgZGlnaXRzIGFyZSBzZWVuIGJ5IGhhc2hpbmdcbiAgICAvLyAtIG1ha2Ugc21hbGwgbnVtYmVycyBsYXJnZXIgdGhhbiBhIG5vcm1hbCB2YWx1ZSB0byBhdm9pZCBjb2xsaXNpb25zXG4gICAgLy8gLSB3b3JrcyBpbiBwcmFjdGljZSBhbmQgaXQncyByZWxhdGl2ZWx5IGNoZWFwXG5cblxuICAgIHZhciBOID0gMjAwMDAwMDAwMDtcblxuICAgIHZhciBjbGVhbk51bSA9IGZ1bmN0aW9uIGNsZWFuTnVtKHZhbCkge1xuICAgICAgcmV0dXJuIC0xMjggPCB2YWwgJiYgdmFsIDwgMTI4ICYmIE1hdGguZmxvb3IodmFsKSAhPT0gdmFsID8gTiAtICh2YWwgKiAxMDI0IHwgMCkgOiB2YWw7XG4gICAgfTtcblxuICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBwcm9wTmFtZXMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICB2YXIgbmFtZSA9IHByb3BOYW1lc1tfaV07XG4gICAgICB2YXIgcGFyc2VkUHJvcCA9IG92ZXJyaWRkZW5TdHlsZXNbbmFtZV07XG5cbiAgICAgIGlmIChwYXJzZWRQcm9wID09IG51bGwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIHZhciBwcm9wSW5mbyA9IHRoaXMucHJvcGVydGllc1tuYW1lXTtcbiAgICAgIHZhciB0eXBlID0gcHJvcEluZm8udHlwZTtcbiAgICAgIHZhciBfZ3JLZXkgPSBwcm9wSW5mby5ncm91cEtleTtcbiAgICAgIHZhciBub3JtYWxpemVkTnVtYmVyVmFsID0gdm9pZCAwO1xuXG4gICAgICBpZiAocHJvcEluZm8uaGFzaE92ZXJyaWRlICE9IG51bGwpIHtcbiAgICAgICAgbm9ybWFsaXplZE51bWJlclZhbCA9IHByb3BJbmZvLmhhc2hPdmVycmlkZShlbGUsIHBhcnNlZFByb3ApO1xuICAgICAgfSBlbHNlIGlmIChwYXJzZWRQcm9wLnBmVmFsdWUgIT0gbnVsbCkge1xuICAgICAgICBub3JtYWxpemVkTnVtYmVyVmFsID0gcGFyc2VkUHJvcC5wZlZhbHVlO1xuICAgICAgfSAvLyBtaWdodCBub3QgYmUgYSBudW1iZXIgaWYgaXQgYWxsb3dzIGVudW1zXG5cblxuICAgICAgdmFyIG51bWJlclZhbCA9IHByb3BJbmZvLmVudW1zID09IG51bGwgPyBwYXJzZWRQcm9wLnZhbHVlIDogbnVsbDtcbiAgICAgIHZhciBoYXZlTm9ybU51bSA9IG5vcm1hbGl6ZWROdW1iZXJWYWwgIT0gbnVsbDtcbiAgICAgIHZhciBoYXZlVW5pdGVkTnVtID0gbnVtYmVyVmFsICE9IG51bGw7XG4gICAgICB2YXIgaGF2ZU51bSA9IGhhdmVOb3JtTnVtIHx8IGhhdmVVbml0ZWROdW07XG4gICAgICB2YXIgdW5pdHMgPSBwYXJzZWRQcm9wLnVuaXRzOyAvLyBudW1iZXJzIGFyZSBjaGVhcGVyIHRvIGhhc2ggdGhhbiBzdHJpbmdzXG4gICAgICAvLyAxIGhhc2ggb3AgdnMgbiBoYXNoIG9wcyAoZm9yIGxlbmd0aCBuIHN0cmluZylcblxuICAgICAgaWYgKHR5cGUubnVtYmVyICYmIGhhdmVOdW0gJiYgIXR5cGUubXVsdGlwbGUpIHtcbiAgICAgICAgdmFyIHYgPSBoYXZlTm9ybU51bSA/IG5vcm1hbGl6ZWROdW1iZXJWYWwgOiBudW1iZXJWYWw7XG4gICAgICAgIHVwZGF0ZUdyS2V5KGNsZWFuTnVtKHYpLCBfZ3JLZXkpO1xuXG4gICAgICAgIGlmICghaGF2ZU5vcm1OdW0gJiYgdW5pdHMgIT0gbnVsbCkge1xuICAgICAgICAgIHVwZGF0ZUdyS2V5V1N0cih1bml0cywgX2dyS2V5KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdXBkYXRlR3JLZXlXU3RyKHBhcnNlZFByb3Auc3RyVmFsdWUsIF9ncktleSk7XG4gICAgICB9XG4gICAgfSAvLyBvdmVyYWxsIHN0eWxlIGtleVxuICAgIC8vXG5cblxuICAgIHZhciBoYXNoID0gW0RFRkFVTFRfSEFTSF9TRUVELCBERUZBVUxUX0hBU0hfU0VFRF9BTFRdO1xuXG4gICAgZm9yICh2YXIgX2kyID0gMDsgX2kyIDwgcHJvcEdyS2V5cy5sZW5ndGg7IF9pMisrKSB7XG4gICAgICB2YXIgX2dyS2V5MiA9IHByb3BHcktleXNbX2kyXTtcbiAgICAgIHZhciBnckhhc2ggPSBfcC5zdHlsZUtleXNbX2dyS2V5Ml07XG4gICAgICBoYXNoWzBdID0gaGFzaEludChnckhhc2hbMF0sIGhhc2hbMF0pO1xuICAgICAgaGFzaFsxXSA9IGhhc2hJbnRBbHQoZ3JIYXNoWzFdLCBoYXNoWzFdKTtcbiAgICB9XG5cbiAgICBfcC5zdHlsZUtleSA9IGNvbWJpbmVIYXNoZXMoaGFzaFswXSwgaGFzaFsxXSk7IC8vIGxhYmVsIGRpbXNcbiAgICAvL1xuXG4gICAgdmFyIHNrID0gX3Auc3R5bGVLZXlzO1xuICAgIF9wLmxhYmVsRGltc0tleSA9IGNvbWJpbmVIYXNoZXNBcnJheShzay5sYWJlbERpbWVuc2lvbnMpO1xuICAgIHZhciBsYWJlbEtleXMgPSBwcm9wSGFzaChlbGUsIFsnbGFiZWwnXSwgc2subGFiZWxEaW1lbnNpb25zKTtcbiAgICBfcC5sYWJlbEtleSA9IGNvbWJpbmVIYXNoZXNBcnJheShsYWJlbEtleXMpO1xuICAgIF9wLmxhYmVsU3R5bGVLZXkgPSBjb21iaW5lSGFzaGVzQXJyYXkoaGFzaEFycmF5cyhzay5jb21tb25MYWJlbCwgbGFiZWxLZXlzKSk7XG5cbiAgICBpZiAoIWlzTm9kZSkge1xuICAgICAgdmFyIHNvdXJjZUxhYmVsS2V5cyA9IHByb3BIYXNoKGVsZSwgWydzb3VyY2UtbGFiZWwnXSwgc2subGFiZWxEaW1lbnNpb25zKTtcbiAgICAgIF9wLnNvdXJjZUxhYmVsS2V5ID0gY29tYmluZUhhc2hlc0FycmF5KHNvdXJjZUxhYmVsS2V5cyk7XG4gICAgICBfcC5zb3VyY2VMYWJlbFN0eWxlS2V5ID0gY29tYmluZUhhc2hlc0FycmF5KGhhc2hBcnJheXMoc2suY29tbW9uTGFiZWwsIHNvdXJjZUxhYmVsS2V5cykpO1xuICAgICAgdmFyIHRhcmdldExhYmVsS2V5cyA9IHByb3BIYXNoKGVsZSwgWyd0YXJnZXQtbGFiZWwnXSwgc2subGFiZWxEaW1lbnNpb25zKTtcbiAgICAgIF9wLnRhcmdldExhYmVsS2V5ID0gY29tYmluZUhhc2hlc0FycmF5KHRhcmdldExhYmVsS2V5cyk7XG4gICAgICBfcC50YXJnZXRMYWJlbFN0eWxlS2V5ID0gY29tYmluZUhhc2hlc0FycmF5KGhhc2hBcnJheXMoc2suY29tbW9uTGFiZWwsIHRhcmdldExhYmVsS2V5cykpO1xuICAgIH0gLy8gbm9kZVxuICAgIC8vXG5cblxuICAgIGlmIChpc05vZGUpIHtcbiAgICAgIHZhciBfcCRzdHlsZUtleXMgPSBfcC5zdHlsZUtleXMsXG4gICAgICAgICAgbm9kZUJvZHkgPSBfcCRzdHlsZUtleXMubm9kZUJvZHksXG4gICAgICAgICAgbm9kZUJvcmRlciA9IF9wJHN0eWxlS2V5cy5ub2RlQm9yZGVyLFxuICAgICAgICAgIGJhY2tncm91bmRJbWFnZSA9IF9wJHN0eWxlS2V5cy5iYWNrZ3JvdW5kSW1hZ2UsXG4gICAgICAgICAgY29tcG91bmQgPSBfcCRzdHlsZUtleXMuY29tcG91bmQsXG4gICAgICAgICAgcGllID0gX3Akc3R5bGVLZXlzLnBpZTtcbiAgICAgIHZhciBub2RlS2V5cyA9IFtub2RlQm9keSwgbm9kZUJvcmRlciwgYmFja2dyb3VuZEltYWdlLCBjb21wb3VuZCwgcGllXS5maWx0ZXIoZnVuY3Rpb24gKGspIHtcbiAgICAgICAgcmV0dXJuIGsgIT0gbnVsbDtcbiAgICAgIH0pLnJlZHVjZShoYXNoQXJyYXlzLCBbREVGQVVMVF9IQVNIX1NFRUQsIERFRkFVTFRfSEFTSF9TRUVEX0FMVF0pO1xuICAgICAgX3Aubm9kZUtleSA9IGNvbWJpbmVIYXNoZXNBcnJheShub2RlS2V5cyk7XG4gICAgICBfcC5oYXNQaWUgPSBwaWUgIT0gbnVsbCAmJiBwaWVbMF0gIT09IERFRkFVTFRfSEFTSF9TRUVEICYmIHBpZVsxXSAhPT0gREVGQVVMVF9IQVNIX1NFRURfQUxUO1xuICAgIH1cblxuICAgIHJldHVybiBvbGRTdHlsZUtleSAhPT0gX3Auc3R5bGVLZXk7XG4gIH07XG5cbiAgc3R5Zm4kOC5jbGVhclN0eWxlSGludHMgPSBmdW5jdGlvbiAoZWxlKSB7XG4gICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgIF9wLnN0eWxlQ3h0S2V5ID0gJyc7XG4gICAgX3Auc3R5bGVLZXlzID0ge307XG4gICAgX3Auc3R5bGVLZXkgPSBudWxsO1xuICAgIF9wLmxhYmVsS2V5ID0gbnVsbDtcbiAgICBfcC5sYWJlbFN0eWxlS2V5ID0gbnVsbDtcbiAgICBfcC5zb3VyY2VMYWJlbEtleSA9IG51bGw7XG4gICAgX3Auc291cmNlTGFiZWxTdHlsZUtleSA9IG51bGw7XG4gICAgX3AudGFyZ2V0TGFiZWxLZXkgPSBudWxsO1xuICAgIF9wLnRhcmdldExhYmVsU3R5bGVLZXkgPSBudWxsO1xuICAgIF9wLm5vZGVLZXkgPSBudWxsO1xuICAgIF9wLmhhc1BpZSA9IG51bGw7XG4gIH07IC8vIGFwcGx5IGEgcHJvcGVydHkgdG8gdGhlIHN0eWxlIChmb3IgaW50ZXJuYWwgdXNlKVxuICAvLyByZXR1cm5zIHdoZXRoZXIgYXBwbGljYXRpb24gd2FzIHN1Y2Nlc3NmdWxcbiAgLy9cbiAgLy8gbm93LCB0aGlzIGZ1bmN0aW9uIGZsYXR0ZW5zIHRoZSBwcm9wZXJ0eSwgYW5kIGhlcmUncyBob3c6XG4gIC8vXG4gIC8vIGZvciBwYXJzZWRQcm9wOnsgYnlwYXNzOiB0cnVlLCBkZWxldGVCeXBhc3M6IHRydWUgfVxuICAvLyBubyBwcm9wZXJ0eSBpcyBnZW5lcmF0ZWQsIGluc3RlYWQgdGhlIGJ5cGFzcyBwcm9wZXJ0eSBpbiB0aGVcbiAgLy8gZWxlbWVudCdzIHN0eWxlIGlzIHJlcGxhY2VkIGJ5IHdoYXQncyBwb2ludGVkIHRvIGJ5IHRoZSBgYnlwYXNzZWRgXG4gIC8vIGZpZWxkIGluIHRoZSBieXBhc3MgcHJvcGVydHkgKGkuZS4gcmVzdG9yaW5nIHRoZSBwcm9wZXJ0eSB0aGVcbiAgLy8gYnlwYXNzIHdhcyBvdmVycmlkaW5nKVxuICAvL1xuICAvLyBmb3IgcGFyc2VkUHJvcDp7IG1hcHBlZDogdHJ1dGh5IH1cbiAgLy8gdGhlIGdlbmVyYXRlZCBmbGF0dGVuZWRQcm9wOnsgbWFwcGluZzogcHJvcCB9XG4gIC8vXG4gIC8vIGZvciBwYXJzZWRQcm9wOnsgYnlwYXNzOiB0cnVlIH1cbiAgLy8gdGhlIGdlbmVyYXRlZCBmbGF0dGVuZWRQcm9wOnsgYnlwYXNzZWQ6IHBhcnNlZFByb3AgfVxuXG5cbiAgc3R5Zm4kOC5hcHBseVBhcnNlZFByb3BlcnR5ID0gZnVuY3Rpb24gKGVsZSwgcGFyc2VkUHJvcCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgcHJvcCA9IHBhcnNlZFByb3A7XG4gICAgdmFyIHN0eWxlID0gZWxlLl9wcml2YXRlLnN0eWxlO1xuICAgIHZhciBmbGF0UHJvcDtcbiAgICB2YXIgdHlwZXMgPSBzZWxmLnR5cGVzO1xuICAgIHZhciB0eXBlID0gc2VsZi5wcm9wZXJ0aWVzW3Byb3AubmFtZV0udHlwZTtcbiAgICB2YXIgcHJvcElzQnlwYXNzID0gcHJvcC5ieXBhc3M7XG4gICAgdmFyIG9yaWdQcm9wID0gc3R5bGVbcHJvcC5uYW1lXTtcbiAgICB2YXIgb3JpZ1Byb3BJc0J5cGFzcyA9IG9yaWdQcm9wICYmIG9yaWdQcm9wLmJ5cGFzcztcbiAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG4gICAgdmFyIGZsYXRQcm9wTWFwcGluZyA9ICdtYXBwaW5nJztcblxuICAgIHZhciBnZXRWYWwgPSBmdW5jdGlvbiBnZXRWYWwocCkge1xuICAgICAgaWYgKHAgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH0gZWxzZSBpZiAocC5wZlZhbHVlICE9IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHAucGZWYWx1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBwLnZhbHVlO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgY2hlY2tUcmlnZ2VycyA9IGZ1bmN0aW9uIGNoZWNrVHJpZ2dlcnMoKSB7XG4gICAgICB2YXIgZnJvbVZhbCA9IGdldFZhbChvcmlnUHJvcCk7XG4gICAgICB2YXIgdG9WYWwgPSBnZXRWYWwocHJvcCk7XG4gICAgICBzZWxmLmNoZWNrVHJpZ2dlcnMoZWxlLCBwcm9wLm5hbWUsIGZyb21WYWwsIHRvVmFsKTtcbiAgICB9O1xuXG4gICAgaWYgKHByb3AgJiYgcHJvcC5uYW1lLnN1YnN0cigwLCAzKSA9PT0gJ3BpZScpIHtcbiAgICAgIHdhcm4oJ1RoZSBwaWUgc3R5bGUgcHJvcGVydGllcyBhcmUgZGVwcmVjYXRlZC4gIENyZWF0ZSBjaGFydHMgdXNpbmcgYmFja2dyb3VuZCBpbWFnZXMgaW5zdGVhZC4nKTtcbiAgICB9IC8vIGVkZ2Ugc2FuaXR5IGNoZWNrcyB0byBwcmV2ZW50IHRoZSBjbGllbnQgZnJvbSBtYWtpbmcgc2VyaW91cyBtaXN0YWtlc1xuXG5cbiAgICBpZiAocGFyc2VkUHJvcC5uYW1lID09PSAnY3VydmUtc3R5bGUnICYmIGVsZS5pc0VkZ2UoKSAmJiAoIC8vIGxvb3BzIG11c3QgYmUgYnVuZGxlZCBiZXppZXJzXG4gICAgcGFyc2VkUHJvcC52YWx1ZSAhPT0gJ2JlemllcicgJiYgZWxlLmlzTG9vcCgpIHx8IC8vIGVkZ2VzIGNvbm5lY3RlZCB0byBjb21wb3VuZCBub2RlcyBjYW4gbm90IGJlIGhheXN0YWNrc1xuICAgIHBhcnNlZFByb3AudmFsdWUgPT09ICdoYXlzdGFjaycgJiYgKGVsZS5zb3VyY2UoKS5pc1BhcmVudCgpIHx8IGVsZS50YXJnZXQoKS5pc1BhcmVudCgpKSkpIHtcbiAgICAgIHByb3AgPSBwYXJzZWRQcm9wID0gdGhpcy5wYXJzZShwYXJzZWRQcm9wLm5hbWUsICdiZXppZXInLCBwcm9wSXNCeXBhc3MpO1xuICAgIH1cblxuICAgIGlmIChwcm9wW1wiZGVsZXRlXCJdKSB7XG4gICAgICAvLyBkZWxldGUgdGhlIHByb3BlcnR5IGFuZCB1c2UgdGhlIGRlZmF1bHQgdmFsdWUgb24gZmFsc2V5IHZhbHVlXG4gICAgICBzdHlsZVtwcm9wLm5hbWVdID0gdW5kZWZpbmVkO1xuICAgICAgY2hlY2tUcmlnZ2VycygpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgaWYgKHByb3AuZGVsZXRlQnlwYXNzZWQpIHtcbiAgICAgIC8vIGRlbGV0ZSB0aGUgcHJvcGVydHkgdGhhdCB0aGVcbiAgICAgIGlmICghb3JpZ1Byb3ApIHtcbiAgICAgICAgY2hlY2tUcmlnZ2VycygpO1xuICAgICAgICByZXR1cm4gdHJ1ZTsgLy8gY2FuJ3QgZGVsZXRlIGlmIG5vIHByb3BcbiAgICAgIH0gZWxzZSBpZiAob3JpZ1Byb3AuYnlwYXNzKSB7XG4gICAgICAgIC8vIGRlbGV0ZSBieXBhc3NlZFxuICAgICAgICBvcmlnUHJvcC5ieXBhc3NlZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgY2hlY2tUcmlnZ2VycygpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBmYWxzZTsgLy8gd2UncmUgdW5zdWNjZXNzZnVsIGRlbGV0aW5nIHRoZSBieXBhc3NlZFxuICAgICAgfVxuICAgIH0gLy8gY2hlY2sgaWYgd2UgbmVlZCB0byBkZWxldGUgdGhlIGN1cnJlbnQgYnlwYXNzXG5cblxuICAgIGlmIChwcm9wLmRlbGV0ZUJ5cGFzcykge1xuICAgICAgLy8gdGhlbiB0aGlzIHByb3BlcnR5IGlzIGp1c3QgaGVyZSB0byBpbmRpY2F0ZSB3ZSBuZWVkIHRvIGRlbGV0ZVxuICAgICAgaWYgKCFvcmlnUHJvcCkge1xuICAgICAgICBjaGVja1RyaWdnZXJzKCk7XG4gICAgICAgIHJldHVybiB0cnVlOyAvLyBwcm9wZXJ0eSBpcyBhbHJlYWR5IG5vdCBkZWZpbmVkXG4gICAgICB9IGVsc2UgaWYgKG9yaWdQcm9wLmJ5cGFzcykge1xuICAgICAgICAvLyB0aGVuIHJlcGxhY2UgdGhlIGJ5cGFzcyBwcm9wZXJ0eSB3aXRoIHRoZSBvcmlnaW5hbFxuICAgICAgICAvLyBiZWNhdXNlIHRoZSBieXBhc3NlZCBwcm9wZXJ0eSB3YXMgYWxyZWFkeSBhcHBsaWVkIChhbmQgdGhlcmVmb3JlIHBhcnNlZCksIHdlIGNhbiBqdXN0IHJlcGxhY2UgaXQgKG5vIHJlYXBwbHlpbmcgbmVjZXNzYXJ5KVxuICAgICAgICBzdHlsZVtwcm9wLm5hbWVdID0gb3JpZ1Byb3AuYnlwYXNzZWQ7XG4gICAgICAgIGNoZWNrVHJpZ2dlcnMoKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gZmFsc2U7IC8vIHdlJ3JlIHVuc3VjY2Vzc2Z1bCBkZWxldGluZyB0aGUgYnlwYXNzXG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIHByaW50TWFwcGluZ0VyciA9IGZ1bmN0aW9uIHByaW50TWFwcGluZ0VycigpIHtcbiAgICAgIHdhcm4oJ0RvIG5vdCBhc3NpZ24gbWFwcGluZ3MgdG8gZWxlbWVudHMgd2l0aG91dCBjb3JyZXNwb25kaW5nIGRhdGEgKGkuZS4gZWxlIGAnICsgZWxlLmlkKCkgKyAnYCBoYXMgbm8gbWFwcGluZyBmb3IgcHJvcGVydHkgYCcgKyBwcm9wLm5hbWUgKyAnYCB3aXRoIGRhdGEgZmllbGQgYCcgKyBwcm9wLmZpZWxkICsgJ2ApOyB0cnkgYSBgWycgKyBwcm9wLmZpZWxkICsgJ11gIHNlbGVjdG9yIHRvIGxpbWl0IHNjb3BlIHRvIGVsZW1lbnRzIHdpdGggYCcgKyBwcm9wLmZpZWxkICsgJ2AgZGVmaW5lZCcpO1xuICAgIH07IC8vIHB1dCB0aGUgcHJvcGVydHkgaW4gdGhlIHN0eWxlIG9iamVjdHNcblxuXG4gICAgc3dpdGNoIChwcm9wLm1hcHBlZCkge1xuICAgICAgLy8gZmxhdHRlbiB0aGUgcHJvcGVydHkgaWYgbWFwcGVkXG4gICAgICBjYXNlIHR5cGVzLm1hcERhdGE6XG4gICAgICAgIHtcbiAgICAgICAgICAvLyBmbGF0dGVuIHRoZSBmaWVsZCAoZS5nLiBkYXRhLmZvby5iYXIpXG4gICAgICAgICAgdmFyIGZpZWxkcyA9IHByb3AuZmllbGQuc3BsaXQoJy4nKTtcbiAgICAgICAgICB2YXIgZmllbGRWYWwgPSBfcC5kYXRhO1xuXG4gICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBmaWVsZHMubGVuZ3RoICYmIGZpZWxkVmFsOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBmaWVsZCA9IGZpZWxkc1tpXTtcbiAgICAgICAgICAgIGZpZWxkVmFsID0gZmllbGRWYWxbZmllbGRdO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChmaWVsZFZhbCA9PSBudWxsKSB7XG4gICAgICAgICAgICBwcmludE1hcHBpbmdFcnIoKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB2YXIgcGVyY2VudDtcblxuICAgICAgICAgIGlmICghbnVtYmVyJDEoZmllbGRWYWwpKSB7XG4gICAgICAgICAgICAvLyB0aGVuIGRvbid0IGFwcGx5IGFuZCBmYWxsIGJhY2sgb24gdGhlIGV4aXN0aW5nIHN0eWxlXG4gICAgICAgICAgICB3YXJuKCdEbyBub3QgdXNlIGNvbnRpbnVvdXMgbWFwcGVycyB3aXRob3V0IHNwZWNpZnlpbmcgbnVtZXJpYyBkYXRhIChpLmUuIGAnICsgcHJvcC5maWVsZCArICc6ICcgKyBmaWVsZFZhbCArICdgIGZvciBgJyArIGVsZS5pZCgpICsgJ2AgaXMgbm9uLW51bWVyaWMpJyk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHZhciBmaWVsZFdpZHRoID0gcHJvcC5maWVsZE1heCAtIHByb3AuZmllbGRNaW47XG5cbiAgICAgICAgICAgIGlmIChmaWVsZFdpZHRoID09PSAwKSB7XG4gICAgICAgICAgICAgIC8vIHNhZmV0eSBjaGVjayAtLSBub3Qgc3RyaWN0bHkgbmVjZXNzYXJ5IGFzIG5vIHByb3BzIG9mIHplcm8gcmFuZ2Ugc2hvdWxkIGJlIHBhc3NlZCBoZXJlXG4gICAgICAgICAgICAgIHBlcmNlbnQgPSAwO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcGVyY2VudCA9IChmaWVsZFZhbCAtIHByb3AuZmllbGRNaW4pIC8gZmllbGRXaWR0aDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIG1ha2Ugc3VyZSB0byBib3VuZCBwZXJjZW50IHZhbHVlXG5cblxuICAgICAgICAgIGlmIChwZXJjZW50IDwgMCkge1xuICAgICAgICAgICAgcGVyY2VudCA9IDA7XG4gICAgICAgICAgfSBlbHNlIGlmIChwZXJjZW50ID4gMSkge1xuICAgICAgICAgICAgcGVyY2VudCA9IDE7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHR5cGUuY29sb3IpIHtcbiAgICAgICAgICAgIHZhciByMSA9IHByb3AudmFsdWVNaW5bMF07XG4gICAgICAgICAgICB2YXIgcjIgPSBwcm9wLnZhbHVlTWF4WzBdO1xuICAgICAgICAgICAgdmFyIGcxID0gcHJvcC52YWx1ZU1pblsxXTtcbiAgICAgICAgICAgIHZhciBnMiA9IHByb3AudmFsdWVNYXhbMV07XG4gICAgICAgICAgICB2YXIgYjEgPSBwcm9wLnZhbHVlTWluWzJdO1xuICAgICAgICAgICAgdmFyIGIyID0gcHJvcC52YWx1ZU1heFsyXTtcbiAgICAgICAgICAgIHZhciBhMSA9IHByb3AudmFsdWVNaW5bM10gPT0gbnVsbCA/IDEgOiBwcm9wLnZhbHVlTWluWzNdO1xuICAgICAgICAgICAgdmFyIGEyID0gcHJvcC52YWx1ZU1heFszXSA9PSBudWxsID8gMSA6IHByb3AudmFsdWVNYXhbM107XG4gICAgICAgICAgICB2YXIgY2xyID0gW01hdGgucm91bmQocjEgKyAocjIgLSByMSkgKiBwZXJjZW50KSwgTWF0aC5yb3VuZChnMSArIChnMiAtIGcxKSAqIHBlcmNlbnQpLCBNYXRoLnJvdW5kKGIxICsgKGIyIC0gYjEpICogcGVyY2VudCksIE1hdGgucm91bmQoYTEgKyAoYTIgLSBhMSkgKiBwZXJjZW50KV07XG4gICAgICAgICAgICBmbGF0UHJvcCA9IHtcbiAgICAgICAgICAgICAgLy8gY29sb3VycyBhcmUgc2ltcGxlLCBzbyBqdXN0IGNyZWF0ZSB0aGUgZmxhdCBwcm9wZXJ0eSBpbnN0ZWFkIG9mIGV4cGVuc2l2ZSBzdHJpbmcgcGFyc2luZ1xuICAgICAgICAgICAgICBieXBhc3M6IHByb3AuYnlwYXNzLFxuICAgICAgICAgICAgICAvLyB3ZSdyZSBhIGJ5cGFzcyBpZiB0aGUgbWFwcGluZyBwcm9wZXJ0eSBpcyBhIGJ5cGFzc1xuICAgICAgICAgICAgICBuYW1lOiBwcm9wLm5hbWUsXG4gICAgICAgICAgICAgIHZhbHVlOiBjbHIsXG4gICAgICAgICAgICAgIHN0clZhbHVlOiAncmdiKCcgKyBjbHJbMF0gKyAnLCAnICsgY2xyWzFdICsgJywgJyArIGNsclsyXSArICcpJ1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHR5cGUubnVtYmVyKSB7XG4gICAgICAgICAgICB2YXIgY2FsY1ZhbHVlID0gcHJvcC52YWx1ZU1pbiArIChwcm9wLnZhbHVlTWF4IC0gcHJvcC52YWx1ZU1pbikgKiBwZXJjZW50O1xuICAgICAgICAgICAgZmxhdFByb3AgPSB0aGlzLnBhcnNlKHByb3AubmFtZSwgY2FsY1ZhbHVlLCBwcm9wLmJ5cGFzcywgZmxhdFByb3BNYXBwaW5nKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlOyAvLyBjYW4gb25seSBtYXAgdG8gY29sb3VycyBhbmQgbnVtYmVyc1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghZmxhdFByb3ApIHtcbiAgICAgICAgICAgIC8vIGlmIHdlIGNhbid0IGZsYXR0ZW4gdGhlIHByb3BlcnR5LCB0aGVuIGRvbid0IGFwcGx5IHRoZSBwcm9wZXJ0eSBhbmQgZmFsbCBiYWNrIG9uIHRoZSBleGlzdGluZyBzdHlsZVxuICAgICAgICAgICAgcHJpbnRNYXBwaW5nRXJyKCk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZmxhdFByb3AubWFwcGluZyA9IHByb3A7IC8vIGtlZXAgYSByZWZlcmVuY2UgdG8gdGhlIG1hcHBpbmdcblxuICAgICAgICAgIHByb3AgPSBmbGF0UHJvcDsgLy8gdGhlIGZsYXR0ZW5lZCAobWFwcGVkKSBwcm9wZXJ0eSBpcyB0aGUgb25lIHdlIHdhbnRcblxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAvLyBkaXJlY3QgbWFwcGluZ1xuXG4gICAgICBjYXNlIHR5cGVzLmRhdGE6XG4gICAgICAgIHtcbiAgICAgICAgICAvLyBmbGF0dGVuIHRoZSBmaWVsZCAoZS5nLiBkYXRhLmZvby5iYXIpXG4gICAgICAgICAgdmFyIF9maWVsZHMgPSBwcm9wLmZpZWxkLnNwbGl0KCcuJyk7XG5cbiAgICAgICAgICB2YXIgX2ZpZWxkVmFsID0gX3AuZGF0YTtcblxuICAgICAgICAgIGZvciAodmFyIF9pMyA9IDA7IF9pMyA8IF9maWVsZHMubGVuZ3RoICYmIF9maWVsZFZhbDsgX2kzKyspIHtcbiAgICAgICAgICAgIHZhciBfZmllbGQgPSBfZmllbGRzW19pM107XG4gICAgICAgICAgICBfZmllbGRWYWwgPSBfZmllbGRWYWxbX2ZpZWxkXTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoX2ZpZWxkVmFsICE9IG51bGwpIHtcbiAgICAgICAgICAgIGZsYXRQcm9wID0gdGhpcy5wYXJzZShwcm9wLm5hbWUsIF9maWVsZFZhbCwgcHJvcC5ieXBhc3MsIGZsYXRQcm9wTWFwcGluZyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFmbGF0UHJvcCkge1xuICAgICAgICAgICAgLy8gaWYgd2UgY2FuJ3QgZmxhdHRlbiB0aGUgcHJvcGVydHksIHRoZW4gZG9uJ3QgYXBwbHkgYW5kIGZhbGwgYmFjayBvbiB0aGUgZXhpc3Rpbmcgc3R5bGVcbiAgICAgICAgICAgIHByaW50TWFwcGluZ0VycigpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGZsYXRQcm9wLm1hcHBpbmcgPSBwcm9wOyAvLyBrZWVwIGEgcmVmZXJlbmNlIHRvIHRoZSBtYXBwaW5nXG5cbiAgICAgICAgICBwcm9wID0gZmxhdFByb3A7IC8vIHRoZSBmbGF0dGVuZWQgKG1hcHBlZCkgcHJvcGVydHkgaXMgdGhlIG9uZSB3ZSB3YW50XG5cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICBjYXNlIHR5cGVzLmZuOlxuICAgICAgICB7XG4gICAgICAgICAgdmFyIGZuID0gcHJvcC52YWx1ZTtcbiAgICAgICAgICB2YXIgZm5SZXRWYWwgPSBwcm9wLmZuVmFsdWUgIT0gbnVsbCA/IHByb3AuZm5WYWx1ZSA6IGZuKGVsZSk7IC8vIGNoZWNrIGZvciBjYWNoZWQgdmFsdWUgYmVmb3JlIGNhbGxpbmcgZnVuY3Rpb25cblxuICAgICAgICAgIHByb3AucHJldkZuVmFsdWUgPSBmblJldFZhbDtcblxuICAgICAgICAgIGlmIChmblJldFZhbCA9PSBudWxsKSB7XG4gICAgICAgICAgICB3YXJuKCdDdXN0b20gZnVuY3Rpb24gbWFwcGVycyBtYXkgbm90IHJldHVybiBudWxsIChpLmUuIGAnICsgcHJvcC5uYW1lICsgJ2AgZm9yIGVsZSBgJyArIGVsZS5pZCgpICsgJ2AgaXMgbnVsbCknKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBmbGF0UHJvcCA9IHRoaXMucGFyc2UocHJvcC5uYW1lLCBmblJldFZhbCwgcHJvcC5ieXBhc3MsIGZsYXRQcm9wTWFwcGluZyk7XG5cbiAgICAgICAgICBpZiAoIWZsYXRQcm9wKSB7XG4gICAgICAgICAgICB3YXJuKCdDdXN0b20gZnVuY3Rpb24gbWFwcGVycyBtYXkgbm90IHJldHVybiBpbnZhbGlkIHZhbHVlcyBmb3IgdGhlIHByb3BlcnR5IHR5cGUgKGkuZS4gYCcgKyBwcm9wLm5hbWUgKyAnYCBmb3IgZWxlIGAnICsgZWxlLmlkKCkgKyAnYCBpcyBpbnZhbGlkKScpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGZsYXRQcm9wLm1hcHBpbmcgPSBjb3B5KHByb3ApOyAvLyBrZWVwIGEgcmVmZXJlbmNlIHRvIHRoZSBtYXBwaW5nXG5cbiAgICAgICAgICBwcm9wID0gZmxhdFByb3A7IC8vIHRoZSBmbGF0dGVuZWQgKG1hcHBlZCkgcHJvcGVydHkgaXMgdGhlIG9uZSB3ZSB3YW50XG5cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICBjYXNlIHVuZGVmaW5lZDpcbiAgICAgICAgYnJlYWs7XG4gICAgICAvLyBqdXN0IHNldCB0aGUgcHJvcGVydHlcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgLy8gbm90IGEgdmFsaWQgbWFwcGluZ1xuICAgIH0gLy8gaWYgdGhlIHByb3BlcnR5IGlzIGEgYnlwYXNzIHByb3BlcnR5LCB0aGVuIGxpbmsgdGhlIHJlc3VsdGFudCBwcm9wZXJ0eSB0byB0aGUgb3JpZ2luYWwgb25lXG5cblxuICAgIGlmIChwcm9wSXNCeXBhc3MpIHtcbiAgICAgIGlmIChvcmlnUHJvcElzQnlwYXNzKSB7XG4gICAgICAgIC8vIHRoZW4gdGhpcyBieXBhc3Mgb3ZlcnJpZGVzIHRoZSBleGlzdGluZyBvbmVcbiAgICAgICAgcHJvcC5ieXBhc3NlZCA9IG9yaWdQcm9wLmJ5cGFzc2VkOyAvLyBzdGVhbCBieXBhc3NlZCBwcm9wIGZyb20gb2xkIGJ5cGFzc1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gdGhlbiBsaW5rIHRoZSBvcmlnIHByb3AgdG8gdGhlIG5ldyBieXBhc3NcbiAgICAgICAgcHJvcC5ieXBhc3NlZCA9IG9yaWdQcm9wO1xuICAgICAgfVxuXG4gICAgICBzdHlsZVtwcm9wLm5hbWVdID0gcHJvcDsgLy8gYW5kIHNldFxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBwcm9wIGlzIG5vdCBieXBhc3NcbiAgICAgIGlmIChvcmlnUHJvcElzQnlwYXNzKSB7XG4gICAgICAgIC8vIHRoZW4ga2VlcCB0aGUgb3JpZyBwcm9wIChzaW5jZSBpdCdzIGEgYnlwYXNzKSBhbmQgbGluayB0byB0aGUgbmV3IHByb3BcbiAgICAgICAgb3JpZ1Byb3AuYnlwYXNzZWQgPSBwcm9wO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gdGhlbiBqdXN0IHJlcGxhY2UgdGhlIG9sZCBwcm9wIHdpdGggdGhlIG5ldyBvbmVcbiAgICAgICAgc3R5bGVbcHJvcC5uYW1lXSA9IHByb3A7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY2hlY2tUcmlnZ2VycygpO1xuICAgIHJldHVybiB0cnVlO1xuICB9O1xuXG4gIHN0eWZuJDguY2xlYW5FbGVtZW50cyA9IGZ1bmN0aW9uIChlbGVzLCBrZWVwQnlwYXNzZXMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBlbGUgPSBlbGVzW2ldO1xuICAgICAgdGhpcy5jbGVhclN0eWxlSGludHMoZWxlKTtcbiAgICAgIGVsZS5kaXJ0eUNvbXBvdW5kQm91bmRzQ2FjaGUoKTtcbiAgICAgIGVsZS5kaXJ0eUJvdW5kaW5nQm94Q2FjaGUoKTtcblxuICAgICAgaWYgKCFrZWVwQnlwYXNzZXMpIHtcbiAgICAgICAgZWxlLl9wcml2YXRlLnN0eWxlID0ge307XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgc3R5bGUgPSBlbGUuX3ByaXZhdGUuc3R5bGU7XG4gICAgICAgIHZhciBwcm9wTmFtZXMgPSBPYmplY3Qua2V5cyhzdHlsZSk7XG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBwcm9wTmFtZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICB2YXIgcHJvcE5hbWUgPSBwcm9wTmFtZXNbal07XG4gICAgICAgICAgdmFyIGVsZVByb3AgPSBzdHlsZVtwcm9wTmFtZV07XG5cbiAgICAgICAgICBpZiAoZWxlUHJvcCAhPSBudWxsKSB7XG4gICAgICAgICAgICBpZiAoZWxlUHJvcC5ieXBhc3MpIHtcbiAgICAgICAgICAgICAgZWxlUHJvcC5ieXBhc3NlZCA9IG51bGw7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzdHlsZVtwcm9wTmFtZV0gPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfTsgLy8gdXBkYXRlcyB0aGUgdmlzdWFsIHN0eWxlIGZvciBhbGwgZWxlbWVudHMgKHVzZWZ1bCBmb3IgbWFudWFsIHN0eWxlIG1vZGlmaWNhdGlvbiBhZnRlciBpbml0KVxuXG5cbiAgc3R5Zm4kOC51cGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGN5ID0gdGhpcy5fcHJpdmF0ZS5jeTtcbiAgICB2YXIgZWxlcyA9IGN5Lm11dGFibGVFbGVtZW50cygpO1xuICAgIGVsZXMudXBkYXRlU3R5bGUoKTtcbiAgfTsgLy8gZGlmZlByb3BzIDogeyBuYW1lID0+IHsgcHJldiwgbmV4dCB9IH1cblxuXG4gIHN0eWZuJDgudXBkYXRlVHJhbnNpdGlvbnMgPSBmdW5jdGlvbiAoZWxlLCBkaWZmUHJvcHMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgIHZhciBwcm9wcyA9IGVsZS5wc3R5bGUoJ3RyYW5zaXRpb24tcHJvcGVydHknKS52YWx1ZTtcbiAgICB2YXIgZHVyYXRpb24gPSBlbGUucHN0eWxlKCd0cmFuc2l0aW9uLWR1cmF0aW9uJykucGZWYWx1ZTtcbiAgICB2YXIgZGVsYXkgPSBlbGUucHN0eWxlKCd0cmFuc2l0aW9uLWRlbGF5JykucGZWYWx1ZTtcblxuICAgIGlmIChwcm9wcy5sZW5ndGggPiAwICYmIGR1cmF0aW9uID4gMCkge1xuICAgICAgdmFyIHN0eWxlID0ge307IC8vIGJ1aWxkIHVwIHRoZSBzdHlsZSB0byBhbmltYXRlIHRvd2FyZHNcblxuICAgICAgdmFyIGFueVByZXYgPSBmYWxzZTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgcHJvcCA9IHByb3BzW2ldO1xuICAgICAgICB2YXIgc3R5UHJvcCA9IGVsZS5wc3R5bGUocHJvcCk7XG4gICAgICAgIHZhciBkaWZmUHJvcCA9IGRpZmZQcm9wc1twcm9wXTtcblxuICAgICAgICBpZiAoIWRpZmZQcm9wKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJldlByb3AgPSBkaWZmUHJvcC5wcmV2O1xuICAgICAgICB2YXIgZnJvbVByb3AgPSBwcmV2UHJvcDtcbiAgICAgICAgdmFyIHRvUHJvcCA9IGRpZmZQcm9wLm5leHQgIT0gbnVsbCA/IGRpZmZQcm9wLm5leHQgOiBzdHlQcm9wO1xuICAgICAgICB2YXIgZGlmZiA9IGZhbHNlO1xuICAgICAgICB2YXIgaW5pdFZhbCA9IHZvaWQgMDtcbiAgICAgICAgdmFyIGluaXREdCA9IDAuMDAwMDAxOyAvLyBkZWx0YSB0aW1lICUgdmFsdWUgZm9yIGluaXRWYWwgKGFsbG93cyBhbmltYXRpbmcgb3V0IG9mIGluaXQgemVybyBvcGFjaXR5KVxuXG4gICAgICAgIGlmICghZnJvbVByb3ApIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfSAvLyBjb25zaWRlciBweCB2YWx1ZXNcblxuXG4gICAgICAgIGlmIChudW1iZXIkMShmcm9tUHJvcC5wZlZhbHVlKSAmJiBudW1iZXIkMSh0b1Byb3AucGZWYWx1ZSkpIHtcbiAgICAgICAgICBkaWZmID0gdG9Qcm9wLnBmVmFsdWUgLSBmcm9tUHJvcC5wZlZhbHVlOyAvLyBub256ZXJvIGlzIHRydXRoeVxuXG4gICAgICAgICAgaW5pdFZhbCA9IGZyb21Qcm9wLnBmVmFsdWUgKyBpbml0RHQgKiBkaWZmOyAvLyBjb25zaWRlciBudW1lcmljYWwgdmFsdWVzXG4gICAgICAgIH0gZWxzZSBpZiAobnVtYmVyJDEoZnJvbVByb3AudmFsdWUpICYmIG51bWJlciQxKHRvUHJvcC52YWx1ZSkpIHtcbiAgICAgICAgICBkaWZmID0gdG9Qcm9wLnZhbHVlIC0gZnJvbVByb3AudmFsdWU7IC8vIG5vbnplcm8gaXMgdHJ1dGh5XG5cbiAgICAgICAgICBpbml0VmFsID0gZnJvbVByb3AudmFsdWUgKyBpbml0RHQgKiBkaWZmOyAvLyBjb25zaWRlciBjb2xvdXIgdmFsdWVzXG4gICAgICAgIH0gZWxzZSBpZiAoYXJyYXkoZnJvbVByb3AudmFsdWUpICYmIGFycmF5KHRvUHJvcC52YWx1ZSkpIHtcbiAgICAgICAgICBkaWZmID0gZnJvbVByb3AudmFsdWVbMF0gIT09IHRvUHJvcC52YWx1ZVswXSB8fCBmcm9tUHJvcC52YWx1ZVsxXSAhPT0gdG9Qcm9wLnZhbHVlWzFdIHx8IGZyb21Qcm9wLnZhbHVlWzJdICE9PSB0b1Byb3AudmFsdWVbMl07XG4gICAgICAgICAgaW5pdFZhbCA9IGZyb21Qcm9wLnN0clZhbHVlO1xuICAgICAgICB9IC8vIHRoZSBwcmV2aW91cyB2YWx1ZSBpcyBnb29kIGZvciBhbiBhbmltYXRpb24gb25seSBpZiBpdCdzIGRpZmZlcmVudFxuXG5cbiAgICAgICAgaWYgKGRpZmYpIHtcbiAgICAgICAgICBzdHlsZVtwcm9wXSA9IHRvUHJvcC5zdHJWYWx1ZTsgLy8gdG8gdmFsXG5cbiAgICAgICAgICB0aGlzLmFwcGx5QnlwYXNzKGVsZSwgcHJvcCwgaW5pdFZhbCk7IC8vIGZyb20gdmFsXG5cbiAgICAgICAgICBhbnlQcmV2ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSAvLyBlbmQgaWYgcHJvcHMgYWxsb3cgYW5pXG4gICAgICAvLyBjYW4ndCB0cmFuc2l0aW9uIGlmIHRoZXJlJ3Mgbm90aGluZyBwcmV2aW91cyB0byB0cmFuc2l0aW9uIGZyb21cblxuXG4gICAgICBpZiAoIWFueVByZXYpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBfcC50cmFuc2l0aW9uaW5nID0gdHJ1ZTtcbiAgICAgIG5ldyBQcm9taXNlJDEoZnVuY3Rpb24gKHJlc29sdmUpIHtcbiAgICAgICAgaWYgKGRlbGF5ID4gMCkge1xuICAgICAgICAgIGVsZS5kZWxheUFuaW1hdGlvbihkZWxheSkucGxheSgpLnByb21pc2UoKS50aGVuKHJlc29sdmUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgfSkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbGUuYW5pbWF0aW9uKHtcbiAgICAgICAgICBzdHlsZTogc3R5bGUsXG4gICAgICAgICAgZHVyYXRpb246IGR1cmF0aW9uLFxuICAgICAgICAgIGVhc2luZzogZWxlLnBzdHlsZSgndHJhbnNpdGlvbi10aW1pbmctZnVuY3Rpb24nKS52YWx1ZSxcbiAgICAgICAgICBxdWV1ZTogZmFsc2VcbiAgICAgICAgfSkucGxheSgpLnByb21pc2UoKTtcbiAgICAgIH0pLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBpZiggIWlzQnlwYXNzICl7XG4gICAgICAgIHNlbGYucmVtb3ZlQnlwYXNzZXMoZWxlLCBwcm9wcyk7XG4gICAgICAgIGVsZS5lbWl0QW5kTm90aWZ5KCdzdHlsZScpOyAvLyB9XG5cbiAgICAgICAgX3AudHJhbnNpdGlvbmluZyA9IGZhbHNlO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIGlmIChfcC50cmFuc2l0aW9uaW5nKSB7XG4gICAgICB0aGlzLnJlbW92ZUJ5cGFzc2VzKGVsZSwgcHJvcHMpO1xuICAgICAgZWxlLmVtaXRBbmROb3RpZnkoJ3N0eWxlJyk7XG4gICAgICBfcC50cmFuc2l0aW9uaW5nID0gZmFsc2U7XG4gICAgfVxuICB9O1xuXG4gIHN0eWZuJDguY2hlY2tUcmlnZ2VyID0gZnVuY3Rpb24gKGVsZSwgbmFtZSwgZnJvbVZhbHVlLCB0b1ZhbHVlLCBnZXRUcmlnZ2VyLCBvblRyaWdnZXIpIHtcbiAgICB2YXIgcHJvcCA9IHRoaXMucHJvcGVydGllc1tuYW1lXTtcbiAgICB2YXIgdHJpZ2dlckNoZWNrID0gZ2V0VHJpZ2dlcihwcm9wKTtcblxuICAgIGlmICh0cmlnZ2VyQ2hlY2sgIT0gbnVsbCAmJiB0cmlnZ2VyQ2hlY2soZnJvbVZhbHVlLCB0b1ZhbHVlKSkge1xuICAgICAgb25UcmlnZ2VyKHByb3ApO1xuICAgIH1cbiAgfTtcblxuICBzdHlmbiQ4LmNoZWNrWk9yZGVyVHJpZ2dlciA9IGZ1bmN0aW9uIChlbGUsIG5hbWUsIGZyb21WYWx1ZSwgdG9WYWx1ZSkge1xuICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICB0aGlzLmNoZWNrVHJpZ2dlcihlbGUsIG5hbWUsIGZyb21WYWx1ZSwgdG9WYWx1ZSwgZnVuY3Rpb24gKHByb3ApIHtcbiAgICAgIHJldHVybiBwcm9wLnRyaWdnZXJzWk9yZGVyO1xuICAgIH0sIGZ1bmN0aW9uICgpIHtcbiAgICAgIF90aGlzLl9wcml2YXRlLmN5Lm5vdGlmeSgnem9yZGVyJywgZWxlKTtcbiAgICB9KTtcbiAgfTtcblxuICBzdHlmbiQ4LmNoZWNrQm91bmRzVHJpZ2dlciA9IGZ1bmN0aW9uIChlbGUsIG5hbWUsIGZyb21WYWx1ZSwgdG9WYWx1ZSkge1xuICAgIHRoaXMuY2hlY2tUcmlnZ2VyKGVsZSwgbmFtZSwgZnJvbVZhbHVlLCB0b1ZhbHVlLCBmdW5jdGlvbiAocHJvcCkge1xuICAgICAgcmV0dXJuIHByb3AudHJpZ2dlcnNCb3VuZHM7XG4gICAgfSwgZnVuY3Rpb24gKHByb3ApIHtcbiAgICAgIGVsZS5kaXJ0eUNvbXBvdW5kQm91bmRzQ2FjaGUoKTtcbiAgICAgIGVsZS5kaXJ0eUJvdW5kaW5nQm94Q2FjaGUoKTsgLy8gaWYgdGhlIHByb3AgY2hhbmdlIG1ha2VzIHRoZSBiYiBvZiBwbGwgYmV6aWVyIGVkZ2VzIGludmFsaWQsXG4gICAgICAvLyB0aGVuIGRpcnR5IHRoZSBwbGwgZWRnZSBiYiBjYWNoZSBhcyB3ZWxsXG5cbiAgICAgIGlmICggLy8gb25seSBmb3IgYmV6aWVycyAtLSBzbyBwZXJmb3JtYW5jZSBvZiBvdGhlciBlZGdlcyBpc24ndCBhZmZlY3RlZFxuICAgICAgcHJvcC50cmlnZ2Vyc0JvdW5kc09mUGFyYWxsZWxCZXppZXJzICYmIChuYW1lID09PSAnY3VydmUtc3R5bGUnICYmIChmcm9tVmFsdWUgPT09ICdiZXppZXInIHx8IHRvVmFsdWUgPT09ICdiZXppZXInKSB8fCBuYW1lID09PSAnZGlzcGxheScgJiYgKGZyb21WYWx1ZSA9PT0gJ25vbmUnIHx8IHRvVmFsdWUgPT09ICdub25lJykpKSB7XG4gICAgICAgIGVsZS5wYXJhbGxlbEVkZ2VzKCkuZm9yRWFjaChmdW5jdGlvbiAocGxsRWRnZSkge1xuICAgICAgICAgIGlmIChwbGxFZGdlLmlzQnVuZGxlZEJlemllcigpKSB7XG4gICAgICAgICAgICBwbGxFZGdlLmRpcnR5Qm91bmRpbmdCb3hDYWNoZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgc3R5Zm4kOC5jaGVja1RyaWdnZXJzID0gZnVuY3Rpb24gKGVsZSwgbmFtZSwgZnJvbVZhbHVlLCB0b1ZhbHVlKSB7XG4gICAgZWxlLmRpcnR5U3R5bGVDYWNoZSgpO1xuICAgIHRoaXMuY2hlY2taT3JkZXJUcmlnZ2VyKGVsZSwgbmFtZSwgZnJvbVZhbHVlLCB0b1ZhbHVlKTtcbiAgICB0aGlzLmNoZWNrQm91bmRzVHJpZ2dlcihlbGUsIG5hbWUsIGZyb21WYWx1ZSwgdG9WYWx1ZSk7XG4gIH07XG5cbiAgdmFyIHN0eWZuJDcgPSB7fTsgLy8gYnlwYXNzZXMgYXJlIGFwcGxpZWQgdG8gYW4gZXhpc3Rpbmcgc3R5bGUgb24gYW4gZWxlbWVudCwgYW5kIGp1c3QgdGFja2VkIG9uIHRlbXBvcmFyaWx5XG4gIC8vIHJldHVybnMgdHJ1ZSBpZmYgYXBwbGljYXRpb24gd2FzIHN1Y2Nlc3NmdWwgZm9yIGF0IGxlYXN0IDEgc3BlY2lmaWVkIHByb3BlcnR5XG5cbiAgc3R5Zm4kNy5hcHBseUJ5cGFzcyA9IGZ1bmN0aW9uIChlbGVzLCBuYW1lLCB2YWx1ZSwgdXBkYXRlVHJhbnNpdGlvbnMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHByb3BzID0gW107XG4gICAgdmFyIGlzQnlwYXNzID0gdHJ1ZTsgLy8gcHV0IGFsbCB0aGUgcHJvcGVydGllcyAoY2FuIHNwZWNpZnkgb25lIG9yIG1hbnkpIGluIGFuIGFycmF5IGFmdGVyIHBhcnNpbmcgdGhlbVxuXG4gICAgaWYgKG5hbWUgPT09ICcqJyB8fCBuYW1lID09PSAnKionKSB7XG4gICAgICAvLyBhcHBseSB0byBhbGwgcHJvcGVydHkgbmFtZXNcbiAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2VsZi5wcm9wZXJ0aWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgdmFyIHByb3AgPSBzZWxmLnByb3BlcnRpZXNbaV07XG4gICAgICAgICAgdmFyIF9uYW1lID0gcHJvcC5uYW1lO1xuICAgICAgICAgIHZhciBwYXJzZWRQcm9wID0gdGhpcy5wYXJzZShfbmFtZSwgdmFsdWUsIHRydWUpO1xuXG4gICAgICAgICAgaWYgKHBhcnNlZFByb3ApIHtcbiAgICAgICAgICAgIHByb3BzLnB1c2gocGFyc2VkUHJvcCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChzdHJpbmcobmFtZSkpIHtcbiAgICAgIC8vIHRoZW4gcGFyc2UgdGhlIHNpbmdsZSBwcm9wZXJ0eVxuICAgICAgdmFyIF9wYXJzZWRQcm9wID0gdGhpcy5wYXJzZShuYW1lLCB2YWx1ZSwgdHJ1ZSk7XG5cbiAgICAgIGlmIChfcGFyc2VkUHJvcCkge1xuICAgICAgICBwcm9wcy5wdXNoKF9wYXJzZWRQcm9wKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHBsYWluT2JqZWN0KG5hbWUpKSB7XG4gICAgICAvLyB0aGVuIHBhcnNlIGVhY2ggcHJvcGVydHlcbiAgICAgIHZhciBzcGVjaWZpZWRQcm9wcyA9IG5hbWU7XG4gICAgICB1cGRhdGVUcmFuc2l0aW9ucyA9IHZhbHVlO1xuICAgICAgdmFyIG5hbWVzID0gT2JqZWN0LmtleXMoc3BlY2lmaWVkUHJvcHMpO1xuXG4gICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgbmFtZXMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciBfbmFtZTIgPSBuYW1lc1tfaV07XG4gICAgICAgIHZhciBfdmFsdWUgPSBzcGVjaWZpZWRQcm9wc1tfbmFtZTJdO1xuXG4gICAgICAgIGlmIChfdmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIC8vIHRyeSBjYW1lbCBjYXNlIG5hbWUgdG9vXG4gICAgICAgICAgX3ZhbHVlID0gc3BlY2lmaWVkUHJvcHNbZGFzaDJjYW1lbChfbmFtZTIpXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChfdmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHZhciBfcGFyc2VkUHJvcDIgPSB0aGlzLnBhcnNlKF9uYW1lMiwgX3ZhbHVlLCB0cnVlKTtcblxuICAgICAgICAgIGlmIChfcGFyc2VkUHJvcDIpIHtcbiAgICAgICAgICAgIHByb3BzLnB1c2goX3BhcnNlZFByb3AyKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gY2FuJ3QgZG8gYW55dGhpbmcgd2l0aG91dCB3ZWxsIGRlZmluZWQgcHJvcGVydGllc1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gLy8gd2UndmUgZmFpbGVkIGlmIHRoZXJlIGFyZSBubyB2YWxpZCBwcm9wZXJ0aWVzXG5cblxuICAgIGlmIChwcm9wcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IC8vIG5vdywgYXBwbHkgdGhlIGJ5cGFzcyBwcm9wZXJ0aWVzIG9uIHRoZSBlbGVtZW50c1xuXG5cbiAgICB2YXIgcmV0ID0gZmFsc2U7IC8vIHJldHVybiB0cnVlIGlmIGF0IGxlYXN0IG9uZSBzdWNjZXNmdWwgYnlwYXNzIGFwcGxpZWRcblxuICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IGVsZXMubGVuZ3RoOyBfaTIrKykge1xuICAgICAgLy8gZm9yIGVhY2ggZWxlXG4gICAgICB2YXIgZWxlID0gZWxlc1tfaTJdO1xuICAgICAgdmFyIGRpZmZQcm9wcyA9IHt9O1xuICAgICAgdmFyIGRpZmZQcm9wID0gdm9pZCAwO1xuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHByb3BzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIC8vIGZvciBlYWNoIHByb3BcbiAgICAgICAgdmFyIF9wcm9wID0gcHJvcHNbal07XG5cbiAgICAgICAgaWYgKHVwZGF0ZVRyYW5zaXRpb25zKSB7XG4gICAgICAgICAgdmFyIHByZXZQcm9wID0gZWxlLnBzdHlsZShfcHJvcC5uYW1lKTtcbiAgICAgICAgICBkaWZmUHJvcCA9IGRpZmZQcm9wc1tfcHJvcC5uYW1lXSA9IHtcbiAgICAgICAgICAgIHByZXY6IHByZXZQcm9wXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldCA9IHRoaXMuYXBwbHlQYXJzZWRQcm9wZXJ0eShlbGUsIGNvcHkoX3Byb3ApKSB8fCByZXQ7XG5cbiAgICAgICAgaWYgKHVwZGF0ZVRyYW5zaXRpb25zKSB7XG4gICAgICAgICAgZGlmZlByb3AubmV4dCA9IGVsZS5wc3R5bGUoX3Byb3AubmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gZm9yIHByb3BzXG5cblxuICAgICAgaWYgKHJldCkge1xuICAgICAgICB0aGlzLnVwZGF0ZVN0eWxlSGludHMoZWxlKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHVwZGF0ZVRyYW5zaXRpb25zKSB7XG4gICAgICAgIHRoaXMudXBkYXRlVHJhbnNpdGlvbnMoZWxlLCBkaWZmUHJvcHMsIGlzQnlwYXNzKTtcbiAgICAgIH1cbiAgICB9IC8vIGZvciBlbGVzXG5cblxuICAgIHJldHVybiByZXQ7XG4gIH07IC8vIG9ubHkgdXNlZnVsIGluIHNwZWNpZmljIGNhc2VzIGxpa2UgYW5pbWF0aW9uXG5cblxuICBzdHlmbiQ3Lm92ZXJyaWRlQnlwYXNzID0gZnVuY3Rpb24gKGVsZXMsIG5hbWUsIHZhbHVlKSB7XG4gICAgbmFtZSA9IGNhbWVsMmRhc2gobmFtZSk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBlbGUgPSBlbGVzW2ldO1xuICAgICAgdmFyIHByb3AgPSBlbGUuX3ByaXZhdGUuc3R5bGVbbmFtZV07XG4gICAgICB2YXIgdHlwZSA9IHRoaXMucHJvcGVydGllc1tuYW1lXS50eXBlO1xuICAgICAgdmFyIGlzQ29sb3IgPSB0eXBlLmNvbG9yO1xuICAgICAgdmFyIGlzTXVsdGkgPSB0eXBlLm11dGlwbGU7XG4gICAgICB2YXIgb2xkVmFsdWUgPSAhcHJvcCA/IG51bGwgOiBwcm9wLnBmVmFsdWUgIT0gbnVsbCA/IHByb3AucGZWYWx1ZSA6IHByb3AudmFsdWU7XG5cbiAgICAgIGlmICghcHJvcCB8fCAhcHJvcC5ieXBhc3MpIHtcbiAgICAgICAgLy8gbmVlZCBhIGJ5cGFzcyBpZiBvbmUgZG9lc24ndCBleGlzdFxuICAgICAgICB0aGlzLmFwcGx5QnlwYXNzKGVsZSwgbmFtZSwgdmFsdWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcHJvcC52YWx1ZSA9IHZhbHVlO1xuXG4gICAgICAgIGlmIChwcm9wLnBmVmFsdWUgIT0gbnVsbCkge1xuICAgICAgICAgIHByb3AucGZWYWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQ29sb3IpIHtcbiAgICAgICAgICBwcm9wLnN0clZhbHVlID0gJ3JnYignICsgdmFsdWUuam9pbignLCcpICsgJyknO1xuICAgICAgICB9IGVsc2UgaWYgKGlzTXVsdGkpIHtcbiAgICAgICAgICBwcm9wLnN0clZhbHVlID0gdmFsdWUuam9pbignICcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHByb3Auc3RyVmFsdWUgPSAnJyArIHZhbHVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVTdHlsZUhpbnRzKGVsZSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuY2hlY2tUcmlnZ2VycyhlbGUsIG5hbWUsIG9sZFZhbHVlLCB2YWx1ZSk7XG4gICAgfVxuICB9O1xuXG4gIHN0eWZuJDcucmVtb3ZlQWxsQnlwYXNzZXMgPSBmdW5jdGlvbiAoZWxlcywgdXBkYXRlVHJhbnNpdGlvbnMpIHtcbiAgICByZXR1cm4gdGhpcy5yZW1vdmVCeXBhc3NlcyhlbGVzLCB0aGlzLnByb3BlcnR5TmFtZXMsIHVwZGF0ZVRyYW5zaXRpb25zKTtcbiAgfTtcblxuICBzdHlmbiQ3LnJlbW92ZUJ5cGFzc2VzID0gZnVuY3Rpb24gKGVsZXMsIHByb3BzLCB1cGRhdGVUcmFuc2l0aW9ucykge1xuICAgIHZhciBpc0J5cGFzcyA9IHRydWU7XG5cbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IGVsZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgIHZhciBlbGUgPSBlbGVzW2pdO1xuICAgICAgdmFyIGRpZmZQcm9wcyA9IHt9O1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHByb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBuYW1lID0gcHJvcHNbaV07XG4gICAgICAgIHZhciBwcm9wID0gdGhpcy5wcm9wZXJ0aWVzW25hbWVdO1xuICAgICAgICB2YXIgcHJldlByb3AgPSBlbGUucHN0eWxlKHByb3AubmFtZSk7XG5cbiAgICAgICAgaWYgKCFwcmV2UHJvcCB8fCAhcHJldlByb3AuYnlwYXNzKSB7XG4gICAgICAgICAgLy8gaWYgYSBieXBhc3MgZG9lc24ndCBleGlzdCBmb3IgdGhlIHByb3AsIG5vdGhpbmcgbmVlZHMgdG8gYmUgcmVtb3ZlZFxuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHZhbHVlID0gJyc7IC8vIGVtcHR5ID0+IHJlbW92ZSBieXBhc3NcblxuICAgICAgICB2YXIgcGFyc2VkUHJvcCA9IHRoaXMucGFyc2UobmFtZSwgdmFsdWUsIHRydWUpO1xuICAgICAgICB2YXIgZGlmZlByb3AgPSBkaWZmUHJvcHNbcHJvcC5uYW1lXSA9IHtcbiAgICAgICAgICBwcmV2OiBwcmV2UHJvcFxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmFwcGx5UGFyc2VkUHJvcGVydHkoZWxlLCBwYXJzZWRQcm9wKTtcbiAgICAgICAgZGlmZlByb3AubmV4dCA9IGVsZS5wc3R5bGUocHJvcC5uYW1lKTtcbiAgICAgIH0gLy8gZm9yIHByb3BzXG5cblxuICAgICAgdGhpcy51cGRhdGVTdHlsZUhpbnRzKGVsZSk7XG5cbiAgICAgIGlmICh1cGRhdGVUcmFuc2l0aW9ucykge1xuICAgICAgICB0aGlzLnVwZGF0ZVRyYW5zaXRpb25zKGVsZSwgZGlmZlByb3BzLCBpc0J5cGFzcyk7XG4gICAgICB9XG4gICAgfSAvLyBmb3IgZWxlc1xuXG4gIH07XG5cbiAgdmFyIHN0eWZuJDYgPSB7fTsgLy8gZ2V0cyB3aGF0IGFuIGVtIHNpemUgY29ycmVzcG9uZHMgdG8gaW4gcGl4ZWxzIHJlbGF0aXZlIHRvIGEgZG9tIGVsZW1lbnRcblxuICBzdHlmbiQ2LmdldEVtU2l6ZUluUGl4ZWxzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBweCA9IHRoaXMuY29udGFpbmVyQ3NzKCdmb250LXNpemUnKTtcblxuICAgIGlmIChweCAhPSBudWxsKSB7XG4gICAgICByZXR1cm4gcGFyc2VGbG9hdChweCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiAxOyAvLyBmb3IgaGVhZGxlc3NcbiAgICB9XG4gIH07IC8vIGdldHMgY3NzIHByb3BlcnR5IGZyb20gdGhlIGNvcmUgY29udGFpbmVyXG5cblxuICBzdHlmbiQ2LmNvbnRhaW5lckNzcyA9IGZ1bmN0aW9uIChwcm9wTmFtZSkge1xuICAgIHZhciBjeSA9IHRoaXMuX3ByaXZhdGUuY3k7XG4gICAgdmFyIGRvbUVsZW1lbnQgPSBjeS5jb250YWluZXIoKTtcbiAgICB2YXIgY29udGFpbmVyV2luZG93ID0gY3kud2luZG93KCk7XG5cbiAgICBpZiAoY29udGFpbmVyV2luZG93ICYmIGRvbUVsZW1lbnQgJiYgY29udGFpbmVyV2luZG93LmdldENvbXB1dGVkU3R5bGUpIHtcbiAgICAgIHJldHVybiBjb250YWluZXJXaW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShkb21FbGVtZW50KS5nZXRQcm9wZXJ0eVZhbHVlKHByb3BOYW1lKTtcbiAgICB9XG4gIH07XG5cbiAgdmFyIHN0eWZuJDUgPSB7fTsgLy8gZ2V0cyB0aGUgcmVuZGVyZWQgc3R5bGUgZm9yIGFuIGVsZW1lbnRcblxuICBzdHlmbiQ1LmdldFJlbmRlcmVkU3R5bGUgPSBmdW5jdGlvbiAoZWxlLCBwcm9wKSB7XG4gICAgaWYgKHByb3ApIHtcbiAgICAgIHJldHVybiB0aGlzLmdldFN0eWxlUHJvcGVydHlWYWx1ZShlbGUsIHByb3AsIHRydWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdGhpcy5nZXRSYXdTdHlsZShlbGUsIHRydWUpO1xuICAgIH1cbiAgfTsgLy8gZ2V0cyB0aGUgcmF3IHN0eWxlIGZvciBhbiBlbGVtZW50XG5cblxuICBzdHlmbiQ1LmdldFJhd1N0eWxlID0gZnVuY3Rpb24gKGVsZSwgaXNSZW5kZXJlZFZhbCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBlbGUgPSBlbGVbMF07IC8vIGluc3VyZSBpdCdzIGFuIGVsZW1lbnRcblxuICAgIGlmIChlbGUpIHtcbiAgICAgIHZhciByc3R5bGUgPSB7fTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzZWxmLnByb3BlcnRpZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHByb3AgPSBzZWxmLnByb3BlcnRpZXNbaV07XG4gICAgICAgIHZhciB2YWwgPSBzZWxmLmdldFN0eWxlUHJvcGVydHlWYWx1ZShlbGUsIHByb3AubmFtZSwgaXNSZW5kZXJlZFZhbCk7XG5cbiAgICAgICAgaWYgKHZhbCAhPSBudWxsKSB7XG4gICAgICAgICAgcnN0eWxlW3Byb3AubmFtZV0gPSB2YWw7XG4gICAgICAgICAgcnN0eWxlW2Rhc2gyY2FtZWwocHJvcC5uYW1lKV0gPSB2YWw7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJzdHlsZTtcbiAgICB9XG4gIH07XG5cbiAgc3R5Zm4kNS5nZXRJbmRleGVkU3R5bGUgPSBmdW5jdGlvbiAoZWxlLCBwcm9wZXJ0eSwgc3VicHJvcGVydHksIGluZGV4KSB7XG4gICAgdmFyIHBzdHlsZSA9IGVsZS5wc3R5bGUocHJvcGVydHkpW3N1YnByb3BlcnR5XVtpbmRleF07XG4gICAgcmV0dXJuIHBzdHlsZSAhPSBudWxsID8gcHN0eWxlIDogZWxlLmN5KCkuc3R5bGUoKS5nZXREZWZhdWx0UHJvcGVydHkocHJvcGVydHkpW3N1YnByb3BlcnR5XVswXTtcbiAgfTtcblxuICBzdHlmbiQ1LmdldFN0eWxlUHJvcGVydHlWYWx1ZSA9IGZ1bmN0aW9uIChlbGUsIHByb3BOYW1lLCBpc1JlbmRlcmVkVmFsKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGVsZSA9IGVsZVswXTsgLy8gaW5zdXJlIGl0J3MgYW4gZWxlbWVudFxuXG4gICAgaWYgKGVsZSkge1xuICAgICAgdmFyIHByb3AgPSBzZWxmLnByb3BlcnRpZXNbcHJvcE5hbWVdO1xuXG4gICAgICBpZiAocHJvcC5hbGlhcykge1xuICAgICAgICBwcm9wID0gcHJvcC5wb2ludHNUbztcbiAgICAgIH1cblxuICAgICAgdmFyIHR5cGUgPSBwcm9wLnR5cGU7XG4gICAgICB2YXIgc3R5bGVQcm9wID0gZWxlLnBzdHlsZShwcm9wLm5hbWUpO1xuXG4gICAgICBpZiAoc3R5bGVQcm9wKSB7XG4gICAgICAgIHZhciB2YWx1ZSA9IHN0eWxlUHJvcC52YWx1ZSxcbiAgICAgICAgICAgIHVuaXRzID0gc3R5bGVQcm9wLnVuaXRzLFxuICAgICAgICAgICAgc3RyVmFsdWUgPSBzdHlsZVByb3Auc3RyVmFsdWU7XG5cbiAgICAgICAgaWYgKGlzUmVuZGVyZWRWYWwgJiYgdHlwZS5udW1iZXIgJiYgdmFsdWUgIT0gbnVsbCAmJiBudW1iZXIkMSh2YWx1ZSkpIHtcbiAgICAgICAgICB2YXIgem9vbSA9IGVsZS5jeSgpLnpvb20oKTtcblxuICAgICAgICAgIHZhciBnZXRSZW5kZXJlZFZhbHVlID0gZnVuY3Rpb24gZ2V0UmVuZGVyZWRWYWx1ZSh2YWwpIHtcbiAgICAgICAgICAgIHJldHVybiB2YWwgKiB6b29tO1xuICAgICAgICAgIH07XG5cbiAgICAgICAgICB2YXIgZ2V0VmFsdWVTdHJpbmdXaXRoVW5pdHMgPSBmdW5jdGlvbiBnZXRWYWx1ZVN0cmluZ1dpdGhVbml0cyh2YWwsIHVuaXRzKSB7XG4gICAgICAgICAgICByZXR1cm4gZ2V0UmVuZGVyZWRWYWx1ZSh2YWwpICsgdW5pdHM7XG4gICAgICAgICAgfTtcblxuICAgICAgICAgIHZhciBpc0FycmF5VmFsdWUgPSBhcnJheSh2YWx1ZSk7XG4gICAgICAgICAgdmFyIGhhdmVVbml0cyA9IGlzQXJyYXlWYWx1ZSA/IHVuaXRzLmV2ZXJ5KGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gdSAhPSBudWxsO1xuICAgICAgICAgIH0pIDogdW5pdHMgIT0gbnVsbDtcblxuICAgICAgICAgIGlmIChoYXZlVW5pdHMpIHtcbiAgICAgICAgICAgIGlmIChpc0FycmF5VmFsdWUpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlLm1hcChmdW5jdGlvbiAodiwgaSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBnZXRWYWx1ZVN0cmluZ1dpdGhVbml0cyh2LCB1bml0c1tpXSk7XG4gICAgICAgICAgICAgIH0pLmpvaW4oJyAnKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHJldHVybiBnZXRWYWx1ZVN0cmluZ1dpdGhVbml0cyh2YWx1ZSwgdW5pdHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoaXNBcnJheVZhbHVlKSB7XG4gICAgICAgICAgICAgIHJldHVybiB2YWx1ZS5tYXAoZnVuY3Rpb24gKHYpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3RyaW5nKHYpID8gdiA6ICcnICsgZ2V0UmVuZGVyZWRWYWx1ZSh2KTtcbiAgICAgICAgICAgICAgfSkuam9pbignICcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcmV0dXJuICcnICsgZ2V0UmVuZGVyZWRWYWx1ZSh2YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHN0clZhbHVlICE9IG51bGwpIHtcbiAgICAgICAgICByZXR1cm4gc3RyVmFsdWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9O1xuXG4gIHN0eWZuJDUuZ2V0QW5pbWF0aW9uU3RhcnRTdHlsZSA9IGZ1bmN0aW9uIChlbGUsIGFuaVByb3BzKSB7XG4gICAgdmFyIHJzdHlsZSA9IHt9O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhbmlQcm9wcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGFuaVByb3AgPSBhbmlQcm9wc1tpXTtcbiAgICAgIHZhciBuYW1lID0gYW5pUHJvcC5uYW1lO1xuICAgICAgdmFyIHN0eWxlUHJvcCA9IGVsZS5wc3R5bGUobmFtZSk7XG5cbiAgICAgIGlmIChzdHlsZVByb3AgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAvLyB0aGVuIG1ha2UgYSBwcm9wIG9mIGl0XG4gICAgICAgIGlmIChwbGFpbk9iamVjdChzdHlsZVByb3ApKSB7XG4gICAgICAgICAgc3R5bGVQcm9wID0gdGhpcy5wYXJzZShuYW1lLCBzdHlsZVByb3Auc3RyVmFsdWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHN0eWxlUHJvcCA9IHRoaXMucGFyc2UobmFtZSwgc3R5bGVQcm9wKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoc3R5bGVQcm9wKSB7XG4gICAgICAgIHJzdHlsZVtuYW1lXSA9IHN0eWxlUHJvcDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcnN0eWxlO1xuICB9O1xuXG4gIHN0eWZuJDUuZ2V0UHJvcHNMaXN0ID0gZnVuY3Rpb24gKHByb3BzT2JqKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciByc3R5bGUgPSBbXTtcbiAgICB2YXIgc3R5bGUgPSBwcm9wc09iajtcbiAgICB2YXIgcHJvcHMgPSBzZWxmLnByb3BlcnRpZXM7XG5cbiAgICBpZiAoc3R5bGUpIHtcbiAgICAgIHZhciBuYW1lcyA9IE9iamVjdC5rZXlzKHN0eWxlKTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuYW1lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgbmFtZSA9IG5hbWVzW2ldO1xuICAgICAgICB2YXIgdmFsID0gc3R5bGVbbmFtZV07XG4gICAgICAgIHZhciBwcm9wID0gcHJvcHNbbmFtZV0gfHwgcHJvcHNbY2FtZWwyZGFzaChuYW1lKV07XG4gICAgICAgIHZhciBzdHlsZVByb3AgPSB0aGlzLnBhcnNlKHByb3AubmFtZSwgdmFsKTtcblxuICAgICAgICBpZiAoc3R5bGVQcm9wKSB7XG4gICAgICAgICAgcnN0eWxlLnB1c2goc3R5bGVQcm9wKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByc3R5bGU7XG4gIH07XG5cbiAgc3R5Zm4kNS5nZXROb25EZWZhdWx0UHJvcGVydGllc0hhc2ggPSBmdW5jdGlvbiAoZWxlLCBwcm9wTmFtZXMsIHNlZWQpIHtcbiAgICB2YXIgaGFzaCA9IHNlZWQuc2xpY2UoKTtcbiAgICB2YXIgbmFtZSwgdmFsLCBzdHJWYWwsIGNoVmFsO1xuICAgIHZhciBpLCBqO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IHByb3BOYW1lcy5sZW5ndGg7IGkrKykge1xuICAgICAgbmFtZSA9IHByb3BOYW1lc1tpXTtcbiAgICAgIHZhbCA9IGVsZS5wc3R5bGUobmFtZSwgZmFsc2UpO1xuXG4gICAgICBpZiAodmFsID09IG51bGwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9IGVsc2UgaWYgKHZhbC5wZlZhbHVlICE9IG51bGwpIHtcbiAgICAgICAgaGFzaFswXSA9IGhhc2hJbnQoY2hWYWwsIGhhc2hbMF0pO1xuICAgICAgICBoYXNoWzFdID0gaGFzaEludEFsdChjaFZhbCwgaGFzaFsxXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzdHJWYWwgPSB2YWwuc3RyVmFsdWU7XG5cbiAgICAgICAgZm9yIChqID0gMDsgaiA8IHN0clZhbC5sZW5ndGg7IGorKykge1xuICAgICAgICAgIGNoVmFsID0gc3RyVmFsLmNoYXJDb2RlQXQoaik7XG4gICAgICAgICAgaGFzaFswXSA9IGhhc2hJbnQoY2hWYWwsIGhhc2hbMF0pO1xuICAgICAgICAgIGhhc2hbMV0gPSBoYXNoSW50QWx0KGNoVmFsLCBoYXNoWzFdKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBoYXNoO1xuICB9O1xuXG4gIHN0eWZuJDUuZ2V0UHJvcGVydGllc0hhc2ggPSBzdHlmbiQ1LmdldE5vbkRlZmF1bHRQcm9wZXJ0aWVzSGFzaDtcblxuICB2YXIgc3R5Zm4kNCA9IHt9O1xuXG4gIHN0eWZuJDQuYXBwZW5kRnJvbUpzb24gPSBmdW5jdGlvbiAoanNvbikge1xuICAgIHZhciBzdHlsZSA9IHRoaXM7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGpzb24ubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBjb250ZXh0ID0ganNvbltpXTtcbiAgICAgIHZhciBzZWxlY3RvciA9IGNvbnRleHQuc2VsZWN0b3I7XG4gICAgICB2YXIgcHJvcHMgPSBjb250ZXh0LnN0eWxlIHx8IGNvbnRleHQuY3NzO1xuICAgICAgdmFyIG5hbWVzID0gT2JqZWN0LmtleXMocHJvcHMpO1xuICAgICAgc3R5bGUuc2VsZWN0b3Ioc2VsZWN0b3IpOyAvLyBhcHBseSBzZWxlY3RvclxuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IG5hbWVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHZhciBuYW1lID0gbmFtZXNbal07XG4gICAgICAgIHZhciB2YWx1ZSA9IHByb3BzW25hbWVdO1xuICAgICAgICBzdHlsZS5jc3MobmFtZSwgdmFsdWUpOyAvLyBhcHBseSBwcm9wZXJ0eVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBzdHlsZTtcbiAgfTsgLy8gYWNjZXNzaWJsZSBjeS5zdHlsZSgpIGZ1bmN0aW9uXG5cblxuICBzdHlmbiQ0LmZyb21Kc29uID0gZnVuY3Rpb24gKGpzb24pIHtcbiAgICB2YXIgc3R5bGUgPSB0aGlzO1xuICAgIHN0eWxlLnJlc2V0VG9EZWZhdWx0KCk7XG4gICAgc3R5bGUuYXBwZW5kRnJvbUpzb24oanNvbik7XG4gICAgcmV0dXJuIHN0eWxlO1xuICB9OyAvLyBnZXQganNvbiBmcm9tIGN5LnN0eWxlKCkgYXBpXG5cblxuICBzdHlmbiQ0Lmpzb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGpzb24gPSBbXTtcblxuICAgIGZvciAodmFyIGkgPSB0aGlzLmRlZmF1bHRMZW5ndGg7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgY3h0ID0gdGhpc1tpXTtcbiAgICAgIHZhciBzZWxlY3RvciA9IGN4dC5zZWxlY3RvcjtcbiAgICAgIHZhciBwcm9wcyA9IGN4dC5wcm9wZXJ0aWVzO1xuICAgICAgdmFyIGNzcyA9IHt9O1xuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHByb3BzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHZhciBwcm9wID0gcHJvcHNbal07XG4gICAgICAgIGNzc1twcm9wLm5hbWVdID0gcHJvcC5zdHJWYWx1ZTtcbiAgICAgIH1cblxuICAgICAganNvbi5wdXNoKHtcbiAgICAgICAgc2VsZWN0b3I6ICFzZWxlY3RvciA/ICdjb3JlJyA6IHNlbGVjdG9yLnRvU3RyaW5nKCksXG4gICAgICAgIHN0eWxlOiBjc3NcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBqc29uO1xuICB9O1xuXG4gIHZhciBzdHlmbiQzID0ge307XG5cbiAgc3R5Zm4kMy5hcHBlbmRGcm9tU3RyaW5nID0gZnVuY3Rpb24gKHN0cmluZykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgc3R5bGUgPSB0aGlzO1xuICAgIHZhciByZW1haW5pbmcgPSAnJyArIHN0cmluZztcbiAgICB2YXIgc2VsQW5kQmxvY2tTdHI7XG4gICAgdmFyIGJsb2NrUmVtO1xuICAgIHZhciBwcm9wQW5kVmFsU3RyOyAvLyByZW1vdmUgY29tbWVudHMgZnJvbSB0aGUgc3R5bGUgc3RyaW5nXG5cbiAgICByZW1haW5pbmcgPSByZW1haW5pbmcucmVwbGFjZSgvWy9dWypdKFxcc3wuKSs/WypdWy9dL2csICcnKTtcblxuICAgIGZ1bmN0aW9uIHJlbW92ZVNlbEFuZEJsb2NrRnJvbVJlbWFpbmluZygpIHtcbiAgICAgIC8vIHJlbW92ZSB0aGUgcGFyc2VkIHNlbGVjdG9yIGFuZCBibG9jayBmcm9tIHRoZSByZW1haW5pbmcgdGV4dCB0byBwYXJzZVxuICAgICAgaWYgKHJlbWFpbmluZy5sZW5ndGggPiBzZWxBbmRCbG9ja1N0ci5sZW5ndGgpIHtcbiAgICAgICAgcmVtYWluaW5nID0gcmVtYWluaW5nLnN1YnN0cihzZWxBbmRCbG9ja1N0ci5sZW5ndGgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVtYWluaW5nID0gJyc7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVtb3ZlUHJvcEFuZFZhbEZyb21SZW0oKSB7XG4gICAgICAvLyByZW1vdmUgdGhlIHBhcnNlZCBwcm9wZXJ0eSBhbmQgdmFsdWUgZnJvbSB0aGUgcmVtYWluaW5nIGJsb2NrIHRleHQgdG8gcGFyc2VcbiAgICAgIGlmIChibG9ja1JlbS5sZW5ndGggPiBwcm9wQW5kVmFsU3RyLmxlbmd0aCkge1xuICAgICAgICBibG9ja1JlbSA9IGJsb2NrUmVtLnN1YnN0cihwcm9wQW5kVmFsU3RyLmxlbmd0aCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBibG9ja1JlbSA9ICcnO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAoOzspIHtcbiAgICAgIHZhciBub3RoaW5nTGVmdFRvUGFyc2UgPSByZW1haW5pbmcubWF0Y2goL15cXHMqJC8pO1xuXG4gICAgICBpZiAobm90aGluZ0xlZnRUb1BhcnNlKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICB2YXIgc2VsQW5kQmxvY2sgPSByZW1haW5pbmcubWF0Y2goL15cXHMqKCg/Oi58XFxzKSs/KVxccypcXHsoKD86LnxcXHMpKz8pXFx9Lyk7XG5cbiAgICAgIGlmICghc2VsQW5kQmxvY2spIHtcbiAgICAgICAgd2FybignSGFsdGluZyBzdHlsZXNoZWV0IHBhcnNpbmc6IFN0cmluZyBzdHlsZXNoZWV0IGNvbnRhaW5zIG1vcmUgdG8gcGFyc2UgYnV0IG5vIHNlbGVjdG9yIGFuZCBibG9jayBmb3VuZCBpbjogJyArIHJlbWFpbmluZyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICBzZWxBbmRCbG9ja1N0ciA9IHNlbEFuZEJsb2NrWzBdOyAvLyBwYXJzZSB0aGUgc2VsZWN0b3JcblxuICAgICAgdmFyIHNlbGVjdG9yU3RyID0gc2VsQW5kQmxvY2tbMV07XG5cbiAgICAgIGlmIChzZWxlY3RvclN0ciAhPT0gJ2NvcmUnKSB7XG4gICAgICAgIHZhciBzZWxlY3RvciA9IG5ldyBTZWxlY3RvcihzZWxlY3RvclN0cik7XG5cbiAgICAgICAgaWYgKHNlbGVjdG9yLmludmFsaWQpIHtcbiAgICAgICAgICB3YXJuKCdTa2lwcGluZyBwYXJzaW5nIG9mIGJsb2NrOiBJbnZhbGlkIHNlbGVjdG9yIGZvdW5kIGluIHN0cmluZyBzdHlsZXNoZWV0OiAnICsgc2VsZWN0b3JTdHIpOyAvLyBza2lwIHRoaXMgc2VsZWN0b3IgYW5kIGJsb2NrXG5cbiAgICAgICAgICByZW1vdmVTZWxBbmRCbG9ja0Zyb21SZW1haW5pbmcoKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfSAvLyBwYXJzZSB0aGUgYmxvY2sgb2YgcHJvcGVydGllcyBhbmQgdmFsdWVzXG5cblxuICAgICAgdmFyIGJsb2NrU3RyID0gc2VsQW5kQmxvY2tbMl07XG4gICAgICB2YXIgaW52YWxpZEJsb2NrID0gZmFsc2U7XG4gICAgICBibG9ja1JlbSA9IGJsb2NrU3RyO1xuICAgICAgdmFyIHByb3BzID0gW107XG5cbiAgICAgIGZvciAoOzspIHtcbiAgICAgICAgdmFyIF9ub3RoaW5nTGVmdFRvUGFyc2UgPSBibG9ja1JlbS5tYXRjaCgvXlxccyokLyk7XG5cbiAgICAgICAgaWYgKF9ub3RoaW5nTGVmdFRvUGFyc2UpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBwcm9wQW5kVmFsID0gYmxvY2tSZW0ubWF0Y2goL15cXHMqKC4rPylcXHMqOlxccyooLis/KSg/Olxccyo7fFxccyokKS8pO1xuXG4gICAgICAgIGlmICghcHJvcEFuZFZhbCkge1xuICAgICAgICAgIHdhcm4oJ1NraXBwaW5nIHBhcnNpbmcgb2YgYmxvY2s6IEludmFsaWQgZm9ybWF0dGluZyBvZiBzdHlsZSBwcm9wZXJ0eSBhbmQgdmFsdWUgZGVmaW5pdGlvbnMgZm91bmQgaW46JyArIGJsb2NrU3RyKTtcbiAgICAgICAgICBpbnZhbGlkQmxvY2sgPSB0cnVlO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgcHJvcEFuZFZhbFN0ciA9IHByb3BBbmRWYWxbMF07XG4gICAgICAgIHZhciBwcm9wU3RyID0gcHJvcEFuZFZhbFsxXTtcbiAgICAgICAgdmFyIHZhbFN0ciA9IHByb3BBbmRWYWxbMl07XG4gICAgICAgIHZhciBwcm9wID0gc2VsZi5wcm9wZXJ0aWVzW3Byb3BTdHJdO1xuXG4gICAgICAgIGlmICghcHJvcCkge1xuICAgICAgICAgIHdhcm4oJ1NraXBwaW5nIHByb3BlcnR5OiBJbnZhbGlkIHByb3BlcnR5IG5hbWUgaW46ICcgKyBwcm9wQW5kVmFsU3RyKTsgLy8gc2tpcCB0aGlzIHByb3BlcnR5IGluIHRoZSBibG9ja1xuXG4gICAgICAgICAgcmVtb3ZlUHJvcEFuZFZhbEZyb21SZW0oKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBwYXJzZWRQcm9wID0gc3R5bGUucGFyc2UocHJvcFN0ciwgdmFsU3RyKTtcblxuICAgICAgICBpZiAoIXBhcnNlZFByb3ApIHtcbiAgICAgICAgICB3YXJuKCdTa2lwcGluZyBwcm9wZXJ0eTogSW52YWxpZCBwcm9wZXJ0eSBkZWZpbml0aW9uIGluOiAnICsgcHJvcEFuZFZhbFN0cik7IC8vIHNraXAgdGhpcyBwcm9wZXJ0eSBpbiB0aGUgYmxvY2tcblxuICAgICAgICAgIHJlbW92ZVByb3BBbmRWYWxGcm9tUmVtKCk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBwcm9wcy5wdXNoKHtcbiAgICAgICAgICBuYW1lOiBwcm9wU3RyLFxuICAgICAgICAgIHZhbDogdmFsU3RyXG4gICAgICAgIH0pO1xuICAgICAgICByZW1vdmVQcm9wQW5kVmFsRnJvbVJlbSgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoaW52YWxpZEJsb2NrKSB7XG4gICAgICAgIHJlbW92ZVNlbEFuZEJsb2NrRnJvbVJlbWFpbmluZygpO1xuICAgICAgICBicmVhaztcbiAgICAgIH0gLy8gcHV0IHRoZSBwYXJzZWQgYmxvY2sgaW4gdGhlIHN0eWxlXG5cblxuICAgICAgc3R5bGUuc2VsZWN0b3Ioc2VsZWN0b3JTdHIpO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHByb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBfcHJvcCA9IHByb3BzW2ldO1xuICAgICAgICBzdHlsZS5jc3MoX3Byb3AubmFtZSwgX3Byb3AudmFsKTtcbiAgICAgIH1cblxuICAgICAgcmVtb3ZlU2VsQW5kQmxvY2tGcm9tUmVtYWluaW5nKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHN0eWxlO1xuICB9O1xuXG4gIHN0eWZuJDMuZnJvbVN0cmluZyA9IGZ1bmN0aW9uIChzdHJpbmcpIHtcbiAgICB2YXIgc3R5bGUgPSB0aGlzO1xuICAgIHN0eWxlLnJlc2V0VG9EZWZhdWx0KCk7XG4gICAgc3R5bGUuYXBwZW5kRnJvbVN0cmluZyhzdHJpbmcpO1xuICAgIHJldHVybiBzdHlsZTtcbiAgfTtcblxuICB2YXIgc3R5Zm4kMiA9IHt9O1xuXG4gIChmdW5jdGlvbiAoKSB7XG4gICAgdmFyIG51bWJlciQxID0gbnVtYmVyO1xuICAgIHZhciByZ2JhID0gcmdiYU5vQmFja1JlZnM7XG4gICAgdmFyIGhzbGEgPSBoc2xhTm9CYWNrUmVmcztcbiAgICB2YXIgaGV4MyQxID0gaGV4MztcbiAgICB2YXIgaGV4NiQxID0gaGV4NjtcblxuICAgIHZhciBkYXRhID0gZnVuY3Rpb24gZGF0YShwcmVmaXgpIHtcbiAgICAgIHJldHVybiAnXicgKyBwcmVmaXggKyAnXFxcXHMqXFxcXChcXFxccyooW1xcXFx3XFxcXC5dKylcXFxccypcXFxcKSQnO1xuICAgIH07XG5cbiAgICB2YXIgbWFwRGF0YSA9IGZ1bmN0aW9uIG1hcERhdGEocHJlZml4KSB7XG4gICAgICB2YXIgbWFwQXJnID0gbnVtYmVyJDEgKyAnfFxcXFx3K3wnICsgcmdiYSArICd8JyArIGhzbGEgKyAnfCcgKyBoZXgzJDEgKyAnfCcgKyBoZXg2JDE7XG4gICAgICByZXR1cm4gJ14nICsgcHJlZml4ICsgJ1xcXFxzKlxcXFwoKFtcXFxcd1xcXFwuXSspXFxcXHMqXFxcXCxcXFxccyooJyArIG51bWJlciQxICsgJylcXFxccypcXFxcLFxcXFxzKignICsgbnVtYmVyJDEgKyAnKVxcXFxzKixcXFxccyooJyArIG1hcEFyZyArICcpXFxcXHMqXFxcXCxcXFxccyooJyArIG1hcEFyZyArICcpXFxcXCkkJztcbiAgICB9O1xuXG4gICAgdmFyIHVybFJlZ2V4ZXMgPSBbJ151cmxcXFxccypcXFxcKFxcXFxzKltcXCdcIl0/KC4rPylbXFwnXCJdP1xcXFxzKlxcXFwpJCcsICdeKG5vbmUpJCcsICdeKC4rKSQnXTsgLy8gZWFjaCB2aXN1YWwgc3R5bGUgcHJvcGVydHkgaGFzIGEgdHlwZSBhbmQgbmVlZHMgdG8gYmUgdmFsaWRhdGVkIGFjY29yZGluZyB0byBpdFxuXG4gICAgc3R5Zm4kMi50eXBlcyA9IHtcbiAgICAgIHRpbWU6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBtaW46IDAsXG4gICAgICAgIHVuaXRzOiAnc3xtcycsXG4gICAgICAgIGltcGxpY2l0VW5pdHM6ICdtcydcbiAgICAgIH0sXG4gICAgICBwZXJjZW50OiB7XG4gICAgICAgIG51bWJlcjogdHJ1ZSxcbiAgICAgICAgbWluOiAwLFxuICAgICAgICBtYXg6IDEwMCxcbiAgICAgICAgdW5pdHM6ICclJyxcbiAgICAgICAgaW1wbGljaXRVbml0czogJyUnXG4gICAgICB9LFxuICAgICAgcGVyY2VudGFnZXM6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBtaW46IDAsXG4gICAgICAgIG1heDogMTAwLFxuICAgICAgICB1bml0czogJyUnLFxuICAgICAgICBpbXBsaWNpdFVuaXRzOiAnJScsXG4gICAgICAgIG11bHRpcGxlOiB0cnVlXG4gICAgICB9LFxuICAgICAgemVyb09uZU51bWJlcjoge1xuICAgICAgICBudW1iZXI6IHRydWUsXG4gICAgICAgIG1pbjogMCxcbiAgICAgICAgbWF4OiAxLFxuICAgICAgICB1bml0bGVzczogdHJ1ZVxuICAgICAgfSxcbiAgICAgIHplcm9PbmVOdW1iZXJzOiB7XG4gICAgICAgIG51bWJlcjogdHJ1ZSxcbiAgICAgICAgbWluOiAwLFxuICAgICAgICBtYXg6IDEsXG4gICAgICAgIHVuaXRsZXNzOiB0cnVlLFxuICAgICAgICBtdWx0aXBsZTogdHJ1ZVxuICAgICAgfSxcbiAgICAgIG5PbmVPbmVOdW1iZXI6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBtaW46IC0xLFxuICAgICAgICBtYXg6IDEsXG4gICAgICAgIHVuaXRsZXNzOiB0cnVlXG4gICAgICB9LFxuICAgICAgbm9uTmVnYXRpdmVJbnQ6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBtaW46IDAsXG4gICAgICAgIGludGVnZXI6IHRydWUsXG4gICAgICAgIHVuaXRsZXNzOiB0cnVlXG4gICAgICB9LFxuICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgZW51bXM6IFsncGFyZW50JywgJ29yaWdpbiddXG4gICAgICB9LFxuICAgICAgbm9kZVNpemU6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBtaW46IDAsXG4gICAgICAgIGVudW1zOiBbJ2xhYmVsJ11cbiAgICAgIH0sXG4gICAgICBudW1iZXI6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICB1bml0bGVzczogdHJ1ZVxuICAgICAgfSxcbiAgICAgIG51bWJlcnM6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICB1bml0bGVzczogdHJ1ZSxcbiAgICAgICAgbXVsdGlwbGU6IHRydWVcbiAgICAgIH0sXG4gICAgICBwb3NpdGl2ZU51bWJlcjoge1xuICAgICAgICBudW1iZXI6IHRydWUsXG4gICAgICAgIHVuaXRsZXNzOiB0cnVlLFxuICAgICAgICBtaW46IDAsXG4gICAgICAgIHN0cmljdE1pbjogdHJ1ZVxuICAgICAgfSxcbiAgICAgIHNpemU6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBtaW46IDBcbiAgICAgIH0sXG4gICAgICBiaWRpcmVjdGlvbmFsU2l6ZToge1xuICAgICAgICBudW1iZXI6IHRydWVcbiAgICAgIH0sXG4gICAgICAvLyBhbGxvd3MgbmVnYXRpdmVcbiAgICAgIGJpZGlyZWN0aW9uYWxTaXplTWF5YmVQZXJjZW50OiB7XG4gICAgICAgIG51bWJlcjogdHJ1ZSxcbiAgICAgICAgYWxsb3dQZXJjZW50OiB0cnVlXG4gICAgICB9LFxuICAgICAgLy8gYWxsb3dzIG5lZ2F0aXZlXG4gICAgICBiaWRpcmVjdGlvbmFsU2l6ZXM6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBtdWx0aXBsZTogdHJ1ZVxuICAgICAgfSxcbiAgICAgIC8vIGFsbG93cyBuZWdhdGl2ZVxuICAgICAgc2l6ZU1heWJlUGVyY2VudDoge1xuICAgICAgICBudW1iZXI6IHRydWUsXG4gICAgICAgIG1pbjogMCxcbiAgICAgICAgYWxsb3dQZXJjZW50OiB0cnVlXG4gICAgICB9LFxuICAgICAgYXhpc0RpcmVjdGlvbjoge1xuICAgICAgICBlbnVtczogWydob3Jpem9udGFsJywgJ2xlZnR3YXJkJywgJ3JpZ2h0d2FyZCcsICd2ZXJ0aWNhbCcsICd1cHdhcmQnLCAnZG93bndhcmQnLCAnYXV0byddXG4gICAgICB9LFxuICAgICAgcGFkZGluZ1JlbGF0aXZlVG86IHtcbiAgICAgICAgZW51bXM6IFsnd2lkdGgnLCAnaGVpZ2h0JywgJ2F2ZXJhZ2UnLCAnbWluJywgJ21heCddXG4gICAgICB9LFxuICAgICAgYmdXSDoge1xuICAgICAgICBudW1iZXI6IHRydWUsXG4gICAgICAgIG1pbjogMCxcbiAgICAgICAgYWxsb3dQZXJjZW50OiB0cnVlLFxuICAgICAgICBlbnVtczogWydhdXRvJ10sXG4gICAgICAgIG11bHRpcGxlOiB0cnVlXG4gICAgICB9LFxuICAgICAgYmdQb3M6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBhbGxvd1BlcmNlbnQ6IHRydWUsXG4gICAgICAgIG11bHRpcGxlOiB0cnVlXG4gICAgICB9LFxuICAgICAgYmdSZWxhdGl2ZVRvOiB7XG4gICAgICAgIGVudW1zOiBbJ2lubmVyJywgJ2luY2x1ZGUtcGFkZGluZyddLFxuICAgICAgICBtdWx0aXBsZTogdHJ1ZVxuICAgICAgfSxcbiAgICAgIGJnUmVwZWF0OiB7XG4gICAgICAgIGVudW1zOiBbJ3JlcGVhdCcsICdyZXBlYXQteCcsICdyZXBlYXQteScsICduby1yZXBlYXQnXSxcbiAgICAgICAgbXVsdGlwbGU6IHRydWVcbiAgICAgIH0sXG4gICAgICBiZ0ZpdDoge1xuICAgICAgICBlbnVtczogWydub25lJywgJ2NvbnRhaW4nLCAnY292ZXInXSxcbiAgICAgICAgbXVsdGlwbGU6IHRydWVcbiAgICAgIH0sXG4gICAgICBiZ0Nyb3NzT3JpZ2luOiB7XG4gICAgICAgIGVudW1zOiBbJ2Fub255bW91cycsICd1c2UtY3JlZGVudGlhbHMnLCAnbnVsbCddLFxuICAgICAgICBtdWx0aXBsZTogdHJ1ZVxuICAgICAgfSxcbiAgICAgIGJnQ2xpcDoge1xuICAgICAgICBlbnVtczogWydub25lJywgJ25vZGUnXSxcbiAgICAgICAgbXVsdGlwbGU6IHRydWVcbiAgICAgIH0sXG4gICAgICBiZ0NvbnRhaW5tZW50OiB7XG4gICAgICAgIGVudW1zOiBbJ2luc2lkZScsICdvdmVyJ10sXG4gICAgICAgIG11bHRpcGxlOiB0cnVlXG4gICAgICB9LFxuICAgICAgY29sb3I6IHtcbiAgICAgICAgY29sb3I6IHRydWVcbiAgICAgIH0sXG4gICAgICBjb2xvcnM6IHtcbiAgICAgICAgY29sb3I6IHRydWUsXG4gICAgICAgIG11bHRpcGxlOiB0cnVlXG4gICAgICB9LFxuICAgICAgZmlsbDoge1xuICAgICAgICBlbnVtczogWydzb2xpZCcsICdsaW5lYXItZ3JhZGllbnQnLCAncmFkaWFsLWdyYWRpZW50J11cbiAgICAgIH0sXG4gICAgICBib29sOiB7XG4gICAgICAgIGVudW1zOiBbJ3llcycsICdubyddXG4gICAgICB9LFxuICAgICAgYm9vbHM6IHtcbiAgICAgICAgZW51bXM6IFsneWVzJywgJ25vJ10sXG4gICAgICAgIG11bHRpcGxlOiB0cnVlXG4gICAgICB9LFxuICAgICAgbGluZVN0eWxlOiB7XG4gICAgICAgIGVudW1zOiBbJ3NvbGlkJywgJ2RvdHRlZCcsICdkYXNoZWQnXVxuICAgICAgfSxcbiAgICAgIGxpbmVDYXA6IHtcbiAgICAgICAgZW51bXM6IFsnYnV0dCcsICdyb3VuZCcsICdzcXVhcmUnXVxuICAgICAgfSxcbiAgICAgIGJvcmRlclN0eWxlOiB7XG4gICAgICAgIGVudW1zOiBbJ3NvbGlkJywgJ2RvdHRlZCcsICdkYXNoZWQnLCAnZG91YmxlJ11cbiAgICAgIH0sXG4gICAgICBjdXJ2ZVN0eWxlOiB7XG4gICAgICAgIGVudW1zOiBbJ2JlemllcicsICd1bmJ1bmRsZWQtYmV6aWVyJywgJ2hheXN0YWNrJywgJ3NlZ21lbnRzJywgJ3N0cmFpZ2h0JywgJ3N0cmFpZ2h0LXRyaWFuZ2xlJywgJ3RheGknXVxuICAgICAgfSxcbiAgICAgIGZvbnRGYW1pbHk6IHtcbiAgICAgICAgcmVnZXg6ICdeKFtcXFxcdy0gXFxcXFwiXSsoPzpcXFxccyosXFxcXHMqW1xcXFx3LSBcXFxcXCJdKykqKSQnXG4gICAgICB9LFxuICAgICAgZm9udFN0eWxlOiB7XG4gICAgICAgIGVudW1zOiBbJ2l0YWxpYycsICdub3JtYWwnLCAnb2JsaXF1ZSddXG4gICAgICB9LFxuICAgICAgZm9udFdlaWdodDoge1xuICAgICAgICBlbnVtczogWydub3JtYWwnLCAnYm9sZCcsICdib2xkZXInLCAnbGlnaHRlcicsICcxMDAnLCAnMjAwJywgJzMwMCcsICc0MDAnLCAnNTAwJywgJzYwMCcsICc4MDAnLCAnOTAwJywgMTAwLCAyMDAsIDMwMCwgNDAwLCA1MDAsIDYwMCwgNzAwLCA4MDAsIDkwMF1cbiAgICAgIH0sXG4gICAgICB0ZXh0RGVjb3JhdGlvbjoge1xuICAgICAgICBlbnVtczogWydub25lJywgJ3VuZGVybGluZScsICdvdmVybGluZScsICdsaW5lLXRocm91Z2gnXVxuICAgICAgfSxcbiAgICAgIHRleHRUcmFuc2Zvcm06IHtcbiAgICAgICAgZW51bXM6IFsnbm9uZScsICd1cHBlcmNhc2UnLCAnbG93ZXJjYXNlJ11cbiAgICAgIH0sXG4gICAgICB0ZXh0V3JhcDoge1xuICAgICAgICBlbnVtczogWydub25lJywgJ3dyYXAnLCAnZWxsaXBzaXMnXVxuICAgICAgfSxcbiAgICAgIHRleHRPdmVyZmxvd1dyYXA6IHtcbiAgICAgICAgZW51bXM6IFsnd2hpdGVzcGFjZScsICdhbnl3aGVyZSddXG4gICAgICB9LFxuICAgICAgdGV4dEJhY2tncm91bmRTaGFwZToge1xuICAgICAgICBlbnVtczogWydyZWN0YW5nbGUnLCAncm91bmRyZWN0YW5nbGUnLCAncm91bmQtcmVjdGFuZ2xlJ11cbiAgICAgIH0sXG4gICAgICBub2RlU2hhcGU6IHtcbiAgICAgICAgZW51bXM6IFsncmVjdGFuZ2xlJywgJ3JvdW5kcmVjdGFuZ2xlJywgJ3JvdW5kLXJlY3RhbmdsZScsICdjdXRyZWN0YW5nbGUnLCAnY3V0LXJlY3RhbmdsZScsICdib3R0b21yb3VuZHJlY3RhbmdsZScsICdib3R0b20tcm91bmQtcmVjdGFuZ2xlJywgJ2JhcnJlbCcsICdlbGxpcHNlJywgJ3RyaWFuZ2xlJywgJ3JvdW5kLXRyaWFuZ2xlJywgJ3NxdWFyZScsICdwZW50YWdvbicsICdyb3VuZC1wZW50YWdvbicsICdoZXhhZ29uJywgJ3JvdW5kLWhleGFnb24nLCAnY29uY2F2ZWhleGFnb24nLCAnY29uY2F2ZS1oZXhhZ29uJywgJ2hlcHRhZ29uJywgJ3JvdW5kLWhlcHRhZ29uJywgJ29jdGFnb24nLCAncm91bmQtb2N0YWdvbicsICd0YWcnLCAncm91bmQtdGFnJywgJ3N0YXInLCAnZGlhbW9uZCcsICdyb3VuZC1kaWFtb25kJywgJ3ZlZScsICdyaG9tYm9pZCcsICdyaWdodC1yaG9tYm9pZCcsICdwb2x5Z29uJ11cbiAgICAgIH0sXG4gICAgICBvdmVybGF5U2hhcGU6IHtcbiAgICAgICAgZW51bXM6IFsncm91bmRyZWN0YW5nbGUnLCAncm91bmQtcmVjdGFuZ2xlJywgJ2VsbGlwc2UnXVxuICAgICAgfSxcbiAgICAgIGNvbXBvdW5kSW5jbHVkZUxhYmVsczoge1xuICAgICAgICBlbnVtczogWydpbmNsdWRlJywgJ2V4Y2x1ZGUnXVxuICAgICAgfSxcbiAgICAgIGFycm93U2hhcGU6IHtcbiAgICAgICAgZW51bXM6IFsndGVlJywgJ3RyaWFuZ2xlJywgJ3RyaWFuZ2xlLXRlZScsICdjaXJjbGUtdHJpYW5nbGUnLCAndHJpYW5nbGUtY3Jvc3MnLCAndHJpYW5nbGUtYmFja2N1cnZlJywgJ3ZlZScsICdzcXVhcmUnLCAnY2lyY2xlJywgJ2RpYW1vbmQnLCAnY2hldnJvbicsICdub25lJ11cbiAgICAgIH0sXG4gICAgICBhcnJvd0ZpbGw6IHtcbiAgICAgICAgZW51bXM6IFsnZmlsbGVkJywgJ2hvbGxvdyddXG4gICAgICB9LFxuICAgICAgZGlzcGxheToge1xuICAgICAgICBlbnVtczogWydlbGVtZW50JywgJ25vbmUnXVxuICAgICAgfSxcbiAgICAgIHZpc2liaWxpdHk6IHtcbiAgICAgICAgZW51bXM6IFsnaGlkZGVuJywgJ3Zpc2libGUnXVxuICAgICAgfSxcbiAgICAgIHpDb21wb3VuZERlcHRoOiB7XG4gICAgICAgIGVudW1zOiBbJ2JvdHRvbScsICdvcnBoYW4nLCAnYXV0bycsICd0b3AnXVxuICAgICAgfSxcbiAgICAgIHpJbmRleENvbXBhcmU6IHtcbiAgICAgICAgZW51bXM6IFsnYXV0bycsICdtYW51YWwnXVxuICAgICAgfSxcbiAgICAgIHZhbGlnbjoge1xuICAgICAgICBlbnVtczogWyd0b3AnLCAnY2VudGVyJywgJ2JvdHRvbSddXG4gICAgICB9LFxuICAgICAgaGFsaWduOiB7XG4gICAgICAgIGVudW1zOiBbJ2xlZnQnLCAnY2VudGVyJywgJ3JpZ2h0J11cbiAgICAgIH0sXG4gICAgICBqdXN0aWZpY2F0aW9uOiB7XG4gICAgICAgIGVudW1zOiBbJ2xlZnQnLCAnY2VudGVyJywgJ3JpZ2h0JywgJ2F1dG8nXVxuICAgICAgfSxcbiAgICAgIHRleHQ6IHtcbiAgICAgICAgc3RyaW5nOiB0cnVlXG4gICAgICB9LFxuICAgICAgZGF0YToge1xuICAgICAgICBtYXBwaW5nOiB0cnVlLFxuICAgICAgICByZWdleDogZGF0YSgnZGF0YScpXG4gICAgICB9LFxuICAgICAgbGF5b3V0RGF0YToge1xuICAgICAgICBtYXBwaW5nOiB0cnVlLFxuICAgICAgICByZWdleDogZGF0YSgnbGF5b3V0RGF0YScpXG4gICAgICB9LFxuICAgICAgc2NyYXRjaDoge1xuICAgICAgICBtYXBwaW5nOiB0cnVlLFxuICAgICAgICByZWdleDogZGF0YSgnc2NyYXRjaCcpXG4gICAgICB9LFxuICAgICAgbWFwRGF0YToge1xuICAgICAgICBtYXBwaW5nOiB0cnVlLFxuICAgICAgICByZWdleDogbWFwRGF0YSgnbWFwRGF0YScpXG4gICAgICB9LFxuICAgICAgbWFwTGF5b3V0RGF0YToge1xuICAgICAgICBtYXBwaW5nOiB0cnVlLFxuICAgICAgICByZWdleDogbWFwRGF0YSgnbWFwTGF5b3V0RGF0YScpXG4gICAgICB9LFxuICAgICAgbWFwU2NyYXRjaDoge1xuICAgICAgICBtYXBwaW5nOiB0cnVlLFxuICAgICAgICByZWdleDogbWFwRGF0YSgnbWFwU2NyYXRjaCcpXG4gICAgICB9LFxuICAgICAgZm46IHtcbiAgICAgICAgbWFwcGluZzogdHJ1ZSxcbiAgICAgICAgZm46IHRydWVcbiAgICAgIH0sXG4gICAgICB1cmw6IHtcbiAgICAgICAgcmVnZXhlczogdXJsUmVnZXhlcyxcbiAgICAgICAgc2luZ2xlUmVnZXhNYXRjaFZhbHVlOiB0cnVlXG4gICAgICB9LFxuICAgICAgdXJsczoge1xuICAgICAgICByZWdleGVzOiB1cmxSZWdleGVzLFxuICAgICAgICBzaW5nbGVSZWdleE1hdGNoVmFsdWU6IHRydWUsXG4gICAgICAgIG11bHRpcGxlOiB0cnVlXG4gICAgICB9LFxuICAgICAgcHJvcExpc3Q6IHtcbiAgICAgICAgcHJvcExpc3Q6IHRydWVcbiAgICAgIH0sXG4gICAgICBhbmdsZToge1xuICAgICAgICBudW1iZXI6IHRydWUsXG4gICAgICAgIHVuaXRzOiAnZGVnfHJhZCcsXG4gICAgICAgIGltcGxpY2l0VW5pdHM6ICdyYWQnXG4gICAgICB9LFxuICAgICAgdGV4dFJvdGF0aW9uOiB7XG4gICAgICAgIG51bWJlcjogdHJ1ZSxcbiAgICAgICAgdW5pdHM6ICdkZWd8cmFkJyxcbiAgICAgICAgaW1wbGljaXRVbml0czogJ3JhZCcsXG4gICAgICAgIGVudW1zOiBbJ25vbmUnLCAnYXV0b3JvdGF0ZSddXG4gICAgICB9LFxuICAgICAgcG9seWdvblBvaW50TGlzdDoge1xuICAgICAgICBudW1iZXI6IHRydWUsXG4gICAgICAgIG11bHRpcGxlOiB0cnVlLFxuICAgICAgICBldmVuTXVsdGlwbGU6IHRydWUsXG4gICAgICAgIG1pbjogLTEsXG4gICAgICAgIG1heDogMSxcbiAgICAgICAgdW5pdGxlc3M6IHRydWVcbiAgICAgIH0sXG4gICAgICBlZGdlRGlzdGFuY2VzOiB7XG4gICAgICAgIGVudW1zOiBbJ2ludGVyc2VjdGlvbicsICdub2RlLXBvc2l0aW9uJ11cbiAgICAgIH0sXG4gICAgICBlZGdlRW5kcG9pbnQ6IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBtdWx0aXBsZTogdHJ1ZSxcbiAgICAgICAgdW5pdHM6ICclfHB4fGVtfGRlZ3xyYWQnLFxuICAgICAgICBpbXBsaWNpdFVuaXRzOiAncHgnLFxuICAgICAgICBlbnVtczogWydpbnNpZGUtdG8tbm9kZScsICdvdXRzaWRlLXRvLW5vZGUnLCAnb3V0c2lkZS10by1ub2RlLW9yLWxhYmVsJywgJ291dHNpZGUtdG8tbGluZScsICdvdXRzaWRlLXRvLWxpbmUtb3ItbGFiZWwnXSxcbiAgICAgICAgc2luZ2xlRW51bTogdHJ1ZSxcbiAgICAgICAgdmFsaWRhdGU6IGZ1bmN0aW9uIHZhbGlkYXRlKHZhbEFyciwgdW5pdHNBcnIpIHtcbiAgICAgICAgICBzd2l0Y2ggKHZhbEFyci5sZW5ndGgpIHtcbiAgICAgICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAgICAgLy8gY2FuIGJlICUgb3IgcHggb25seVxuICAgICAgICAgICAgICByZXR1cm4gdW5pdHNBcnJbMF0gIT09ICdkZWcnICYmIHVuaXRzQXJyWzBdICE9PSAncmFkJyAmJiB1bml0c0FyclsxXSAhPT0gJ2RlZycgJiYgdW5pdHNBcnJbMV0gIT09ICdyYWQnO1xuXG4gICAgICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgICAgIC8vIGNhbiBiZSBlbnVtLCBkZWcsIG9yIHJhZCBvbmx5XG4gICAgICAgICAgICAgIHJldHVybiBzdHJpbmcodmFsQXJyWzBdKSB8fCB1bml0c0FyclswXSA9PT0gJ2RlZycgfHwgdW5pdHNBcnJbMF0gPT09ICdyYWQnO1xuXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgZWFzaW5nOiB7XG4gICAgICAgIHJlZ2V4ZXM6IFsnXihzcHJpbmcpXFxcXHMqXFxcXChcXFxccyooJyArIG51bWJlciQxICsgJylcXFxccyosXFxcXHMqKCcgKyBudW1iZXIkMSArICcpXFxcXHMqXFxcXCkkJywgJ14oY3ViaWMtYmV6aWVyKVxcXFxzKlxcXFwoXFxcXHMqKCcgKyBudW1iZXIkMSArICcpXFxcXHMqLFxcXFxzKignICsgbnVtYmVyJDEgKyAnKVxcXFxzKixcXFxccyooJyArIG51bWJlciQxICsgJylcXFxccyosXFxcXHMqKCcgKyBudW1iZXIkMSArICcpXFxcXHMqXFxcXCkkJ10sXG4gICAgICAgIGVudW1zOiBbJ2xpbmVhcicsICdlYXNlJywgJ2Vhc2UtaW4nLCAnZWFzZS1vdXQnLCAnZWFzZS1pbi1vdXQnLCAnZWFzZS1pbi1zaW5lJywgJ2Vhc2Utb3V0LXNpbmUnLCAnZWFzZS1pbi1vdXQtc2luZScsICdlYXNlLWluLXF1YWQnLCAnZWFzZS1vdXQtcXVhZCcsICdlYXNlLWluLW91dC1xdWFkJywgJ2Vhc2UtaW4tY3ViaWMnLCAnZWFzZS1vdXQtY3ViaWMnLCAnZWFzZS1pbi1vdXQtY3ViaWMnLCAnZWFzZS1pbi1xdWFydCcsICdlYXNlLW91dC1xdWFydCcsICdlYXNlLWluLW91dC1xdWFydCcsICdlYXNlLWluLXF1aW50JywgJ2Vhc2Utb3V0LXF1aW50JywgJ2Vhc2UtaW4tb3V0LXF1aW50JywgJ2Vhc2UtaW4tZXhwbycsICdlYXNlLW91dC1leHBvJywgJ2Vhc2UtaW4tb3V0LWV4cG8nLCAnZWFzZS1pbi1jaXJjJywgJ2Vhc2Utb3V0LWNpcmMnLCAnZWFzZS1pbi1vdXQtY2lyYyddXG4gICAgICB9LFxuICAgICAgZ3JhZGllbnREaXJlY3Rpb246IHtcbiAgICAgICAgZW51bXM6IFsndG8tYm90dG9tJywgJ3RvLXRvcCcsICd0by1sZWZ0JywgJ3RvLXJpZ2h0JywgJ3RvLWJvdHRvbS1yaWdodCcsICd0by1ib3R0b20tbGVmdCcsICd0by10b3AtcmlnaHQnLCAndG8tdG9wLWxlZnQnLCAndG8tcmlnaHQtYm90dG9tJywgJ3RvLWxlZnQtYm90dG9tJywgJ3RvLXJpZ2h0LXRvcCcsICd0by1sZWZ0LXRvcCcgLy8gZGlmZmVyZW50IG9yZGVyXG4gICAgICAgIF1cbiAgICAgIH0sXG4gICAgICBib3VuZHNFeHBhbnNpb246IHtcbiAgICAgICAgbnVtYmVyOiB0cnVlLFxuICAgICAgICBtdWx0aXBsZTogdHJ1ZSxcbiAgICAgICAgbWluOiAwLFxuICAgICAgICB2YWxpZGF0ZTogZnVuY3Rpb24gdmFsaWRhdGUodmFsQXJyKSB7XG4gICAgICAgICAgdmFyIGxlbmd0aCA9IHZhbEFyci5sZW5ndGg7XG4gICAgICAgICAgcmV0dXJuIGxlbmd0aCA9PT0gMSB8fCBsZW5ndGggPT09IDIgfHwgbGVuZ3RoID09PSA0O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcbiAgICB2YXIgZGlmZiA9IHtcbiAgICAgIHplcm9Ob25aZXJvOiBmdW5jdGlvbiB6ZXJvTm9uWmVybyh2YWwxLCB2YWwyKSB7XG4gICAgICAgIGlmICgodmFsMSA9PSBudWxsIHx8IHZhbDIgPT0gbnVsbCkgJiYgdmFsMSAhPT0gdmFsMikge1xuICAgICAgICAgIHJldHVybiB0cnVlOyAvLyBudWxsIGNhc2VzIGNvdWxkIHJlcHJlc2VudCBhbnkgdmFsdWVcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh2YWwxID09IDAgJiYgdmFsMiAhPSAwKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gZWxzZSBpZiAodmFsMSAhPSAwICYmIHZhbDIgPT0gMCkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIGFueTogZnVuY3Rpb24gYW55KHZhbDEsIHZhbDIpIHtcbiAgICAgICAgcmV0dXJuIHZhbDEgIT0gdmFsMjtcbiAgICAgIH0sXG4gICAgICBlbXB0eU5vbkVtcHR5OiBmdW5jdGlvbiBlbXB0eU5vbkVtcHR5KHN0cjEsIHN0cjIpIHtcbiAgICAgICAgdmFyIGVtcHR5MSA9IGVtcHR5U3RyaW5nKHN0cjEpO1xuICAgICAgICB2YXIgZW1wdHkyID0gZW1wdHlTdHJpbmcoc3RyMik7XG4gICAgICAgIHJldHVybiBlbXB0eTEgJiYgIWVtcHR5MiB8fCAhZW1wdHkxICYmIGVtcHR5MjtcbiAgICAgIH1cbiAgICB9OyAvLyBkZWZpbmUgdmlzdWFsIHN0eWxlIHByb3BlcnRpZXNcbiAgICAvL1xuICAgIC8vIC0gbi5iLiBhZGRpbmcgYSBuZXcgZ3JvdXAgb2YgcHJvcHMgbWF5IHJlcXVpcmUgdXBkYXRlcyB0byB1cGRhdGVTdHlsZUhpbnRzKClcbiAgICAvLyAtIGFkZGluZyBuZXcgcHJvcHMgdG8gYW4gZXhpc3RpbmcgZ3JvdXAgZ2V0cyBoYW5kbGVkIGF1dG9tYXRpY2FsbHlcblxuICAgIHZhciB0ID0gc3R5Zm4kMi50eXBlcztcbiAgICB2YXIgbWFpbkxhYmVsID0gW3tcbiAgICAgIG5hbWU6ICdsYWJlbCcsXG4gICAgICB0eXBlOiB0LnRleHQsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnksXG4gICAgICB0cmlnZ2Vyc1pPcmRlcjogZGlmZi5lbXB0eU5vbkVtcHR5XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RleHQtcm90YXRpb24nLFxuICAgICAgdHlwZTogdC50ZXh0Um90YXRpb24sXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAndGV4dC1tYXJnaW4teCcsXG4gICAgICB0eXBlOiB0LmJpZGlyZWN0aW9uYWxTaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RleHQtbWFyZ2luLXknLFxuICAgICAgdHlwZTogdC5iaWRpcmVjdGlvbmFsU2l6ZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH1dO1xuICAgIHZhciBzb3VyY2VMYWJlbCA9IFt7XG4gICAgICBuYW1lOiAnc291cmNlLWxhYmVsJyxcbiAgICAgIHR5cGU6IHQudGV4dCxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdzb3VyY2UtdGV4dC1yb3RhdGlvbicsXG4gICAgICB0eXBlOiB0LnRleHRSb3RhdGlvbixcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdzb3VyY2UtdGV4dC1tYXJnaW4teCcsXG4gICAgICB0eXBlOiB0LmJpZGlyZWN0aW9uYWxTaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3NvdXJjZS10ZXh0LW1hcmdpbi15JyxcbiAgICAgIHR5cGU6IHQuYmlkaXJlY3Rpb25hbFNpemUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnc291cmNlLXRleHQtb2Zmc2V0JyxcbiAgICAgIHR5cGU6IHQuc2l6ZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH1dO1xuICAgIHZhciB0YXJnZXRMYWJlbCA9IFt7XG4gICAgICBuYW1lOiAndGFyZ2V0LWxhYmVsJyxcbiAgICAgIHR5cGU6IHQudGV4dCxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0YXJnZXQtdGV4dC1yb3RhdGlvbicsXG4gICAgICB0eXBlOiB0LnRleHRSb3RhdGlvbixcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0YXJnZXQtdGV4dC1tYXJnaW4teCcsXG4gICAgICB0eXBlOiB0LmJpZGlyZWN0aW9uYWxTaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RhcmdldC10ZXh0LW1hcmdpbi15JyxcbiAgICAgIHR5cGU6IHQuYmlkaXJlY3Rpb25hbFNpemUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAndGFyZ2V0LXRleHQtb2Zmc2V0JyxcbiAgICAgIHR5cGU6IHQuc2l6ZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH1dO1xuICAgIHZhciBsYWJlbERpbWVuc2lvbnMgPSBbe1xuICAgICAgbmFtZTogJ2ZvbnQtZmFtaWx5JyxcbiAgICAgIHR5cGU6IHQuZm9udEZhbWlseSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdmb250LXN0eWxlJyxcbiAgICAgIHR5cGU6IHQuZm9udFN0eWxlLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ2ZvbnQtd2VpZ2h0JyxcbiAgICAgIHR5cGU6IHQuZm9udFdlaWdodCxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdmb250LXNpemUnLFxuICAgICAgdHlwZTogdC5zaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RleHQtdHJhbnNmb3JtJyxcbiAgICAgIHR5cGU6IHQudGV4dFRyYW5zZm9ybSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0ZXh0LXdyYXAnLFxuICAgICAgdHlwZTogdC50ZXh0V3JhcCxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0ZXh0LW92ZXJmbG93LXdyYXAnLFxuICAgICAgdHlwZTogdC50ZXh0T3ZlcmZsb3dXcmFwLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RleHQtbWF4LXdpZHRoJyxcbiAgICAgIHR5cGU6IHQuc2l6ZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0ZXh0LW91dGxpbmUtd2lkdGgnLFxuICAgICAgdHlwZTogdC5zaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ2xpbmUtaGVpZ2h0JyxcbiAgICAgIHR5cGU6IHQucG9zaXRpdmVOdW1iZXIsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9XTtcbiAgICB2YXIgY29tbW9uTGFiZWwgPSBbe1xuICAgICAgbmFtZTogJ3RleHQtdmFsaWduJyxcbiAgICAgIHR5cGU6IHQudmFsaWduLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RleHQtaGFsaWduJyxcbiAgICAgIHR5cGU6IHQuaGFsaWduLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ2NvbG9yJyxcbiAgICAgIHR5cGU6IHQuY29sb3JcbiAgICB9LCB7XG4gICAgICBuYW1lOiAndGV4dC1vdXRsaW5lLWNvbG9yJyxcbiAgICAgIHR5cGU6IHQuY29sb3JcbiAgICB9LCB7XG4gICAgICBuYW1lOiAndGV4dC1vdXRsaW5lLW9wYWNpdHknLFxuICAgICAgdHlwZTogdC56ZXJvT25lTnVtYmVyXG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RleHQtYmFja2dyb3VuZC1jb2xvcicsXG4gICAgICB0eXBlOiB0LmNvbG9yXG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RleHQtYmFja2dyb3VuZC1vcGFjaXR5JyxcbiAgICAgIHR5cGU6IHQuemVyb09uZU51bWJlclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0ZXh0LWJhY2tncm91bmQtcGFkZGluZycsXG4gICAgICB0eXBlOiB0LnNpemUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAndGV4dC1ib3JkZXItb3BhY2l0eScsXG4gICAgICB0eXBlOiB0Lnplcm9PbmVOdW1iZXJcbiAgICB9LCB7XG4gICAgICBuYW1lOiAndGV4dC1ib3JkZXItY29sb3InLFxuICAgICAgdHlwZTogdC5jb2xvclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0ZXh0LWJvcmRlci13aWR0aCcsXG4gICAgICB0eXBlOiB0LnNpemUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAndGV4dC1ib3JkZXItc3R5bGUnLFxuICAgICAgdHlwZTogdC5ib3JkZXJTdHlsZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0ZXh0LWJhY2tncm91bmQtc2hhcGUnLFxuICAgICAgdHlwZTogdC50ZXh0QmFja2dyb3VuZFNoYXBlLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RleHQtanVzdGlmaWNhdGlvbicsXG4gICAgICB0eXBlOiB0Lmp1c3RpZmljYXRpb25cbiAgICB9XTtcbiAgICB2YXIgYmVoYXZpb3IgPSBbe1xuICAgICAgbmFtZTogJ2V2ZW50cycsXG4gICAgICB0eXBlOiB0LmJvb2xcbiAgICB9LCB7XG4gICAgICBuYW1lOiAndGV4dC1ldmVudHMnLFxuICAgICAgdHlwZTogdC5ib29sXG4gICAgfV07XG4gICAgdmFyIHZpc2liaWxpdHkgPSBbe1xuICAgICAgbmFtZTogJ2Rpc3BsYXknLFxuICAgICAgdHlwZTogdC5kaXNwbGF5LFxuICAgICAgdHJpZ2dlcnNaT3JkZXI6IGRpZmYuYW55LFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55LFxuICAgICAgdHJpZ2dlcnNCb3VuZHNPZlBhcmFsbGVsQmV6aWVyczogdHJ1ZVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd2aXNpYmlsaXR5JyxcbiAgICAgIHR5cGU6IHQudmlzaWJpbGl0eSxcbiAgICAgIHRyaWdnZXJzWk9yZGVyOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdvcGFjaXR5JyxcbiAgICAgIHR5cGU6IHQuemVyb09uZU51bWJlcixcbiAgICAgIHRyaWdnZXJzWk9yZGVyOiBkaWZmLnplcm9Ob25aZXJvXG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RleHQtb3BhY2l0eScsXG4gICAgICB0eXBlOiB0Lnplcm9PbmVOdW1iZXJcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnbWluLXpvb21lZC1mb250LXNpemUnLFxuICAgICAgdHlwZTogdC5zaXplXG4gICAgfSwge1xuICAgICAgbmFtZTogJ3otY29tcG91bmQtZGVwdGgnLFxuICAgICAgdHlwZTogdC56Q29tcG91bmREZXB0aCxcbiAgICAgIHRyaWdnZXJzWk9yZGVyOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd6LWluZGV4LWNvbXBhcmUnLFxuICAgICAgdHlwZTogdC56SW5kZXhDb21wYXJlLFxuICAgICAgdHJpZ2dlcnNaT3JkZXI6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3otaW5kZXgnLFxuICAgICAgdHlwZTogdC5ub25OZWdhdGl2ZUludCxcbiAgICAgIHRyaWdnZXJzWk9yZGVyOiBkaWZmLmFueVxuICAgIH1dO1xuICAgIHZhciBvdmVybGF5ID0gW3tcbiAgICAgIG5hbWU6ICdvdmVybGF5LXBhZGRpbmcnLFxuICAgICAgdHlwZTogdC5zaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ292ZXJsYXktY29sb3InLFxuICAgICAgdHlwZTogdC5jb2xvclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdvdmVybGF5LW9wYWNpdHknLFxuICAgICAgdHlwZTogdC56ZXJvT25lTnVtYmVyLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuemVyb05vblplcm9cbiAgICB9LCB7XG4gICAgICBuYW1lOiAnb3ZlcmxheS1zaGFwZScsXG4gICAgICB0eXBlOiB0Lm92ZXJsYXlTaGFwZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH1dO1xuICAgIHZhciB1bmRlcmxheSA9IFt7XG4gICAgICBuYW1lOiAndW5kZXJsYXktcGFkZGluZycsXG4gICAgICB0eXBlOiB0LnNpemUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAndW5kZXJsYXktY29sb3InLFxuICAgICAgdHlwZTogdC5jb2xvclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd1bmRlcmxheS1vcGFjaXR5JyxcbiAgICAgIHR5cGU6IHQuemVyb09uZU51bWJlcixcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLnplcm9Ob25aZXJvXG4gICAgfSwge1xuICAgICAgbmFtZTogJ3VuZGVybGF5LXNoYXBlJyxcbiAgICAgIHR5cGU6IHQub3ZlcmxheVNoYXBlLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfV07XG4gICAgdmFyIHRyYW5zaXRpb24gPSBbe1xuICAgICAgbmFtZTogJ3RyYW5zaXRpb24tcHJvcGVydHknLFxuICAgICAgdHlwZTogdC5wcm9wTGlzdFxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0cmFuc2l0aW9uLWR1cmF0aW9uJyxcbiAgICAgIHR5cGU6IHQudGltZVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0cmFuc2l0aW9uLWRlbGF5JyxcbiAgICAgIHR5cGU6IHQudGltZVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0cmFuc2l0aW9uLXRpbWluZy1mdW5jdGlvbicsXG4gICAgICB0eXBlOiB0LmVhc2luZ1xuICAgIH1dO1xuXG4gICAgdmFyIG5vZGVTaXplSGFzaE92ZXJyaWRlID0gZnVuY3Rpb24gbm9kZVNpemVIYXNoT3ZlcnJpZGUoZWxlLCBwYXJzZWRQcm9wKSB7XG4gICAgICBpZiAocGFyc2VkUHJvcC52YWx1ZSA9PT0gJ2xhYmVsJykge1xuICAgICAgICByZXR1cm4gLWVsZS5wb29sSW5kZXgoKTsgLy8gbm8gaGFzaCBrZXkgaGl0cyBpcyB1c2luZyBsYWJlbCBzaXplIChoaXRyYXRlIGZvciBwZXJmIHByb2JhYmx5IGxvdyBhbnl3YXkpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gcGFyc2VkUHJvcC5wZlZhbHVlO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgbm9kZUJvZHkgPSBbe1xuICAgICAgbmFtZTogJ2hlaWdodCcsXG4gICAgICB0eXBlOiB0Lm5vZGVTaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55LFxuICAgICAgaGFzaE92ZXJyaWRlOiBub2RlU2l6ZUhhc2hPdmVycmlkZVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd3aWR0aCcsXG4gICAgICB0eXBlOiB0Lm5vZGVTaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55LFxuICAgICAgaGFzaE92ZXJyaWRlOiBub2RlU2l6ZUhhc2hPdmVycmlkZVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdzaGFwZScsXG4gICAgICB0eXBlOiB0Lm5vZGVTaGFwZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdzaGFwZS1wb2x5Z29uLXBvaW50cycsXG4gICAgICB0eXBlOiB0LnBvbHlnb25Qb2ludExpc3QsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYmFja2dyb3VuZC1jb2xvcicsXG4gICAgICB0eXBlOiB0LmNvbG9yXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JhY2tncm91bmQtZmlsbCcsXG4gICAgICB0eXBlOiB0LmZpbGxcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYmFja2dyb3VuZC1vcGFjaXR5JyxcbiAgICAgIHR5cGU6IHQuemVyb09uZU51bWJlclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdiYWNrZ3JvdW5kLWJsYWNrZW4nLFxuICAgICAgdHlwZTogdC5uT25lT25lTnVtYmVyXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JhY2tncm91bmQtZ3JhZGllbnQtc3RvcC1jb2xvcnMnLFxuICAgICAgdHlwZTogdC5jb2xvcnNcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYmFja2dyb3VuZC1ncmFkaWVudC1zdG9wLXBvc2l0aW9ucycsXG4gICAgICB0eXBlOiB0LnBlcmNlbnRhZ2VzXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JhY2tncm91bmQtZ3JhZGllbnQtZGlyZWN0aW9uJyxcbiAgICAgIHR5cGU6IHQuZ3JhZGllbnREaXJlY3Rpb25cbiAgICB9LCB7XG4gICAgICBuYW1lOiAncGFkZGluZycsXG4gICAgICB0eXBlOiB0LnNpemVNYXliZVBlcmNlbnQsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAncGFkZGluZy1yZWxhdGl2ZS10bycsXG4gICAgICB0eXBlOiB0LnBhZGRpbmdSZWxhdGl2ZVRvLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JvdW5kcy1leHBhbnNpb24nLFxuICAgICAgdHlwZTogdC5ib3VuZHNFeHBhbnNpb24sXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9XTtcbiAgICB2YXIgbm9kZUJvcmRlciA9IFt7XG4gICAgICBuYW1lOiAnYm9yZGVyLWNvbG9yJyxcbiAgICAgIHR5cGU6IHQuY29sb3JcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYm9yZGVyLW9wYWNpdHknLFxuICAgICAgdHlwZTogdC56ZXJvT25lTnVtYmVyXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JvcmRlci13aWR0aCcsXG4gICAgICB0eXBlOiB0LnNpemUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYm9yZGVyLXN0eWxlJyxcbiAgICAgIHR5cGU6IHQuYm9yZGVyU3R5bGVcbiAgICB9XTtcbiAgICB2YXIgYmFja2dyb3VuZEltYWdlID0gW3tcbiAgICAgIG5hbWU6ICdiYWNrZ3JvdW5kLWltYWdlJyxcbiAgICAgIHR5cGU6IHQudXJsc1xuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdiYWNrZ3JvdW5kLWltYWdlLWNyb3Nzb3JpZ2luJyxcbiAgICAgIHR5cGU6IHQuYmdDcm9zc09yaWdpblxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdiYWNrZ3JvdW5kLWltYWdlLW9wYWNpdHknLFxuICAgICAgdHlwZTogdC56ZXJvT25lTnVtYmVyc1xuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdiYWNrZ3JvdW5kLWltYWdlLWNvbnRhaW5tZW50JyxcbiAgICAgIHR5cGU6IHQuYmdDb250YWlubWVudFxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdiYWNrZ3JvdW5kLWltYWdlLXNtb290aGluZycsXG4gICAgICB0eXBlOiB0LmJvb2xzXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JhY2tncm91bmQtcG9zaXRpb24teCcsXG4gICAgICB0eXBlOiB0LmJnUG9zXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JhY2tncm91bmQtcG9zaXRpb24teScsXG4gICAgICB0eXBlOiB0LmJnUG9zXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JhY2tncm91bmQtd2lkdGgtcmVsYXRpdmUtdG8nLFxuICAgICAgdHlwZTogdC5iZ1JlbGF0aXZlVG9cbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYmFja2dyb3VuZC1oZWlnaHQtcmVsYXRpdmUtdG8nLFxuICAgICAgdHlwZTogdC5iZ1JlbGF0aXZlVG9cbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYmFja2dyb3VuZC1yZXBlYXQnLFxuICAgICAgdHlwZTogdC5iZ1JlcGVhdFxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdiYWNrZ3JvdW5kLWZpdCcsXG4gICAgICB0eXBlOiB0LmJnRml0XG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JhY2tncm91bmQtY2xpcCcsXG4gICAgICB0eXBlOiB0LmJnQ2xpcFxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdiYWNrZ3JvdW5kLXdpZHRoJyxcbiAgICAgIHR5cGU6IHQuYmdXSFxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdiYWNrZ3JvdW5kLWhlaWdodCcsXG4gICAgICB0eXBlOiB0LmJnV0hcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYmFja2dyb3VuZC1vZmZzZXQteCcsXG4gICAgICB0eXBlOiB0LmJnUG9zXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2JhY2tncm91bmQtb2Zmc2V0LXknLFxuICAgICAgdHlwZTogdC5iZ1Bvc1xuICAgIH1dO1xuICAgIHZhciBjb21wb3VuZCA9IFt7XG4gICAgICBuYW1lOiAncG9zaXRpb24nLFxuICAgICAgdHlwZTogdC5wb3NpdGlvbixcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdjb21wb3VuZC1zaXppbmctd3J0LWxhYmVscycsXG4gICAgICB0eXBlOiB0LmNvbXBvdW5kSW5jbHVkZUxhYmVscyxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdtaW4td2lkdGgnLFxuICAgICAgdHlwZTogdC5zaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ21pbi13aWR0aC1iaWFzLWxlZnQnLFxuICAgICAgdHlwZTogdC5zaXplTWF5YmVQZXJjZW50LFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ21pbi13aWR0aC1iaWFzLXJpZ2h0JyxcbiAgICAgIHR5cGU6IHQuc2l6ZU1heWJlUGVyY2VudCxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdtaW4taGVpZ2h0JyxcbiAgICAgIHR5cGU6IHQuc2l6ZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdtaW4taGVpZ2h0LWJpYXMtdG9wJyxcbiAgICAgIHR5cGU6IHQuc2l6ZU1heWJlUGVyY2VudCxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdtaW4taGVpZ2h0LWJpYXMtYm90dG9tJyxcbiAgICAgIHR5cGU6IHQuc2l6ZU1heWJlUGVyY2VudCxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH1dO1xuICAgIHZhciBlZGdlTGluZSA9IFt7XG4gICAgICBuYW1lOiAnbGluZS1zdHlsZScsXG4gICAgICB0eXBlOiB0LmxpbmVTdHlsZVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdsaW5lLWNvbG9yJyxcbiAgICAgIHR5cGU6IHQuY29sb3JcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnbGluZS1maWxsJyxcbiAgICAgIHR5cGU6IHQuZmlsbFxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdsaW5lLWNhcCcsXG4gICAgICB0eXBlOiB0LmxpbmVDYXBcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnbGluZS1vcGFjaXR5JyxcbiAgICAgIHR5cGU6IHQuemVyb09uZU51bWJlclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdsaW5lLWRhc2gtcGF0dGVybicsXG4gICAgICB0eXBlOiB0Lm51bWJlcnNcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnbGluZS1kYXNoLW9mZnNldCcsXG4gICAgICB0eXBlOiB0Lm51bWJlclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdsaW5lLWdyYWRpZW50LXN0b3AtY29sb3JzJyxcbiAgICAgIHR5cGU6IHQuY29sb3JzXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2xpbmUtZ3JhZGllbnQtc3RvcC1wb3NpdGlvbnMnLFxuICAgICAgdHlwZTogdC5wZXJjZW50YWdlc1xuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdjdXJ2ZS1zdHlsZScsXG4gICAgICB0eXBlOiB0LmN1cnZlU3R5bGUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnksXG4gICAgICB0cmlnZ2Vyc0JvdW5kc09mUGFyYWxsZWxCZXppZXJzOiB0cnVlXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2hheXN0YWNrLXJhZGl1cycsXG4gICAgICB0eXBlOiB0Lnplcm9PbmVOdW1iZXIsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnc291cmNlLWVuZHBvaW50JyxcbiAgICAgIHR5cGU6IHQuZWRnZUVuZHBvaW50LFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RhcmdldC1lbmRwb2ludCcsXG4gICAgICB0eXBlOiB0LmVkZ2VFbmRwb2ludCxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdjb250cm9sLXBvaW50LXN0ZXAtc2l6ZScsXG4gICAgICB0eXBlOiB0LnNpemUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnY29udHJvbC1wb2ludC1kaXN0YW5jZXMnLFxuICAgICAgdHlwZTogdC5iaWRpcmVjdGlvbmFsU2l6ZXMsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnY29udHJvbC1wb2ludC13ZWlnaHRzJyxcbiAgICAgIHR5cGU6IHQubnVtYmVycyxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdzZWdtZW50LWRpc3RhbmNlcycsXG4gICAgICB0eXBlOiB0LmJpZGlyZWN0aW9uYWxTaXplcyxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdzZWdtZW50LXdlaWdodHMnLFxuICAgICAgdHlwZTogdC5udW1iZXJzLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RheGktdHVybicsXG4gICAgICB0eXBlOiB0LmJpZGlyZWN0aW9uYWxTaXplTWF5YmVQZXJjZW50LFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RheGktdHVybi1taW4tZGlzdGFuY2UnLFxuICAgICAgdHlwZTogdC5zaXplLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ3RheGktZGlyZWN0aW9uJyxcbiAgICAgIHR5cGU6IHQuYXhpc0RpcmVjdGlvbixcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdlZGdlLWRpc3RhbmNlcycsXG4gICAgICB0eXBlOiB0LmVkZ2VEaXN0YW5jZXMsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYXJyb3ctc2NhbGUnLFxuICAgICAgdHlwZTogdC5wb3NpdGl2ZU51bWJlcixcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdsb29wLWRpcmVjdGlvbicsXG4gICAgICB0eXBlOiB0LmFuZ2xlLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ2xvb3Atc3dlZXAnLFxuICAgICAgdHlwZTogdC5hbmdsZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdzb3VyY2UtZGlzdGFuY2UtZnJvbS1ub2RlJyxcbiAgICAgIHR5cGU6IHQuc2l6ZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICd0YXJnZXQtZGlzdGFuY2UtZnJvbS1ub2RlJyxcbiAgICAgIHR5cGU6IHQuc2l6ZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH1dO1xuICAgIHZhciBnaG9zdCA9IFt7XG4gICAgICBuYW1lOiAnZ2hvc3QnLFxuICAgICAgdHlwZTogdC5ib29sLFxuICAgICAgdHJpZ2dlcnNCb3VuZHM6IGRpZmYuYW55XG4gICAgfSwge1xuICAgICAgbmFtZTogJ2dob3N0LW9mZnNldC14JyxcbiAgICAgIHR5cGU6IHQuYmlkaXJlY3Rpb25hbFNpemUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnZ2hvc3Qtb2Zmc2V0LXknLFxuICAgICAgdHlwZTogdC5iaWRpcmVjdGlvbmFsU2l6ZSxcbiAgICAgIHRyaWdnZXJzQm91bmRzOiBkaWZmLmFueVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdnaG9zdC1vcGFjaXR5JyxcbiAgICAgIHR5cGU6IHQuemVyb09uZU51bWJlclxuICAgIH1dO1xuICAgIHZhciBjb3JlID0gW3tcbiAgICAgIG5hbWU6ICdzZWxlY3Rpb24tYm94LWNvbG9yJyxcbiAgICAgIHR5cGU6IHQuY29sb3JcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnc2VsZWN0aW9uLWJveC1vcGFjaXR5JyxcbiAgICAgIHR5cGU6IHQuemVyb09uZU51bWJlclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdzZWxlY3Rpb24tYm94LWJvcmRlci1jb2xvcicsXG4gICAgICB0eXBlOiB0LmNvbG9yXG4gICAgfSwge1xuICAgICAgbmFtZTogJ3NlbGVjdGlvbi1ib3gtYm9yZGVyLXdpZHRoJyxcbiAgICAgIHR5cGU6IHQuc2l6ZVxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdhY3RpdmUtYmctY29sb3InLFxuICAgICAgdHlwZTogdC5jb2xvclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdhY3RpdmUtYmctb3BhY2l0eScsXG4gICAgICB0eXBlOiB0Lnplcm9PbmVOdW1iZXJcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYWN0aXZlLWJnLXNpemUnLFxuICAgICAgdHlwZTogdC5zaXplXG4gICAgfSwge1xuICAgICAgbmFtZTogJ291dHNpZGUtdGV4dHVyZS1iZy1jb2xvcicsXG4gICAgICB0eXBlOiB0LmNvbG9yXG4gICAgfSwge1xuICAgICAgbmFtZTogJ291dHNpZGUtdGV4dHVyZS1iZy1vcGFjaXR5JyxcbiAgICAgIHR5cGU6IHQuemVyb09uZU51bWJlclxuICAgIH1dOyAvLyBwaWUgYmFja2dyb3VuZHMgZm9yIG5vZGVzXG5cbiAgICB2YXIgcGllID0gW107XG4gICAgc3R5Zm4kMi5waWVCYWNrZ3JvdW5kTiA9IDE2OyAvLyBiZWNhdXNlIHRoZSBwaWUgcHJvcGVydGllcyBhcmUgbnVtYmVyZWQsIGdpdmUgYWNjZXNzIHRvIGEgY29uc3RhbnQgTiAoZm9yIHJlbmRlcmVyIHVzZSlcblxuICAgIHBpZS5wdXNoKHtcbiAgICAgIG5hbWU6ICdwaWUtc2l6ZScsXG4gICAgICB0eXBlOiB0LnNpemVNYXliZVBlcmNlbnRcbiAgICB9KTtcblxuICAgIGZvciAodmFyIGkgPSAxOyBpIDw9IHN0eWZuJDIucGllQmFja2dyb3VuZE47IGkrKykge1xuICAgICAgcGllLnB1c2goe1xuICAgICAgICBuYW1lOiAncGllLScgKyBpICsgJy1iYWNrZ3JvdW5kLWNvbG9yJyxcbiAgICAgICAgdHlwZTogdC5jb2xvclxuICAgICAgfSk7XG4gICAgICBwaWUucHVzaCh7XG4gICAgICAgIG5hbWU6ICdwaWUtJyArIGkgKyAnLWJhY2tncm91bmQtc2l6ZScsXG4gICAgICAgIHR5cGU6IHQucGVyY2VudFxuICAgICAgfSk7XG4gICAgICBwaWUucHVzaCh7XG4gICAgICAgIG5hbWU6ICdwaWUtJyArIGkgKyAnLWJhY2tncm91bmQtb3BhY2l0eScsXG4gICAgICAgIHR5cGU6IHQuemVyb09uZU51bWJlclxuICAgICAgfSk7XG4gICAgfSAvLyBlZGdlIGFycm93c1xuXG5cbiAgICB2YXIgZWRnZUFycm93ID0gW107XG4gICAgdmFyIGFycm93UHJlZml4ZXMgPSBzdHlmbiQyLmFycm93UHJlZml4ZXMgPSBbJ3NvdXJjZScsICdtaWQtc291cmNlJywgJ3RhcmdldCcsICdtaWQtdGFyZ2V0J107XG4gICAgW3tcbiAgICAgIG5hbWU6ICdhcnJvdy1zaGFwZScsXG4gICAgICB0eXBlOiB0LmFycm93U2hhcGUsXG4gICAgICB0cmlnZ2Vyc0JvdW5kczogZGlmZi5hbnlcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYXJyb3ctY29sb3InLFxuICAgICAgdHlwZTogdC5jb2xvclxuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdhcnJvdy1maWxsJyxcbiAgICAgIHR5cGU6IHQuYXJyb3dGaWxsXG4gICAgfV0uZm9yRWFjaChmdW5jdGlvbiAocHJvcCkge1xuICAgICAgYXJyb3dQcmVmaXhlcy5mb3JFYWNoKGZ1bmN0aW9uIChwcmVmaXgpIHtcbiAgICAgICAgdmFyIG5hbWUgPSBwcmVmaXggKyAnLScgKyBwcm9wLm5hbWU7XG4gICAgICAgIHZhciB0eXBlID0gcHJvcC50eXBlLFxuICAgICAgICAgICAgdHJpZ2dlcnNCb3VuZHMgPSBwcm9wLnRyaWdnZXJzQm91bmRzO1xuICAgICAgICBlZGdlQXJyb3cucHVzaCh7XG4gICAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgICB0eXBlOiB0eXBlLFxuICAgICAgICAgIHRyaWdnZXJzQm91bmRzOiB0cmlnZ2Vyc0JvdW5kc1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0sIHt9KTtcbiAgICB2YXIgcHJvcHMgPSBzdHlmbiQyLnByb3BlcnRpZXMgPSBbXS5jb25jYXQoYmVoYXZpb3IsIHRyYW5zaXRpb24sIHZpc2liaWxpdHksIG92ZXJsYXksIHVuZGVybGF5LCBnaG9zdCwgY29tbW9uTGFiZWwsIGxhYmVsRGltZW5zaW9ucywgbWFpbkxhYmVsLCBzb3VyY2VMYWJlbCwgdGFyZ2V0TGFiZWwsIG5vZGVCb2R5LCBub2RlQm9yZGVyLCBiYWNrZ3JvdW5kSW1hZ2UsIHBpZSwgY29tcG91bmQsIGVkZ2VMaW5lLCBlZGdlQXJyb3csIGNvcmUpO1xuICAgIHZhciBwcm9wR3JvdXBzID0gc3R5Zm4kMi5wcm9wZXJ0eUdyb3VwcyA9IHtcbiAgICAgIC8vIGNvbW1vbiB0byBhbGwgZWxlc1xuICAgICAgYmVoYXZpb3I6IGJlaGF2aW9yLFxuICAgICAgdHJhbnNpdGlvbjogdHJhbnNpdGlvbixcbiAgICAgIHZpc2liaWxpdHk6IHZpc2liaWxpdHksXG4gICAgICBvdmVybGF5OiBvdmVybGF5LFxuICAgICAgdW5kZXJsYXk6IHVuZGVybGF5LFxuICAgICAgZ2hvc3Q6IGdob3N0LFxuICAgICAgLy8gbGFiZWxzXG4gICAgICBjb21tb25MYWJlbDogY29tbW9uTGFiZWwsXG4gICAgICBsYWJlbERpbWVuc2lvbnM6IGxhYmVsRGltZW5zaW9ucyxcbiAgICAgIG1haW5MYWJlbDogbWFpbkxhYmVsLFxuICAgICAgc291cmNlTGFiZWw6IHNvdXJjZUxhYmVsLFxuICAgICAgdGFyZ2V0TGFiZWw6IHRhcmdldExhYmVsLFxuICAgICAgLy8gbm9kZSBwcm9wc1xuICAgICAgbm9kZUJvZHk6IG5vZGVCb2R5LFxuICAgICAgbm9kZUJvcmRlcjogbm9kZUJvcmRlcixcbiAgICAgIGJhY2tncm91bmRJbWFnZTogYmFja2dyb3VuZEltYWdlLFxuICAgICAgcGllOiBwaWUsXG4gICAgICBjb21wb3VuZDogY29tcG91bmQsXG4gICAgICAvLyBlZGdlIHByb3BzXG4gICAgICBlZGdlTGluZTogZWRnZUxpbmUsXG4gICAgICBlZGdlQXJyb3c6IGVkZ2VBcnJvdyxcbiAgICAgIGNvcmU6IGNvcmVcbiAgICB9O1xuICAgIHZhciBwcm9wR3JvdXBOYW1lcyA9IHN0eWZuJDIucHJvcGVydHlHcm91cE5hbWVzID0ge307XG4gICAgdmFyIHByb3BHcm91cEtleXMgPSBzdHlmbiQyLnByb3BlcnR5R3JvdXBLZXlzID0gT2JqZWN0LmtleXMocHJvcEdyb3Vwcyk7XG4gICAgcHJvcEdyb3VwS2V5cy5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgIHByb3BHcm91cE5hbWVzW2tleV0gPSBwcm9wR3JvdXBzW2tleV0ubWFwKGZ1bmN0aW9uIChwcm9wKSB7XG4gICAgICAgIHJldHVybiBwcm9wLm5hbWU7XG4gICAgICB9KTtcbiAgICAgIHByb3BHcm91cHNba2V5XS5mb3JFYWNoKGZ1bmN0aW9uIChwcm9wKSB7XG4gICAgICAgIHJldHVybiBwcm9wLmdyb3VwS2V5ID0ga2V5O1xuICAgICAgfSk7XG4gICAgfSk7IC8vIGRlZmluZSBhbGlhc2VzXG5cbiAgICB2YXIgYWxpYXNlcyA9IHN0eWZuJDIuYWxpYXNlcyA9IFt7XG4gICAgICBuYW1lOiAnY29udGVudCcsXG4gICAgICBwb2ludHNUbzogJ2xhYmVsJ1xuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdjb250cm9sLXBvaW50LWRpc3RhbmNlJyxcbiAgICAgIHBvaW50c1RvOiAnY29udHJvbC1wb2ludC1kaXN0YW5jZXMnXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2NvbnRyb2wtcG9pbnQtd2VpZ2h0JyxcbiAgICAgIHBvaW50c1RvOiAnY29udHJvbC1wb2ludC13ZWlnaHRzJ1xuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdlZGdlLXRleHQtcm90YXRpb24nLFxuICAgICAgcG9pbnRzVG86ICd0ZXh0LXJvdGF0aW9uJ1xuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdwYWRkaW5nLWxlZnQnLFxuICAgICAgcG9pbnRzVG86ICdwYWRkaW5nJ1xuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdwYWRkaW5nLXJpZ2h0JyxcbiAgICAgIHBvaW50c1RvOiAncGFkZGluZydcbiAgICB9LCB7XG4gICAgICBuYW1lOiAncGFkZGluZy10b3AnLFxuICAgICAgcG9pbnRzVG86ICdwYWRkaW5nJ1xuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdwYWRkaW5nLWJvdHRvbScsXG4gICAgICBwb2ludHNUbzogJ3BhZGRpbmcnXG4gICAgfV07IC8vIGxpc3Qgb2YgcHJvcGVydHkgbmFtZXNcblxuICAgIHN0eWZuJDIucHJvcGVydHlOYW1lcyA9IHByb3BzLm1hcChmdW5jdGlvbiAocCkge1xuICAgICAgcmV0dXJuIHAubmFtZTtcbiAgICB9KTsgLy8gYWxsb3cgYWNjZXNzIG9mIHByb3BlcnRpZXMgYnkgbmFtZSAoIGUuZy4gc3R5bGUucHJvcGVydGllcy5oZWlnaHQgKVxuXG4gICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IHByb3BzLmxlbmd0aDsgX2krKykge1xuICAgICAgdmFyIHByb3AgPSBwcm9wc1tfaV07XG4gICAgICBwcm9wc1twcm9wLm5hbWVdID0gcHJvcDsgLy8gYWxsb3cgbG9va3VwIGJ5IG5hbWVcbiAgICB9IC8vIG1hcCBhbGlhc2VzXG5cblxuICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IGFsaWFzZXMubGVuZ3RoOyBfaTIrKykge1xuICAgICAgdmFyIGFsaWFzID0gYWxpYXNlc1tfaTJdO1xuICAgICAgdmFyIHBvaW50c1RvUHJvcCA9IHByb3BzW2FsaWFzLnBvaW50c1RvXTtcbiAgICAgIHZhciBhbGlhc1Byb3AgPSB7XG4gICAgICAgIG5hbWU6IGFsaWFzLm5hbWUsXG4gICAgICAgIGFsaWFzOiB0cnVlLFxuICAgICAgICBwb2ludHNUbzogcG9pbnRzVG9Qcm9wXG4gICAgICB9OyAvLyBhZGQgYWxpYXMgcHJvcCBmb3IgcGFyc2luZ1xuXG4gICAgICBwcm9wcy5wdXNoKGFsaWFzUHJvcCk7XG4gICAgICBwcm9wc1thbGlhcy5uYW1lXSA9IGFsaWFzUHJvcDsgLy8gYWxsb3cgbG9va3VwIGJ5IG5hbWVcbiAgICB9XG4gIH0pKCk7XG5cbiAgc3R5Zm4kMi5nZXREZWZhdWx0UHJvcGVydHkgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgIHJldHVybiB0aGlzLmdldERlZmF1bHRQcm9wZXJ0aWVzKClbbmFtZV07XG4gIH07XG5cbiAgc3R5Zm4kMi5nZXREZWZhdWx0UHJvcGVydGllcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuXG4gICAgaWYgKF9wLmRlZmF1bHRQcm9wZXJ0aWVzICE9IG51bGwpIHtcbiAgICAgIHJldHVybiBfcC5kZWZhdWx0UHJvcGVydGllcztcbiAgICB9XG5cbiAgICB2YXIgcmF3UHJvcHMgPSBleHRlbmQoe1xuICAgICAgLy8gY29yZSBwcm9wc1xuICAgICAgJ3NlbGVjdGlvbi1ib3gtY29sb3InOiAnI2RkZCcsXG4gICAgICAnc2VsZWN0aW9uLWJveC1vcGFjaXR5JzogMC42NSxcbiAgICAgICdzZWxlY3Rpb24tYm94LWJvcmRlci1jb2xvcic6ICcjYWFhJyxcbiAgICAgICdzZWxlY3Rpb24tYm94LWJvcmRlci13aWR0aCc6IDEsXG4gICAgICAnYWN0aXZlLWJnLWNvbG9yJzogJ2JsYWNrJyxcbiAgICAgICdhY3RpdmUtYmctb3BhY2l0eSc6IDAuMTUsXG4gICAgICAnYWN0aXZlLWJnLXNpemUnOiAzMCxcbiAgICAgICdvdXRzaWRlLXRleHR1cmUtYmctY29sb3InOiAnIzAwMCcsXG4gICAgICAnb3V0c2lkZS10ZXh0dXJlLWJnLW9wYWNpdHknOiAwLjEyNSxcbiAgICAgIC8vIGNvbW1vbiBub2RlL2VkZ2UgcHJvcHNcbiAgICAgICdldmVudHMnOiAneWVzJyxcbiAgICAgICd0ZXh0LWV2ZW50cyc6ICdubycsXG4gICAgICAndGV4dC12YWxpZ24nOiAndG9wJyxcbiAgICAgICd0ZXh0LWhhbGlnbic6ICdjZW50ZXInLFxuICAgICAgJ3RleHQtanVzdGlmaWNhdGlvbic6ICdhdXRvJyxcbiAgICAgICdsaW5lLWhlaWdodCc6IDEsXG4gICAgICAnY29sb3InOiAnIzAwMCcsXG4gICAgICAndGV4dC1vdXRsaW5lLWNvbG9yJzogJyMwMDAnLFxuICAgICAgJ3RleHQtb3V0bGluZS13aWR0aCc6IDAsXG4gICAgICAndGV4dC1vdXRsaW5lLW9wYWNpdHknOiAxLFxuICAgICAgJ3RleHQtb3BhY2l0eSc6IDEsXG4gICAgICAndGV4dC1kZWNvcmF0aW9uJzogJ25vbmUnLFxuICAgICAgJ3RleHQtdHJhbnNmb3JtJzogJ25vbmUnLFxuICAgICAgJ3RleHQtd3JhcCc6ICdub25lJyxcbiAgICAgICd0ZXh0LW92ZXJmbG93LXdyYXAnOiAnd2hpdGVzcGFjZScsXG4gICAgICAndGV4dC1tYXgtd2lkdGgnOiA5OTk5LFxuICAgICAgJ3RleHQtYmFja2dyb3VuZC1jb2xvcic6ICcjMDAwJyxcbiAgICAgICd0ZXh0LWJhY2tncm91bmQtb3BhY2l0eSc6IDAsXG4gICAgICAndGV4dC1iYWNrZ3JvdW5kLXNoYXBlJzogJ3JlY3RhbmdsZScsXG4gICAgICAndGV4dC1iYWNrZ3JvdW5kLXBhZGRpbmcnOiAwLFxuICAgICAgJ3RleHQtYm9yZGVyLW9wYWNpdHknOiAwLFxuICAgICAgJ3RleHQtYm9yZGVyLXdpZHRoJzogMCxcbiAgICAgICd0ZXh0LWJvcmRlci1zdHlsZSc6ICdzb2xpZCcsXG4gICAgICAndGV4dC1ib3JkZXItY29sb3InOiAnIzAwMCcsXG4gICAgICAnZm9udC1mYW1pbHknOiAnSGVsdmV0aWNhIE5ldWUsIEhlbHZldGljYSwgc2Fucy1zZXJpZicsXG4gICAgICAnZm9udC1zdHlsZSc6ICdub3JtYWwnLFxuICAgICAgJ2ZvbnQtd2VpZ2h0JzogJ25vcm1hbCcsXG4gICAgICAnZm9udC1zaXplJzogMTYsXG4gICAgICAnbWluLXpvb21lZC1mb250LXNpemUnOiAwLFxuICAgICAgJ3RleHQtcm90YXRpb24nOiAnbm9uZScsXG4gICAgICAnc291cmNlLXRleHQtcm90YXRpb24nOiAnbm9uZScsXG4gICAgICAndGFyZ2V0LXRleHQtcm90YXRpb24nOiAnbm9uZScsXG4gICAgICAndmlzaWJpbGl0eSc6ICd2aXNpYmxlJyxcbiAgICAgICdkaXNwbGF5JzogJ2VsZW1lbnQnLFxuICAgICAgJ29wYWNpdHknOiAxLFxuICAgICAgJ3otY29tcG91bmQtZGVwdGgnOiAnYXV0bycsXG4gICAgICAnei1pbmRleC1jb21wYXJlJzogJ2F1dG8nLFxuICAgICAgJ3otaW5kZXgnOiAwLFxuICAgICAgJ2xhYmVsJzogJycsXG4gICAgICAndGV4dC1tYXJnaW4teCc6IDAsXG4gICAgICAndGV4dC1tYXJnaW4teSc6IDAsXG4gICAgICAnc291cmNlLWxhYmVsJzogJycsXG4gICAgICAnc291cmNlLXRleHQtb2Zmc2V0JzogMCxcbiAgICAgICdzb3VyY2UtdGV4dC1tYXJnaW4teCc6IDAsXG4gICAgICAnc291cmNlLXRleHQtbWFyZ2luLXknOiAwLFxuICAgICAgJ3RhcmdldC1sYWJlbCc6ICcnLFxuICAgICAgJ3RhcmdldC10ZXh0LW9mZnNldCc6IDAsXG4gICAgICAndGFyZ2V0LXRleHQtbWFyZ2luLXgnOiAwLFxuICAgICAgJ3RhcmdldC10ZXh0LW1hcmdpbi15JzogMCxcbiAgICAgICdvdmVybGF5LW9wYWNpdHknOiAwLFxuICAgICAgJ292ZXJsYXktY29sb3InOiAnIzAwMCcsXG4gICAgICAnb3ZlcmxheS1wYWRkaW5nJzogMTAsXG4gICAgICAnb3ZlcmxheS1zaGFwZSc6ICdyb3VuZC1yZWN0YW5nbGUnLFxuICAgICAgJ3VuZGVybGF5LW9wYWNpdHknOiAwLFxuICAgICAgJ3VuZGVybGF5LWNvbG9yJzogJyMwMDAnLFxuICAgICAgJ3VuZGVybGF5LXBhZGRpbmcnOiAxMCxcbiAgICAgICd1bmRlcmxheS1zaGFwZSc6ICdyb3VuZC1yZWN0YW5nbGUnLFxuICAgICAgJ3RyYW5zaXRpb24tcHJvcGVydHknOiAnbm9uZScsXG4gICAgICAndHJhbnNpdGlvbi1kdXJhdGlvbic6IDAsXG4gICAgICAndHJhbnNpdGlvbi1kZWxheSc6IDAsXG4gICAgICAndHJhbnNpdGlvbi10aW1pbmctZnVuY3Rpb24nOiAnbGluZWFyJyxcbiAgICAgIC8vIG5vZGUgcHJvcHNcbiAgICAgICdiYWNrZ3JvdW5kLWJsYWNrZW4nOiAwLFxuICAgICAgJ2JhY2tncm91bmQtY29sb3InOiAnIzk5OScsXG4gICAgICAnYmFja2dyb3VuZC1maWxsJzogJ3NvbGlkJyxcbiAgICAgICdiYWNrZ3JvdW5kLW9wYWNpdHknOiAxLFxuICAgICAgJ2JhY2tncm91bmQtaW1hZ2UnOiAnbm9uZScsXG4gICAgICAnYmFja2dyb3VuZC1pbWFnZS1jcm9zc29yaWdpbic6ICdhbm9ueW1vdXMnLFxuICAgICAgJ2JhY2tncm91bmQtaW1hZ2Utb3BhY2l0eSc6IDEsXG4gICAgICAnYmFja2dyb3VuZC1pbWFnZS1jb250YWlubWVudCc6ICdpbnNpZGUnLFxuICAgICAgJ2JhY2tncm91bmQtaW1hZ2Utc21vb3RoaW5nJzogJ3llcycsXG4gICAgICAnYmFja2dyb3VuZC1wb3NpdGlvbi14JzogJzUwJScsXG4gICAgICAnYmFja2dyb3VuZC1wb3NpdGlvbi15JzogJzUwJScsXG4gICAgICAnYmFja2dyb3VuZC1vZmZzZXQteCc6IDAsXG4gICAgICAnYmFja2dyb3VuZC1vZmZzZXQteSc6IDAsXG4gICAgICAnYmFja2dyb3VuZC13aWR0aC1yZWxhdGl2ZS10byc6ICdpbmNsdWRlLXBhZGRpbmcnLFxuICAgICAgJ2JhY2tncm91bmQtaGVpZ2h0LXJlbGF0aXZlLXRvJzogJ2luY2x1ZGUtcGFkZGluZycsXG4gICAgICAnYmFja2dyb3VuZC1yZXBlYXQnOiAnbm8tcmVwZWF0JyxcbiAgICAgICdiYWNrZ3JvdW5kLWZpdCc6ICdub25lJyxcbiAgICAgICdiYWNrZ3JvdW5kLWNsaXAnOiAnbm9kZScsXG4gICAgICAnYmFja2dyb3VuZC13aWR0aCc6ICdhdXRvJyxcbiAgICAgICdiYWNrZ3JvdW5kLWhlaWdodCc6ICdhdXRvJyxcbiAgICAgICdib3JkZXItY29sb3InOiAnIzAwMCcsXG4gICAgICAnYm9yZGVyLW9wYWNpdHknOiAxLFxuICAgICAgJ2JvcmRlci13aWR0aCc6IDAsXG4gICAgICAnYm9yZGVyLXN0eWxlJzogJ3NvbGlkJyxcbiAgICAgICdoZWlnaHQnOiAzMCxcbiAgICAgICd3aWR0aCc6IDMwLFxuICAgICAgJ3NoYXBlJzogJ2VsbGlwc2UnLFxuICAgICAgJ3NoYXBlLXBvbHlnb24tcG9pbnRzJzogJy0xLCAtMSwgICAxLCAtMSwgICAxLCAxLCAgIC0xLCAxJyxcbiAgICAgICdib3VuZHMtZXhwYW5zaW9uJzogMCxcbiAgICAgIC8vIG5vZGUgZ3JhZGllbnRcbiAgICAgICdiYWNrZ3JvdW5kLWdyYWRpZW50LWRpcmVjdGlvbic6ICd0by1ib3R0b20nLFxuICAgICAgJ2JhY2tncm91bmQtZ3JhZGllbnQtc3RvcC1jb2xvcnMnOiAnIzk5OScsXG4gICAgICAnYmFja2dyb3VuZC1ncmFkaWVudC1zdG9wLXBvc2l0aW9ucyc6ICcwJScsXG4gICAgICAvLyBnaG9zdCBwcm9wc1xuICAgICAgJ2dob3N0JzogJ25vJyxcbiAgICAgICdnaG9zdC1vZmZzZXQteSc6IDAsXG4gICAgICAnZ2hvc3Qtb2Zmc2V0LXgnOiAwLFxuICAgICAgJ2dob3N0LW9wYWNpdHknOiAwLFxuICAgICAgLy8gY29tcG91bmQgcHJvcHNcbiAgICAgICdwYWRkaW5nJzogMCxcbiAgICAgICdwYWRkaW5nLXJlbGF0aXZlLXRvJzogJ3dpZHRoJyxcbiAgICAgICdwb3NpdGlvbic6ICdvcmlnaW4nLFxuICAgICAgJ2NvbXBvdW5kLXNpemluZy13cnQtbGFiZWxzJzogJ2luY2x1ZGUnLFxuICAgICAgJ21pbi13aWR0aCc6IDAsXG4gICAgICAnbWluLXdpZHRoLWJpYXMtbGVmdCc6IDAsXG4gICAgICAnbWluLXdpZHRoLWJpYXMtcmlnaHQnOiAwLFxuICAgICAgJ21pbi1oZWlnaHQnOiAwLFxuICAgICAgJ21pbi1oZWlnaHQtYmlhcy10b3AnOiAwLFxuICAgICAgJ21pbi1oZWlnaHQtYmlhcy1ib3R0b20nOiAwXG4gICAgfSwge1xuICAgICAgLy8gbm9kZSBwaWUgYmdcbiAgICAgICdwaWUtc2l6ZSc6ICcxMDAlJ1xuICAgIH0sIFt7XG4gICAgICBuYW1lOiAncGllLXt7aX19LWJhY2tncm91bmQtY29sb3InLFxuICAgICAgdmFsdWU6ICdibGFjaydcbiAgICB9LCB7XG4gICAgICBuYW1lOiAncGllLXt7aX19LWJhY2tncm91bmQtc2l6ZScsXG4gICAgICB2YWx1ZTogJzAlJ1xuICAgIH0sIHtcbiAgICAgIG5hbWU6ICdwaWUte3tpfX0tYmFja2dyb3VuZC1vcGFjaXR5JyxcbiAgICAgIHZhbHVlOiAxXG4gICAgfV0ucmVkdWNlKGZ1bmN0aW9uIChjc3MsIHByb3ApIHtcbiAgICAgIGZvciAodmFyIGkgPSAxOyBpIDw9IHN0eWZuJDIucGllQmFja2dyb3VuZE47IGkrKykge1xuICAgICAgICB2YXIgbmFtZSA9IHByb3AubmFtZS5yZXBsYWNlKCd7e2l9fScsIGkpO1xuICAgICAgICB2YXIgdmFsID0gcHJvcC52YWx1ZTtcbiAgICAgICAgY3NzW25hbWVdID0gdmFsO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gY3NzO1xuICAgIH0sIHt9KSwge1xuICAgICAgLy8gZWRnZSBwcm9wc1xuICAgICAgJ2xpbmUtc3R5bGUnOiAnc29saWQnLFxuICAgICAgJ2xpbmUtY29sb3InOiAnIzk5OScsXG4gICAgICAnbGluZS1maWxsJzogJ3NvbGlkJyxcbiAgICAgICdsaW5lLWNhcCc6ICdidXR0JyxcbiAgICAgICdsaW5lLW9wYWNpdHknOiAxLFxuICAgICAgJ2xpbmUtZ3JhZGllbnQtc3RvcC1jb2xvcnMnOiAnIzk5OScsXG4gICAgICAnbGluZS1ncmFkaWVudC1zdG9wLXBvc2l0aW9ucyc6ICcwJScsXG4gICAgICAnY29udHJvbC1wb2ludC1zdGVwLXNpemUnOiA0MCxcbiAgICAgICdjb250cm9sLXBvaW50LXdlaWdodHMnOiAwLjUsXG4gICAgICAnc2VnbWVudC13ZWlnaHRzJzogMC41LFxuICAgICAgJ3NlZ21lbnQtZGlzdGFuY2VzJzogMjAsXG4gICAgICAndGF4aS10dXJuJzogJzUwJScsXG4gICAgICAndGF4aS10dXJuLW1pbi1kaXN0YW5jZSc6IDEwLFxuICAgICAgJ3RheGktZGlyZWN0aW9uJzogJ2F1dG8nLFxuICAgICAgJ2VkZ2UtZGlzdGFuY2VzJzogJ2ludGVyc2VjdGlvbicsXG4gICAgICAnY3VydmUtc3R5bGUnOiAnaGF5c3RhY2snLFxuICAgICAgJ2hheXN0YWNrLXJhZGl1cyc6IDAsXG4gICAgICAnYXJyb3ctc2NhbGUnOiAxLFxuICAgICAgJ2xvb3AtZGlyZWN0aW9uJzogJy00NWRlZycsXG4gICAgICAnbG9vcC1zd2VlcCc6ICctOTBkZWcnLFxuICAgICAgJ3NvdXJjZS1kaXN0YW5jZS1mcm9tLW5vZGUnOiAwLFxuICAgICAgJ3RhcmdldC1kaXN0YW5jZS1mcm9tLW5vZGUnOiAwLFxuICAgICAgJ3NvdXJjZS1lbmRwb2ludCc6ICdvdXRzaWRlLXRvLW5vZGUnLFxuICAgICAgJ3RhcmdldC1lbmRwb2ludCc6ICdvdXRzaWRlLXRvLW5vZGUnLFxuICAgICAgJ2xpbmUtZGFzaC1wYXR0ZXJuJzogWzYsIDNdLFxuICAgICAgJ2xpbmUtZGFzaC1vZmZzZXQnOiAwXG4gICAgfSwgW3tcbiAgICAgIG5hbWU6ICdhcnJvdy1zaGFwZScsXG4gICAgICB2YWx1ZTogJ25vbmUnXG4gICAgfSwge1xuICAgICAgbmFtZTogJ2Fycm93LWNvbG9yJyxcbiAgICAgIHZhbHVlOiAnIzk5OSdcbiAgICB9LCB7XG4gICAgICBuYW1lOiAnYXJyb3ctZmlsbCcsXG4gICAgICB2YWx1ZTogJ2ZpbGxlZCdcbiAgICB9XS5yZWR1Y2UoZnVuY3Rpb24gKGNzcywgcHJvcCkge1xuICAgICAgc3R5Zm4kMi5hcnJvd1ByZWZpeGVzLmZvckVhY2goZnVuY3Rpb24gKHByZWZpeCkge1xuICAgICAgICB2YXIgbmFtZSA9IHByZWZpeCArICctJyArIHByb3AubmFtZTtcbiAgICAgICAgdmFyIHZhbCA9IHByb3AudmFsdWU7XG4gICAgICAgIGNzc1tuYW1lXSA9IHZhbDtcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIGNzcztcbiAgICB9LCB7fSkpO1xuICAgIHZhciBwYXJzZWRQcm9wcyA9IHt9O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnByb3BlcnRpZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBwcm9wID0gdGhpcy5wcm9wZXJ0aWVzW2ldO1xuXG4gICAgICBpZiAocHJvcC5wb2ludHNUbykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdmFyIG5hbWUgPSBwcm9wLm5hbWU7XG4gICAgICB2YXIgdmFsID0gcmF3UHJvcHNbbmFtZV07XG4gICAgICB2YXIgcGFyc2VkUHJvcCA9IHRoaXMucGFyc2UobmFtZSwgdmFsKTtcbiAgICAgIHBhcnNlZFByb3BzW25hbWVdID0gcGFyc2VkUHJvcDtcbiAgICB9XG5cbiAgICBfcC5kZWZhdWx0UHJvcGVydGllcyA9IHBhcnNlZFByb3BzO1xuICAgIHJldHVybiBfcC5kZWZhdWx0UHJvcGVydGllcztcbiAgfTtcblxuICBzdHlmbiQyLmFkZERlZmF1bHRTdHlsZXNoZWV0ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuc2VsZWN0b3IoJzpwYXJlbnQnKS5jc3Moe1xuICAgICAgJ3NoYXBlJzogJ3JlY3RhbmdsZScsXG4gICAgICAncGFkZGluZyc6IDEwLFxuICAgICAgJ2JhY2tncm91bmQtY29sb3InOiAnI2VlZScsXG4gICAgICAnYm9yZGVyLWNvbG9yJzogJyNjY2MnLFxuICAgICAgJ2JvcmRlci13aWR0aCc6IDFcbiAgICB9KS5zZWxlY3RvcignZWRnZScpLmNzcyh7XG4gICAgICAnd2lkdGgnOiAzXG4gICAgfSkuc2VsZWN0b3IoJzpsb29wJykuY3NzKHtcbiAgICAgICdjdXJ2ZS1zdHlsZSc6ICdiZXppZXInXG4gICAgfSkuc2VsZWN0b3IoJ2VkZ2U6Y29tcG91bmQnKS5jc3Moe1xuICAgICAgJ2N1cnZlLXN0eWxlJzogJ2JlemllcicsXG4gICAgICAnc291cmNlLWVuZHBvaW50JzogJ291dHNpZGUtdG8tbGluZScsXG4gICAgICAndGFyZ2V0LWVuZHBvaW50JzogJ291dHNpZGUtdG8tbGluZSdcbiAgICB9KS5zZWxlY3RvcignOnNlbGVjdGVkJykuY3NzKHtcbiAgICAgICdiYWNrZ3JvdW5kLWNvbG9yJzogJyMwMTY5RDknLFxuICAgICAgJ2xpbmUtY29sb3InOiAnIzAxNjlEOScsXG4gICAgICAnc291cmNlLWFycm93LWNvbG9yJzogJyMwMTY5RDknLFxuICAgICAgJ3RhcmdldC1hcnJvdy1jb2xvcic6ICcjMDE2OUQ5JyxcbiAgICAgICdtaWQtc291cmNlLWFycm93LWNvbG9yJzogJyMwMTY5RDknLFxuICAgICAgJ21pZC10YXJnZXQtYXJyb3ctY29sb3InOiAnIzAxNjlEOSdcbiAgICB9KS5zZWxlY3RvcignOnBhcmVudDpzZWxlY3RlZCcpLmNzcyh7XG4gICAgICAnYmFja2dyb3VuZC1jb2xvcic6ICcjQ0NFMUY5JyxcbiAgICAgICdib3JkZXItY29sb3InOiAnI2FlYzhlNSdcbiAgICB9KS5zZWxlY3RvcignOmFjdGl2ZScpLmNzcyh7XG4gICAgICAnb3ZlcmxheS1jb2xvcic6ICdibGFjaycsXG4gICAgICAnb3ZlcmxheS1wYWRkaW5nJzogMTAsXG4gICAgICAnb3ZlcmxheS1vcGFjaXR5JzogMC4yNVxuICAgIH0pO1xuICAgIHRoaXMuZGVmYXVsdExlbmd0aCA9IHRoaXMubGVuZ3RoO1xuICB9O1xuXG4gIHZhciBzdHlmbiQxID0ge307IC8vIGEgY2FjaGluZyBsYXllciBmb3IgcHJvcGVydHkgcGFyc2luZ1xuXG4gIHN0eWZuJDEucGFyc2UgPSBmdW5jdGlvbiAobmFtZSwgdmFsdWUsIHByb3BJc0J5cGFzcywgcHJvcElzRmxhdCkge1xuICAgIHZhciBzZWxmID0gdGhpczsgLy8gZnVuY3Rpb24gdmFsdWVzIGNhbid0IGJlIGNhY2hlZCBpbiBhbGwgY2FzZXMsIGFuZCB0aGVyZSBpc24ndCBtdWNoIGJlbmVmaXQgb2YgY2FjaGluZyB0aGVtIGFueXdheVxuXG4gICAgaWYgKGZuJDYodmFsdWUpKSB7XG4gICAgICByZXR1cm4gc2VsZi5wYXJzZUltcGxXYXJuKG5hbWUsIHZhbHVlLCBwcm9wSXNCeXBhc3MsIHByb3BJc0ZsYXQpO1xuICAgIH1cblxuICAgIHZhciBmbGF0S2V5ID0gcHJvcElzRmxhdCA9PT0gJ21hcHBpbmcnIHx8IHByb3BJc0ZsYXQgPT09IHRydWUgfHwgcHJvcElzRmxhdCA9PT0gZmFsc2UgfHwgcHJvcElzRmxhdCA9PSBudWxsID8gJ2RvbnRjYXJlJyA6IHByb3BJc0ZsYXQ7XG4gICAgdmFyIGJ5cGFzc0tleSA9IHByb3BJc0J5cGFzcyA/ICd0JyA6ICdmJztcbiAgICB2YXIgdmFsdWVLZXkgPSAnJyArIHZhbHVlO1xuICAgIHZhciBhcmdIYXNoID0gaGFzaFN0cmluZ3MobmFtZSwgdmFsdWVLZXksIGJ5cGFzc0tleSwgZmxhdEtleSk7XG4gICAgdmFyIHByb3BDYWNoZSA9IHNlbGYucHJvcENhY2hlID0gc2VsZi5wcm9wQ2FjaGUgfHwgW107XG4gICAgdmFyIHJldDtcblxuICAgIGlmICghKHJldCA9IHByb3BDYWNoZVthcmdIYXNoXSkpIHtcbiAgICAgIHJldCA9IHByb3BDYWNoZVthcmdIYXNoXSA9IHNlbGYucGFyc2VJbXBsV2FybihuYW1lLCB2YWx1ZSwgcHJvcElzQnlwYXNzLCBwcm9wSXNGbGF0KTtcbiAgICB9IC8vIC0gYnlwYXNzZXMgY2FuJ3QgYmUgc2hhcmVkIGIvYyB0aGUgdmFsdWUgY2FuIGJlIGNoYW5nZWQgYnkgYW5pbWF0aW9ucyBvciBvdGhlcndpc2Ugb3ZlcnJpZGRlblxuICAgIC8vIC0gbWFwcGluZ3MgY2FuJ3QgYmUgc2hhcmVkIGIvYyBtYXBwaW5ncyBhcmUgcGVyLWVsZW1lbnRcblxuXG4gICAgaWYgKHByb3BJc0J5cGFzcyB8fCBwcm9wSXNGbGF0ID09PSAnbWFwcGluZycpIHtcbiAgICAgIC8vIG5lZWQgYSBjb3B5IHNpbmNlIHByb3BzIGFyZSBtdXRhdGVkIGxhdGVyIGluIHRoZWlyIGxpZmVjeWNsZXNcbiAgICAgIHJldCA9IGNvcHkocmV0KTtcblxuICAgICAgaWYgKHJldCkge1xuICAgICAgICByZXQudmFsdWUgPSBjb3B5KHJldC52YWx1ZSk7IC8vIGJlY2F1c2UgaXQgY291bGQgYmUgYW4gYXJyYXksIGUuZy4gY29sb3VyXG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJldDtcbiAgfTtcblxuICBzdHlmbiQxLnBhcnNlSW1wbFdhcm4gPSBmdW5jdGlvbiAobmFtZSwgdmFsdWUsIHByb3BJc0J5cGFzcywgcHJvcElzRmxhdCkge1xuICAgIHZhciBwcm9wID0gdGhpcy5wYXJzZUltcGwobmFtZSwgdmFsdWUsIHByb3BJc0J5cGFzcywgcHJvcElzRmxhdCk7XG5cbiAgICBpZiAoIXByb3AgJiYgdmFsdWUgIT0gbnVsbCkge1xuICAgICAgd2FybihcIlRoZSBzdHlsZSBwcm9wZXJ0eSBgXCIuY29uY2F0KG5hbWUsIFwiOiBcIikuY29uY2F0KHZhbHVlLCBcImAgaXMgaW52YWxpZFwiKSk7XG4gICAgfVxuXG4gICAgaWYgKHByb3AgJiYgKHByb3AubmFtZSA9PT0gJ3dpZHRoJyB8fCBwcm9wLm5hbWUgPT09ICdoZWlnaHQnKSAmJiB2YWx1ZSA9PT0gJ2xhYmVsJykge1xuICAgICAgd2FybignVGhlIHN0eWxlIHZhbHVlIG9mIGBsYWJlbGAgaXMgZGVwcmVjYXRlZCBmb3IgYCcgKyBwcm9wLm5hbWUgKyAnYCcpO1xuICAgIH1cblxuICAgIHJldHVybiBwcm9wO1xuICB9OyAvLyBwYXJzZSBhIHByb3BlcnR5OyByZXR1cm4gbnVsbCBvbiBpbnZhbGlkOyByZXR1cm4gcGFyc2VkIHByb3BlcnR5IG90aGVyd2lzZVxuICAvLyBmaWVsZHMgOlxuICAvLyAtIG5hbWUgOiB0aGUgbmFtZSBvZiB0aGUgcHJvcGVydHlcbiAgLy8gLSB2YWx1ZSA6IHRoZSBwYXJzZWQsIG5hdGl2ZS10eXBlZCB2YWx1ZSBvZiB0aGUgcHJvcGVydHlcbiAgLy8gLSBzdHJWYWx1ZSA6IGEgc3RyaW5nIHZhbHVlIHRoYXQgcmVwcmVzZW50cyB0aGUgcHJvcGVydHkgdmFsdWUgaW4gdmFsaWQgY3NzXG4gIC8vIC0gYnlwYXNzIDogdHJ1ZSBpZmYgdGhlIHByb3BlcnR5IGlzIGEgYnlwYXNzIHByb3BlcnR5XG5cblxuICBzdHlmbiQxLnBhcnNlSW1wbCA9IGZ1bmN0aW9uIChuYW1lLCB2YWx1ZSwgcHJvcElzQnlwYXNzLCBwcm9wSXNGbGF0KSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIG5hbWUgPSBjYW1lbDJkYXNoKG5hbWUpOyAvLyBtYWtlIHN1cmUgdGhlIHByb3BlcnR5IG5hbWUgaXMgaW4gZGFzaCBmb3JtIChlLmcuICdwcm9wZXJ0eS1uYW1lJyBub3QgJ3Byb3BlcnR5TmFtZScpXG5cbiAgICB2YXIgcHJvcGVydHkgPSBzZWxmLnByb3BlcnRpZXNbbmFtZV07XG4gICAgdmFyIHBhc3NlZFZhbHVlID0gdmFsdWU7XG4gICAgdmFyIHR5cGVzID0gc2VsZi50eXBlcztcblxuICAgIGlmICghcHJvcGVydHkpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gLy8gcmV0dXJuIG51bGwgb24gcHJvcGVydHkgb2YgdW5rbm93biBuYW1lXG5cblxuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9IC8vIGNhbid0IGFzc2lnbiB1bmRlZmluZWRcbiAgICAvLyB0aGUgcHJvcGVydHkgbWF5IGJlIGFuIGFsaWFzXG5cblxuICAgIGlmIChwcm9wZXJ0eS5hbGlhcykge1xuICAgICAgcHJvcGVydHkgPSBwcm9wZXJ0eS5wb2ludHNUbztcbiAgICAgIG5hbWUgPSBwcm9wZXJ0eS5uYW1lO1xuICAgIH1cblxuICAgIHZhciB2YWx1ZUlzU3RyaW5nID0gc3RyaW5nKHZhbHVlKTtcblxuICAgIGlmICh2YWx1ZUlzU3RyaW5nKSB7XG4gICAgICAvLyB0cmltIHRoZSB2YWx1ZSB0byBtYWtlIHBhcnNpbmcgZWFzaWVyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcbiAgICB9XG5cbiAgICB2YXIgdHlwZSA9IHByb3BlcnR5LnR5cGU7XG5cbiAgICBpZiAoIXR5cGUpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gLy8gbm8gdHlwZSwgbm8gbHVja1xuICAgIC8vIGNoZWNrIGlmIGJ5cGFzcyBpcyBudWxsIG9yIGVtcHR5IHN0cmluZyAoaS5lLiBpbmRpY2F0aW9uIHRvIGRlbGV0ZSBieXBhc3MgcHJvcGVydHkpXG5cblxuICAgIGlmIChwcm9wSXNCeXBhc3MgJiYgKHZhbHVlID09PSAnJyB8fCB2YWx1ZSA9PT0gbnVsbCkpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgIHZhbHVlOiB2YWx1ZSxcbiAgICAgICAgYnlwYXNzOiB0cnVlLFxuICAgICAgICBkZWxldGVCeXBhc3M6IHRydWVcbiAgICAgIH07XG4gICAgfSAvLyBjaGVjayBpZiB2YWx1ZSBpcyBhIGZ1bmN0aW9uIHVzZWQgYXMgYSBtYXBwZXJcblxuXG4gICAgaWYgKGZuJDYodmFsdWUpKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBuYW1lOiBuYW1lLFxuICAgICAgICB2YWx1ZTogdmFsdWUsXG4gICAgICAgIHN0clZhbHVlOiAnZm4nLFxuICAgICAgICBtYXBwZWQ6IHR5cGVzLmZuLFxuICAgICAgICBieXBhc3M6IHByb3BJc0J5cGFzc1xuICAgICAgfTtcbiAgICB9IC8vIGNoZWNrIGlmIHZhbHVlIGlzIG1hcHBlZFxuXG5cbiAgICB2YXIgZGF0YSwgbWFwRGF0YTtcblxuICAgIGlmICghdmFsdWVJc1N0cmluZyB8fCBwcm9wSXNGbGF0IHx8IHZhbHVlLmxlbmd0aCA8IDcgfHwgdmFsdWVbMV0gIT09ICdhJykgOyBlbHNlIGlmICh2YWx1ZS5sZW5ndGggPj0gNyAmJiB2YWx1ZVswXSA9PT0gJ2QnICYmIChkYXRhID0gbmV3IFJlZ0V4cCh0eXBlcy5kYXRhLnJlZ2V4KS5leGVjKHZhbHVlKSkpIHtcbiAgICAgIGlmIChwcm9wSXNCeXBhc3MpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSAvLyBtYXBwZXJzIG5vdCBhbGxvd2VkIGluIGJ5cGFzc1xuXG5cbiAgICAgIHZhciBtYXBwZWQgPSB0eXBlcy5kYXRhO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgdmFsdWU6IGRhdGEsXG4gICAgICAgIHN0clZhbHVlOiAnJyArIHZhbHVlLFxuICAgICAgICBtYXBwZWQ6IG1hcHBlZCxcbiAgICAgICAgZmllbGQ6IGRhdGFbMV0sXG4gICAgICAgIGJ5cGFzczogcHJvcElzQnlwYXNzXG4gICAgICB9O1xuICAgIH0gZWxzZSBpZiAodmFsdWUubGVuZ3RoID49IDEwICYmIHZhbHVlWzBdID09PSAnbScgJiYgKG1hcERhdGEgPSBuZXcgUmVnRXhwKHR5cGVzLm1hcERhdGEucmVnZXgpLmV4ZWModmFsdWUpKSkge1xuICAgICAgaWYgKHByb3BJc0J5cGFzcykge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9IC8vIG1hcHBlcnMgbm90IGFsbG93ZWQgaW4gYnlwYXNzXG5cblxuICAgICAgaWYgKHR5cGUubXVsdGlwbGUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSAvLyBpbXBvc3NpYmxlIHRvIG1hcCB0byBudW1cblxuXG4gICAgICB2YXIgX21hcHBlZCA9IHR5cGVzLm1hcERhdGE7IC8vIHdlIGNhbiBtYXAgb25seSBpZiB0aGUgdHlwZSBpcyBhIGNvbG91ciBvciBhIG51bWJlclxuXG4gICAgICBpZiAoISh0eXBlLmNvbG9yIHx8IHR5cGUubnVtYmVyKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIHZhciB2YWx1ZU1pbiA9IHRoaXMucGFyc2UobmFtZSwgbWFwRGF0YVs0XSk7IC8vIHBhcnNlIHRvIHZhbGlkYXRlXG5cbiAgICAgIGlmICghdmFsdWVNaW4gfHwgdmFsdWVNaW4ubWFwcGVkKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0gLy8gY2FuJ3QgYmUgaW52YWxpZCBvciBtYXBwZWRcblxuXG4gICAgICB2YXIgdmFsdWVNYXggPSB0aGlzLnBhcnNlKG5hbWUsIG1hcERhdGFbNV0pOyAvLyBwYXJzZSB0byB2YWxpZGF0ZVxuXG4gICAgICBpZiAoIXZhbHVlTWF4IHx8IHZhbHVlTWF4Lm1hcHBlZCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9IC8vIGNhbid0IGJlIGludmFsaWQgb3IgbWFwcGVkXG4gICAgICAvLyBjaGVjayBpZiB2YWx1ZU1pbiBhbmQgdmFsdWVNYXggYXJlIHRoZSBzYW1lXG5cblxuICAgICAgaWYgKHZhbHVlTWluLnBmVmFsdWUgPT09IHZhbHVlTWF4LnBmVmFsdWUgfHwgdmFsdWVNaW4uc3RyVmFsdWUgPT09IHZhbHVlTWF4LnN0clZhbHVlKSB7XG4gICAgICAgIHdhcm4oJ2AnICsgbmFtZSArICc6ICcgKyB2YWx1ZSArICdgIGlzIG5vdCBhIHZhbGlkIG1hcHBlciBiZWNhdXNlIHRoZSBvdXRwdXQgcmFuZ2UgaXMgemVybzsgY29udmVydGluZyB0byBgJyArIG5hbWUgKyAnOiAnICsgdmFsdWVNaW4uc3RyVmFsdWUgKyAnYCcpO1xuICAgICAgICByZXR1cm4gdGhpcy5wYXJzZShuYW1lLCB2YWx1ZU1pbi5zdHJWYWx1ZSk7IC8vIGNhbid0IG1ha2UgbXVjaCBvZiBhIG1hcHBlciB3aXRob3V0IGEgcmFuZ2VcbiAgICAgIH0gZWxzZSBpZiAodHlwZS5jb2xvcikge1xuICAgICAgICB2YXIgYzEgPSB2YWx1ZU1pbi52YWx1ZTtcbiAgICAgICAgdmFyIGMyID0gdmFsdWVNYXgudmFsdWU7XG4gICAgICAgIHZhciBzYW1lID0gYzFbMF0gPT09IGMyWzBdIC8vIHJlZFxuICAgICAgICAmJiBjMVsxXSA9PT0gYzJbMV0gLy8gZ3JlZW5cbiAgICAgICAgJiYgYzFbMl0gPT09IGMyWzJdIC8vIGJsdWVcbiAgICAgICAgJiYgKCAvLyBvcHRpb25hbCBhbHBoYVxuICAgICAgICBjMVszXSA9PT0gYzJbM10gLy8gc2FtZSBhbHBoYSBvdXRyaWdodFxuICAgICAgICB8fCAoYzFbM10gPT0gbnVsbCB8fCBjMVszXSA9PT0gMSAvLyBmdWxsIG9wYWNpdHkgZm9yIGNvbG91ciAxP1xuICAgICAgICApICYmIChjMlszXSA9PSBudWxsIHx8IGMyWzNdID09PSAxKSAvLyBmdWxsIG9wYWNpdHkgZm9yIGNvbG91ciAyP1xuICAgICAgICApO1xuXG4gICAgICAgIGlmIChzYW1lKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9IC8vIGNhbid0IG1ha2UgYSBtYXBwZXIgd2l0aG91dCBhIHJhbmdlXG5cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgdmFsdWU6IG1hcERhdGEsXG4gICAgICAgIHN0clZhbHVlOiAnJyArIHZhbHVlLFxuICAgICAgICBtYXBwZWQ6IF9tYXBwZWQsXG4gICAgICAgIGZpZWxkOiBtYXBEYXRhWzFdLFxuICAgICAgICBmaWVsZE1pbjogcGFyc2VGbG9hdChtYXBEYXRhWzJdKSxcbiAgICAgICAgLy8gbWluICYgbWF4IGFyZSBudW1lcmljXG4gICAgICAgIGZpZWxkTWF4OiBwYXJzZUZsb2F0KG1hcERhdGFbM10pLFxuICAgICAgICB2YWx1ZU1pbjogdmFsdWVNaW4udmFsdWUsXG4gICAgICAgIHZhbHVlTWF4OiB2YWx1ZU1heC52YWx1ZSxcbiAgICAgICAgYnlwYXNzOiBwcm9wSXNCeXBhc3NcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKHR5cGUubXVsdGlwbGUgJiYgcHJvcElzRmxhdCAhPT0gJ211bHRpcGxlJykge1xuICAgICAgdmFyIHZhbHM7XG5cbiAgICAgIGlmICh2YWx1ZUlzU3RyaW5nKSB7XG4gICAgICAgIHZhbHMgPSB2YWx1ZS5zcGxpdCgvXFxzKy8pO1xuICAgICAgfSBlbHNlIGlmIChhcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgdmFscyA9IHZhbHVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFscyA9IFt2YWx1ZV07XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlLmV2ZW5NdWx0aXBsZSAmJiB2YWxzLmxlbmd0aCAlIDIgIT09IDApIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIHZhciB2YWxBcnIgPSBbXTtcbiAgICAgIHZhciB1bml0c0FyciA9IFtdO1xuICAgICAgdmFyIHBmVmFsQXJyID0gW107XG4gICAgICB2YXIgc3RyVmFsID0gJyc7XG4gICAgICB2YXIgaGFzRW51bSA9IGZhbHNlO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZhbHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHAgPSBzZWxmLnBhcnNlKG5hbWUsIHZhbHNbaV0sIHByb3BJc0J5cGFzcywgJ211bHRpcGxlJyk7XG4gICAgICAgIGhhc0VudW0gPSBoYXNFbnVtIHx8IHN0cmluZyhwLnZhbHVlKTtcbiAgICAgICAgdmFsQXJyLnB1c2gocC52YWx1ZSk7XG4gICAgICAgIHBmVmFsQXJyLnB1c2gocC5wZlZhbHVlICE9IG51bGwgPyBwLnBmVmFsdWUgOiBwLnZhbHVlKTtcbiAgICAgICAgdW5pdHNBcnIucHVzaChwLnVuaXRzKTtcbiAgICAgICAgc3RyVmFsICs9IChpID4gMCA/ICcgJyA6ICcnKSArIHAuc3RyVmFsdWU7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlLnZhbGlkYXRlICYmICF0eXBlLnZhbGlkYXRlKHZhbEFyciwgdW5pdHNBcnIpKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBpZiAodHlwZS5zaW5nbGVFbnVtICYmIGhhc0VudW0pIHtcbiAgICAgICAgaWYgKHZhbEFyci5sZW5ndGggPT09IDEgJiYgc3RyaW5nKHZhbEFyclswXSkpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgICAgIHZhbHVlOiB2YWxBcnJbMF0sXG4gICAgICAgICAgICBzdHJWYWx1ZTogdmFsQXJyWzBdLFxuICAgICAgICAgICAgYnlwYXNzOiBwcm9wSXNCeXBhc3NcbiAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgIHZhbHVlOiB2YWxBcnIsXG4gICAgICAgIHBmVmFsdWU6IHBmVmFsQXJyLFxuICAgICAgICBzdHJWYWx1ZTogc3RyVmFsLFxuICAgICAgICBieXBhc3M6IHByb3BJc0J5cGFzcyxcbiAgICAgICAgdW5pdHM6IHVuaXRzQXJyXG4gICAgICB9O1xuICAgIH0gLy8gc2V2ZXJhbCB0eXBlcyBhbHNvIGFsbG93IGVudW1zXG5cblxuICAgIHZhciBjaGVja0VudW1zID0gZnVuY3Rpb24gY2hlY2tFbnVtcygpIHtcbiAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCB0eXBlLmVudW1zLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgZW4gPSB0eXBlLmVudW1zW19pXTtcblxuICAgICAgICBpZiAoZW4gPT09IHZhbHVlKSB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgICAgICB2YWx1ZTogdmFsdWUsXG4gICAgICAgICAgICBzdHJWYWx1ZTogJycgKyB2YWx1ZSxcbiAgICAgICAgICAgIGJ5cGFzczogcHJvcElzQnlwYXNzXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9OyAvLyBjaGVjayB0aGUgdHlwZSBhbmQgcmV0dXJuIHRoZSBhcHByb3ByaWF0ZSBvYmplY3RcblxuXG4gICAgaWYgKHR5cGUubnVtYmVyKSB7XG4gICAgICB2YXIgdW5pdHM7XG4gICAgICB2YXIgaW1wbGljaXRVbml0cyA9ICdweCc7IC8vIG5vdCBzZXQgPT4gcHhcblxuICAgICAgaWYgKHR5cGUudW5pdHMpIHtcbiAgICAgICAgLy8gdXNlIHNwZWNpZmllZCB1bml0cyBpZiBzZXRcbiAgICAgICAgdW5pdHMgPSB0eXBlLnVuaXRzO1xuICAgICAgfVxuXG4gICAgICBpZiAodHlwZS5pbXBsaWNpdFVuaXRzKSB7XG4gICAgICAgIGltcGxpY2l0VW5pdHMgPSB0eXBlLmltcGxpY2l0VW5pdHM7XG4gICAgICB9XG5cbiAgICAgIGlmICghdHlwZS51bml0bGVzcykge1xuICAgICAgICBpZiAodmFsdWVJc1N0cmluZykge1xuICAgICAgICAgIHZhciB1bml0c1JlZ2V4ID0gJ3B4fGVtJyArICh0eXBlLmFsbG93UGVyY2VudCA/ICd8XFxcXCUnIDogJycpO1xuXG4gICAgICAgICAgaWYgKHVuaXRzKSB7XG4gICAgICAgICAgICB1bml0c1JlZ2V4ID0gdW5pdHM7XG4gICAgICAgICAgfSAvLyBvbmx5IGFsbG93IGV4cGxpY2l0IHVuaXRzIGlmIHNvIHNldFxuXG5cbiAgICAgICAgICB2YXIgbWF0Y2ggPSB2YWx1ZS5tYXRjaCgnXignICsgbnVtYmVyICsgJykoJyArIHVuaXRzUmVnZXggKyAnKT8nICsgJyQnKTtcblxuICAgICAgICAgIGlmIChtYXRjaCkge1xuICAgICAgICAgICAgdmFsdWUgPSBtYXRjaFsxXTtcbiAgICAgICAgICAgIHVuaXRzID0gbWF0Y2hbMl0gfHwgaW1wbGljaXRVbml0cztcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoIXVuaXRzIHx8IHR5cGUuaW1wbGljaXRVbml0cykge1xuICAgICAgICAgIHVuaXRzID0gaW1wbGljaXRVbml0czsgLy8gaW1wbGljaXRseSBweCBpZiB1bnNwZWNpZmllZFxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHZhbHVlID0gcGFyc2VGbG9hdCh2YWx1ZSk7IC8vIGlmIG5vdCBhIG51bWJlciBhbmQgZW51bXMgbm90IGFsbG93ZWQsIHRoZW4gdGhlIHZhbHVlIGlzIGludmFsaWRcblxuICAgICAgaWYgKGlzTmFOKHZhbHVlKSAmJiB0eXBlLmVudW1zID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9IC8vIGNoZWNrIGlmIHRoaXMgbnVtYmVyIHR5cGUgYWxzbyBhY2NlcHRzIHNwZWNpYWwga2V5d29yZHMgaW4gcGxhY2Ugb2YgbnVtYmVyc1xuICAgICAgLy8gKGkuZS4gYGxlZnRgLCBgYXV0b2AsIGV0YylcblxuXG4gICAgICBpZiAoaXNOYU4odmFsdWUpICYmIHR5cGUuZW51bXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB2YWx1ZSA9IHBhc3NlZFZhbHVlO1xuICAgICAgICByZXR1cm4gY2hlY2tFbnVtcygpO1xuICAgICAgfSAvLyBjaGVjayBpZiB2YWx1ZSBtdXN0IGJlIGFuIGludGVnZXJcblxuXG4gICAgICBpZiAodHlwZS5pbnRlZ2VyICYmICFpbnRlZ2VyKHZhbHVlKSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH0gLy8gY2hlY2sgdmFsdWUgaXMgd2l0aGluIHJhbmdlXG5cblxuICAgICAgaWYgKHR5cGUubWluICE9PSB1bmRlZmluZWQgJiYgKHZhbHVlIDwgdHlwZS5taW4gfHwgdHlwZS5zdHJpY3RNaW4gJiYgdmFsdWUgPT09IHR5cGUubWluKSB8fCB0eXBlLm1heCAhPT0gdW5kZWZpbmVkICYmICh2YWx1ZSA+IHR5cGUubWF4IHx8IHR5cGUuc3RyaWN0TWF4ICYmIHZhbHVlID09PSB0eXBlLm1heCkpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIHZhciByZXQgPSB7XG4gICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgIHZhbHVlOiB2YWx1ZSxcbiAgICAgICAgc3RyVmFsdWU6ICcnICsgdmFsdWUgKyAodW5pdHMgPyB1bml0cyA6ICcnKSxcbiAgICAgICAgdW5pdHM6IHVuaXRzLFxuICAgICAgICBieXBhc3M6IHByb3BJc0J5cGFzc1xuICAgICAgfTsgLy8gbm9ybWFsaXNlIHZhbHVlIGluIHBpeGVsc1xuXG4gICAgICBpZiAodHlwZS51bml0bGVzcyB8fCB1bml0cyAhPT0gJ3B4JyAmJiB1bml0cyAhPT0gJ2VtJykge1xuICAgICAgICByZXQucGZWYWx1ZSA9IHZhbHVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0LnBmVmFsdWUgPSB1bml0cyA9PT0gJ3B4JyB8fCAhdW5pdHMgPyB2YWx1ZSA6IHRoaXMuZ2V0RW1TaXplSW5QaXhlbHMoKSAqIHZhbHVlO1xuICAgICAgfSAvLyBub3JtYWxpc2UgdmFsdWUgaW4gbXNcblxuXG4gICAgICBpZiAodW5pdHMgPT09ICdtcycgfHwgdW5pdHMgPT09ICdzJykge1xuICAgICAgICByZXQucGZWYWx1ZSA9IHVuaXRzID09PSAnbXMnID8gdmFsdWUgOiAxMDAwICogdmFsdWU7XG4gICAgICB9IC8vIG5vcm1hbGlzZSB2YWx1ZSBpbiByYWRcblxuXG4gICAgICBpZiAodW5pdHMgPT09ICdkZWcnIHx8IHVuaXRzID09PSAncmFkJykge1xuICAgICAgICByZXQucGZWYWx1ZSA9IHVuaXRzID09PSAncmFkJyA/IHZhbHVlIDogZGVnMnJhZCh2YWx1ZSk7XG4gICAgICB9IC8vIG5vcm1hbGl6ZSB2YWx1ZSBpbiAlXG5cblxuICAgICAgaWYgKHVuaXRzID09PSAnJScpIHtcbiAgICAgICAgcmV0LnBmVmFsdWUgPSB2YWx1ZSAvIDEwMDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJldDtcbiAgICB9IGVsc2UgaWYgKHR5cGUucHJvcExpc3QpIHtcbiAgICAgIHZhciBwcm9wcyA9IFtdO1xuICAgICAgdmFyIHByb3BzU3RyID0gJycgKyB2YWx1ZTtcblxuICAgICAgaWYgKHByb3BzU3RyID09PSAnbm9uZScpIDsgZWxzZSB7XG4gICAgICAgIC8vIGdvIG92ZXIgZWFjaCBwcm9wXG4gICAgICAgIHZhciBwcm9wc1NwbGl0ID0gcHJvcHNTdHIuc3BsaXQoL1xccyosXFxzKnxcXHMrLyk7XG5cbiAgICAgICAgZm9yICh2YXIgX2kyID0gMDsgX2kyIDwgcHJvcHNTcGxpdC5sZW5ndGg7IF9pMisrKSB7XG4gICAgICAgICAgdmFyIHByb3BOYW1lID0gcHJvcHNTcGxpdFtfaTJdLnRyaW0oKTtcblxuICAgICAgICAgIGlmIChzZWxmLnByb3BlcnRpZXNbcHJvcE5hbWVdKSB7XG4gICAgICAgICAgICBwcm9wcy5wdXNoKHByb3BOYW1lKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgd2FybignYCcgKyBwcm9wTmFtZSArICdgIGlzIG5vdCBhIHZhbGlkIHByb3BlcnR5IG5hbWUnKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocHJvcHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgdmFsdWU6IHByb3BzLFxuICAgICAgICBzdHJWYWx1ZTogcHJvcHMubGVuZ3RoID09PSAwID8gJ25vbmUnIDogcHJvcHMuam9pbignICcpLFxuICAgICAgICBieXBhc3M6IHByb3BJc0J5cGFzc1xuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKHR5cGUuY29sb3IpIHtcbiAgICAgIHZhciB0dXBsZSA9IGNvbG9yMnR1cGxlKHZhbHVlKTtcblxuICAgICAgaWYgKCF0dXBsZSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgdmFsdWU6IHR1cGxlLFxuICAgICAgICBwZlZhbHVlOiB0dXBsZSxcbiAgICAgICAgc3RyVmFsdWU6ICdyZ2IoJyArIHR1cGxlWzBdICsgJywnICsgdHVwbGVbMV0gKyAnLCcgKyB0dXBsZVsyXSArICcpJyxcbiAgICAgICAgLy8gbi5iLiBubyBzcGFjZXMgYi9jIG9mIG11bHRpcGxlIHN1cHBvcnRcbiAgICAgICAgYnlwYXNzOiBwcm9wSXNCeXBhc3NcbiAgICAgIH07XG4gICAgfSBlbHNlIGlmICh0eXBlLnJlZ2V4IHx8IHR5cGUucmVnZXhlcykge1xuICAgICAgLy8gZmlyc3QgY2hlY2sgZW51bXNcbiAgICAgIGlmICh0eXBlLmVudW1zKSB7XG4gICAgICAgIHZhciBlbnVtUHJvcCA9IGNoZWNrRW51bXMoKTtcblxuICAgICAgICBpZiAoZW51bVByb3ApIHtcbiAgICAgICAgICByZXR1cm4gZW51bVByb3A7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdmFyIHJlZ2V4ZXMgPSB0eXBlLnJlZ2V4ZXMgPyB0eXBlLnJlZ2V4ZXMgOiBbdHlwZS5yZWdleF07XG5cbiAgICAgIGZvciAodmFyIF9pMyA9IDA7IF9pMyA8IHJlZ2V4ZXMubGVuZ3RoOyBfaTMrKykge1xuICAgICAgICB2YXIgcmVnZXggPSBuZXcgUmVnRXhwKHJlZ2V4ZXNbX2kzXSk7IC8vIG1ha2UgYSByZWdleCBmcm9tIHRoZSB0eXBlIHN0cmluZ1xuXG4gICAgICAgIHZhciBtID0gcmVnZXguZXhlYyh2YWx1ZSk7XG5cbiAgICAgICAgaWYgKG0pIHtcbiAgICAgICAgICAvLyByZWdleCBtYXRjaGVzXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgICAgICB2YWx1ZTogdHlwZS5zaW5nbGVSZWdleE1hdGNoVmFsdWUgPyBtWzFdIDogbSxcbiAgICAgICAgICAgIHN0clZhbHVlOiAnJyArIHZhbHVlLFxuICAgICAgICAgICAgYnlwYXNzOiBwcm9wSXNCeXBhc3NcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBudWxsOyAvLyBkaWRuJ3QgbWF0Y2ggYW55XG4gICAgfSBlbHNlIGlmICh0eXBlLnN0cmluZykge1xuICAgICAgLy8ganVzdCByZXR1cm5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgIHZhbHVlOiAnJyArIHZhbHVlLFxuICAgICAgICBzdHJWYWx1ZTogJycgKyB2YWx1ZSxcbiAgICAgICAgYnlwYXNzOiBwcm9wSXNCeXBhc3NcbiAgICAgIH07XG4gICAgfSBlbHNlIGlmICh0eXBlLmVudW1zKSB7XG4gICAgICAvLyBjaGVjayBlbnVtcyBsYXN0IGJlY2F1c2UgaXQncyBhIGNvbWJvIHR5cGUgaW4gb3RoZXJzXG4gICAgICByZXR1cm4gY2hlY2tFbnVtcygpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gbnVsbDsgLy8gbm90IGEgdHlwZSB3ZSBjYW4gaGFuZGxlXG4gICAgfVxuICB9O1xuXG4gIHZhciBTdHlsZSA9IGZ1bmN0aW9uIFN0eWxlKGN5KSB7XG4gICAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFN0eWxlKSkge1xuICAgICAgcmV0dXJuIG5ldyBTdHlsZShjeSk7XG4gICAgfVxuXG4gICAgaWYgKCFjb3JlKGN5KSkge1xuICAgICAgZXJyb3IoJ0Egc3R5bGUgbXVzdCBoYXZlIGEgY29yZSByZWZlcmVuY2UnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl9wcml2YXRlID0ge1xuICAgICAgY3k6IGN5LFxuICAgICAgY29yZVN0eWxlOiB7fVxuICAgIH07XG4gICAgdGhpcy5sZW5ndGggPSAwO1xuICAgIHRoaXMucmVzZXRUb0RlZmF1bHQoKTtcbiAgfTtcblxuICB2YXIgc3R5Zm4gPSBTdHlsZS5wcm90b3R5cGU7XG5cbiAgc3R5Zm4uaW5zdGFuY2VTdHJpbmcgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICdzdHlsZSc7XG4gIH07IC8vIHJlbW92ZSBhbGwgY29udGV4dHNcblxuXG4gIHN0eWZuLmNsZWFyID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG4gICAgdmFyIGN5ID0gX3AuY3k7XG4gICAgdmFyIGVsZXMgPSBjeS5lbGVtZW50cygpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB0aGlzW2ldID0gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHRoaXMubGVuZ3RoID0gMDtcbiAgICBfcC5jb250ZXh0U3R5bGVzID0ge307XG4gICAgX3AucHJvcERpZmZzID0ge307XG4gICAgdGhpcy5jbGVhbkVsZW1lbnRzKGVsZXMsIHRydWUpO1xuICAgIGVsZXMuZm9yRWFjaChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICB2YXIgZWxlX3AgPSBlbGVbMF0uX3ByaXZhdGU7XG4gICAgICBlbGVfcC5zdHlsZURpcnR5ID0gdHJ1ZTtcbiAgICAgIGVsZV9wLmFwcGxpZWRJbml0U3R5bGUgPSBmYWxzZTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgfTtcblxuICBzdHlmbi5yZXNldFRvRGVmYXVsdCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmNsZWFyKCk7XG4gICAgdGhpcy5hZGREZWZhdWx0U3R5bGVzaGVldCgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9OyAvLyBidWlsZHMgYSBzdHlsZSBvYmplY3QgZm9yIHRoZSAnY29yZScgc2VsZWN0b3JcblxuXG4gIHN0eWZuLmNvcmUgPSBmdW5jdGlvbiAocHJvcE5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5jb3JlU3R5bGVbcHJvcE5hbWVdIHx8IHRoaXMuZ2V0RGVmYXVsdFByb3BlcnR5KHByb3BOYW1lKTtcbiAgfTsgLy8gY3JlYXRlIGEgbmV3IGNvbnRleHQgZnJvbSB0aGUgc3BlY2lmaWVkIHNlbGVjdG9yIHN0cmluZyBhbmQgc3dpdGNoIHRvIHRoYXQgY29udGV4dFxuXG5cbiAgc3R5Zm4uc2VsZWN0b3IgPSBmdW5jdGlvbiAoc2VsZWN0b3JTdHIpIHtcbiAgICAvLyAnY29yZScgaXMgYSBzcGVjaWFsIGNhc2UgYW5kIGRvZXMgbm90IG5lZWQgYSBzZWxlY3RvclxuICAgIHZhciBzZWxlY3RvciA9IHNlbGVjdG9yU3RyID09PSAnY29yZScgPyBudWxsIDogbmV3IFNlbGVjdG9yKHNlbGVjdG9yU3RyKTtcbiAgICB2YXIgaSA9IHRoaXMubGVuZ3RoKys7IC8vIG5ldyBjb250ZXh0IG1lYW5zIG5ldyBpbmRleFxuXG4gICAgdGhpc1tpXSA9IHtcbiAgICAgIHNlbGVjdG9yOiBzZWxlY3RvcixcbiAgICAgIHByb3BlcnRpZXM6IFtdLFxuICAgICAgbWFwcGVkUHJvcGVydGllczogW10sXG4gICAgICBpbmRleDogaVxuICAgIH07XG4gICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gIH07IC8vIGFkZCBvbmUgb3IgbWFueSBjc3MgcnVsZXMgdG8gdGhlIGN1cnJlbnQgY29udGV4dFxuXG5cbiAgc3R5Zm4uY3NzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgYXJncyA9IGFyZ3VtZW50cztcblxuICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgdmFyIG1hcCA9IGFyZ3NbMF07XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2VsZi5wcm9wZXJ0aWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBwcm9wID0gc2VsZi5wcm9wZXJ0aWVzW2ldO1xuICAgICAgICB2YXIgbWFwVmFsID0gbWFwW3Byb3AubmFtZV07XG5cbiAgICAgICAgaWYgKG1hcFZhbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgbWFwVmFsID0gbWFwW2Rhc2gyY2FtZWwocHJvcC5uYW1lKV07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWFwVmFsICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICB0aGlzLmNzc1J1bGUocHJvcC5uYW1lLCBtYXBWYWwpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChhcmdzLmxlbmd0aCA9PT0gMikge1xuICAgICAgdGhpcy5jc3NSdWxlKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIH0gLy8gZG8gbm90aGluZyBpZiBhcmdzIGFyZSBpbnZhbGlkXG5cblxuICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICB9O1xuXG4gIHN0eWZuLnN0eWxlID0gc3R5Zm4uY3NzOyAvLyBhZGQgYSBzaW5nbGUgY3NzIHJ1bGUgdG8gdGhlIGN1cnJlbnQgY29udGV4dFxuXG4gIHN0eWZuLmNzc1J1bGUgPSBmdW5jdGlvbiAobmFtZSwgdmFsdWUpIHtcbiAgICAvLyBuYW1lLXZhbHVlIHBhaXJcbiAgICB2YXIgcHJvcGVydHkgPSB0aGlzLnBhcnNlKG5hbWUsIHZhbHVlKTsgLy8gYWRkIHByb3BlcnR5IHRvIGN1cnJlbnQgY29udGV4dCBpZiB2YWxpZFxuXG4gICAgaWYgKHByb3BlcnR5KSB7XG4gICAgICB2YXIgaSA9IHRoaXMubGVuZ3RoIC0gMTtcbiAgICAgIHRoaXNbaV0ucHJvcGVydGllcy5wdXNoKHByb3BlcnR5KTtcbiAgICAgIHRoaXNbaV0ucHJvcGVydGllc1twcm9wZXJ0eS5uYW1lXSA9IHByb3BlcnR5OyAvLyBhbGxvdyBhY2Nlc3MgYnkgbmFtZSBhcyB3ZWxsXG5cbiAgICAgIGlmIChwcm9wZXJ0eS5uYW1lLm1hdGNoKC9waWUtKFxcZCspLWJhY2tncm91bmQtc2l6ZS8pICYmIHByb3BlcnR5LnZhbHVlKSB7XG4gICAgICAgIHRoaXMuX3ByaXZhdGUuaGFzUGllID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKHByb3BlcnR5Lm1hcHBlZCkge1xuICAgICAgICB0aGlzW2ldLm1hcHBlZFByb3BlcnRpZXMucHVzaChwcm9wZXJ0eSk7XG4gICAgICB9IC8vIGFkZCB0byBjb3JlIHN0eWxlIGlmIG5lY2Vzc2FyeVxuXG5cbiAgICAgIHZhciBjdXJyZW50U2VsZWN0b3JJc0NvcmUgPSAhdGhpc1tpXS5zZWxlY3RvcjtcblxuICAgICAgaWYgKGN1cnJlbnRTZWxlY3RvcklzQ29yZSkge1xuICAgICAgICB0aGlzLl9wcml2YXRlLmNvcmVTdHlsZVtwcm9wZXJ0eS5uYW1lXSA9IHByb3BlcnR5O1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICB9O1xuXG4gIHN0eWZuLmFwcGVuZCA9IGZ1bmN0aW9uIChzdHlsZSkge1xuICAgIGlmIChzdHlsZXNoZWV0KHN0eWxlKSkge1xuICAgICAgc3R5bGUuYXBwZW5kVG9TdHlsZSh0aGlzKTtcbiAgICB9IGVsc2UgaWYgKGFycmF5KHN0eWxlKSkge1xuICAgICAgdGhpcy5hcHBlbmRGcm9tSnNvbihzdHlsZSk7XG4gICAgfSBlbHNlIGlmIChzdHJpbmcoc3R5bGUpKSB7XG4gICAgICB0aGlzLmFwcGVuZEZyb21TdHJpbmcoc3R5bGUpO1xuICAgIH0gLy8geW91IHByb2JhYmx5IHdvdWxkbid0IHdhbnQgdG8gYXBwZW5kIGEgU3R5bGUsIHNpbmNlIHlvdSdkIGR1cGxpY2F0ZSB0aGUgZGVmYXVsdCBwYXJ0c1xuXG5cbiAgICByZXR1cm4gdGhpcztcbiAgfTsgLy8gc3RhdGljIGZ1bmN0aW9uXG5cblxuICBTdHlsZS5mcm9tSnNvbiA9IGZ1bmN0aW9uIChjeSwganNvbikge1xuICAgIHZhciBzdHlsZSA9IG5ldyBTdHlsZShjeSk7XG4gICAgc3R5bGUuZnJvbUpzb24oanNvbik7XG4gICAgcmV0dXJuIHN0eWxlO1xuICB9O1xuXG4gIFN0eWxlLmZyb21TdHJpbmcgPSBmdW5jdGlvbiAoY3ksIHN0cmluZykge1xuICAgIHJldHVybiBuZXcgU3R5bGUoY3kpLmZyb21TdHJpbmcoc3RyaW5nKTtcbiAgfTtcblxuICBbc3R5Zm4kOCwgc3R5Zm4kNywgc3R5Zm4kNiwgc3R5Zm4kNSwgc3R5Zm4kNCwgc3R5Zm4kMywgc3R5Zm4kMiwgc3R5Zm4kMV0uZm9yRWFjaChmdW5jdGlvbiAocHJvcHMpIHtcbiAgICBleHRlbmQoc3R5Zm4sIHByb3BzKTtcbiAgfSk7XG4gIFN0eWxlLnR5cGVzID0gc3R5Zm4udHlwZXM7XG4gIFN0eWxlLnByb3BlcnRpZXMgPSBzdHlmbi5wcm9wZXJ0aWVzO1xuICBTdHlsZS5wcm9wZXJ0eUdyb3VwcyA9IHN0eWZuLnByb3BlcnR5R3JvdXBzO1xuICBTdHlsZS5wcm9wZXJ0eUdyb3VwTmFtZXMgPSBzdHlmbi5wcm9wZXJ0eUdyb3VwTmFtZXM7XG4gIFN0eWxlLnByb3BlcnR5R3JvdXBLZXlzID0gc3R5Zm4ucHJvcGVydHlHcm91cEtleXM7XG5cbiAgdmFyIGNvcmVmbiQyID0ge1xuICAgIHN0eWxlOiBmdW5jdGlvbiBzdHlsZShuZXdTdHlsZSkge1xuICAgICAgaWYgKG5ld1N0eWxlKSB7XG4gICAgICAgIHZhciBzID0gdGhpcy5zZXRTdHlsZShuZXdTdHlsZSk7XG4gICAgICAgIHMudXBkYXRlKCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLnN0eWxlO1xuICAgIH0sXG4gICAgc2V0U3R5bGU6IGZ1bmN0aW9uIHNldFN0eWxlKHN0eWxlKSB7XG4gICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuXG4gICAgICBpZiAoc3R5bGVzaGVldChzdHlsZSkpIHtcbiAgICAgICAgX3Auc3R5bGUgPSBzdHlsZS5nZW5lcmF0ZVN0eWxlKHRoaXMpO1xuICAgICAgfSBlbHNlIGlmIChhcnJheShzdHlsZSkpIHtcbiAgICAgICAgX3Auc3R5bGUgPSBTdHlsZS5mcm9tSnNvbih0aGlzLCBzdHlsZSk7XG4gICAgICB9IGVsc2UgaWYgKHN0cmluZyhzdHlsZSkpIHtcbiAgICAgICAgX3Auc3R5bGUgPSBTdHlsZS5mcm9tU3RyaW5nKHRoaXMsIHN0eWxlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIF9wLnN0eWxlID0gU3R5bGUodGhpcyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBfcC5zdHlsZTtcbiAgICB9LFxuICAgIC8vIGUuZy4gY3kuZGF0YSgpIGNoYW5nZWQgPT4gcmVjYWxjIGVsZSBtYXBwZXJzXG4gICAgdXBkYXRlU3R5bGU6IGZ1bmN0aW9uIHVwZGF0ZVN0eWxlKCkge1xuICAgICAgdGhpcy5tdXRhYmxlRWxlbWVudHMoKS51cGRhdGVTdHlsZSgpOyAvLyBqdXN0IHNlbmQgdG8gYWxsIGVsZXNcbiAgICB9XG4gIH07XG5cbiAgdmFyIGRlZmF1bHRTZWxlY3Rpb25UeXBlID0gJ3NpbmdsZSc7XG4gIHZhciBjb3JlZm4kMSA9IHtcbiAgICBhdXRvbG9jazogZnVuY3Rpb24gYXV0b2xvY2soYm9vbCkge1xuICAgICAgaWYgKGJvb2wgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLl9wcml2YXRlLmF1dG9sb2NrID0gYm9vbCA/IHRydWUgOiBmYWxzZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLmF1dG9sb2NrO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgICB9LFxuICAgIGF1dG91bmdyYWJpZnk6IGZ1bmN0aW9uIGF1dG91bmdyYWJpZnkoYm9vbCkge1xuICAgICAgaWYgKGJvb2wgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLl9wcml2YXRlLmF1dG91bmdyYWJpZnkgPSBib29sID8gdHJ1ZSA6IGZhbHNlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3ByaXZhdGUuYXV0b3VuZ3JhYmlmeTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICBhdXRvdW5zZWxlY3RpZnk6IGZ1bmN0aW9uIGF1dG91bnNlbGVjdGlmeShib29sKSB7XG4gICAgICBpZiAoYm9vbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMuX3ByaXZhdGUuYXV0b3Vuc2VsZWN0aWZ5ID0gYm9vbCA/IHRydWUgOiBmYWxzZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLmF1dG91bnNlbGVjdGlmeTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICBzZWxlY3Rpb25UeXBlOiBmdW5jdGlvbiBzZWxlY3Rpb25UeXBlKHNlbFR5cGUpIHtcbiAgICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG5cbiAgICAgIGlmIChfcC5zZWxlY3Rpb25UeXBlID09IG51bGwpIHtcbiAgICAgICAgX3Auc2VsZWN0aW9uVHlwZSA9IGRlZmF1bHRTZWxlY3Rpb25UeXBlO1xuICAgICAgfVxuXG4gICAgICBpZiAoc2VsVHlwZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGlmIChzZWxUeXBlID09PSAnYWRkaXRpdmUnIHx8IHNlbFR5cGUgPT09ICdzaW5nbGUnKSB7XG4gICAgICAgICAgX3Auc2VsZWN0aW9uVHlwZSA9IHNlbFR5cGU7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBfcC5zZWxlY3Rpb25UeXBlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIHBhbm5pbmdFbmFibGVkOiBmdW5jdGlvbiBwYW5uaW5nRW5hYmxlZChib29sKSB7XG4gICAgICBpZiAoYm9vbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMuX3ByaXZhdGUucGFubmluZ0VuYWJsZWQgPSBib29sID8gdHJ1ZSA6IGZhbHNlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3ByaXZhdGUucGFubmluZ0VuYWJsZWQ7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICAgIH0sXG4gICAgdXNlclBhbm5pbmdFbmFibGVkOiBmdW5jdGlvbiB1c2VyUGFubmluZ0VuYWJsZWQoYm9vbCkge1xuICAgICAgaWYgKGJvb2wgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLl9wcml2YXRlLnVzZXJQYW5uaW5nRW5hYmxlZCA9IGJvb2wgPyB0cnVlIDogZmFsc2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS51c2VyUGFubmluZ0VuYWJsZWQ7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICAgIH0sXG4gICAgem9vbWluZ0VuYWJsZWQ6IGZ1bmN0aW9uIHpvb21pbmdFbmFibGVkKGJvb2wpIHtcbiAgICAgIGlmIChib29sICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5fcHJpdmF0ZS56b29taW5nRW5hYmxlZCA9IGJvb2wgPyB0cnVlIDogZmFsc2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS56b29taW5nRW5hYmxlZDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICB1c2VyWm9vbWluZ0VuYWJsZWQ6IGZ1bmN0aW9uIHVzZXJab29taW5nRW5hYmxlZChib29sKSB7XG4gICAgICBpZiAoYm9vbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMuX3ByaXZhdGUudXNlclpvb21pbmdFbmFibGVkID0gYm9vbCA/IHRydWUgOiBmYWxzZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLnVzZXJab29taW5nRW5hYmxlZDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICBib3hTZWxlY3Rpb25FbmFibGVkOiBmdW5jdGlvbiBib3hTZWxlY3Rpb25FbmFibGVkKGJvb2wpIHtcbiAgICAgIGlmIChib29sICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5fcHJpdmF0ZS5ib3hTZWxlY3Rpb25FbmFibGVkID0gYm9vbCA/IHRydWUgOiBmYWxzZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLmJveFNlbGVjdGlvbkVuYWJsZWQ7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICAgIH0sXG4gICAgcGFuOiBmdW5jdGlvbiBwYW4oKSB7XG4gICAgICB2YXIgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgIHZhciBwYW4gPSB0aGlzLl9wcml2YXRlLnBhbjtcbiAgICAgIHZhciBkaW0sIHZhbCwgZGltcywgeCwgeTtcblxuICAgICAgc3dpdGNoIChhcmdzLmxlbmd0aCkge1xuICAgICAgICBjYXNlIDA6XG4gICAgICAgICAgLy8gLnBhbigpXG4gICAgICAgICAgcmV0dXJuIHBhbjtcblxuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgaWYgKHN0cmluZyhhcmdzWzBdKSkge1xuICAgICAgICAgICAgLy8gLnBhbigneCcpXG4gICAgICAgICAgICBkaW0gPSBhcmdzWzBdO1xuICAgICAgICAgICAgcmV0dXJuIHBhbltkaW1dO1xuICAgICAgICAgIH0gZWxzZSBpZiAocGxhaW5PYmplY3QoYXJnc1swXSkpIHtcbiAgICAgICAgICAgIC8vIC5wYW4oeyB4OiAwLCB5OiAxMDAgfSlcbiAgICAgICAgICAgIGlmICghdGhpcy5fcHJpdmF0ZS5wYW5uaW5nRW5hYmxlZCkge1xuICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZGltcyA9IGFyZ3NbMF07XG4gICAgICAgICAgICB4ID0gZGltcy54O1xuICAgICAgICAgICAgeSA9IGRpbXMueTtcblxuICAgICAgICAgICAgaWYgKG51bWJlciQxKHgpKSB7XG4gICAgICAgICAgICAgIHBhbi54ID0geDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKG51bWJlciQxKHkpKSB7XG4gICAgICAgICAgICAgIHBhbi55ID0geTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5lbWl0KCdwYW4gdmlld3BvcnQnKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgLy8gLnBhbigneCcsIDEwMClcbiAgICAgICAgICBpZiAoIXRoaXMuX3ByaXZhdGUucGFubmluZ0VuYWJsZWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGRpbSA9IGFyZ3NbMF07XG4gICAgICAgICAgdmFsID0gYXJnc1sxXTtcblxuICAgICAgICAgIGlmICgoZGltID09PSAneCcgfHwgZGltID09PSAneScpICYmIG51bWJlciQxKHZhbCkpIHtcbiAgICAgICAgICAgIHBhbltkaW1dID0gdmFsO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuZW1pdCgncGFuIHZpZXdwb3J0Jyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIC8vIGludmFsaWRcbiAgICAgIH1cblxuICAgICAgdGhpcy5ub3RpZnkoJ3ZpZXdwb3J0Jyk7XG4gICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgICB9LFxuICAgIHBhbkJ5OiBmdW5jdGlvbiBwYW5CeShhcmcwLCBhcmcxKSB7XG4gICAgICB2YXIgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgIHZhciBwYW4gPSB0aGlzLl9wcml2YXRlLnBhbjtcbiAgICAgIHZhciBkaW0sIHZhbCwgZGltcywgeCwgeTtcblxuICAgICAgaWYgKCF0aGlzLl9wcml2YXRlLnBhbm5pbmdFbmFibGVkKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuXG4gICAgICBzd2l0Y2ggKGFyZ3MubGVuZ3RoKSB7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgICBpZiAocGxhaW5PYmplY3QoYXJnMCkpIHtcbiAgICAgICAgICAgIC8vIC5wYW5CeSh7IHg6IDAsIHk6IDEwMCB9KVxuICAgICAgICAgICAgZGltcyA9IGFyZ3NbMF07XG4gICAgICAgICAgICB4ID0gZGltcy54O1xuICAgICAgICAgICAgeSA9IGRpbXMueTtcblxuICAgICAgICAgICAgaWYgKG51bWJlciQxKHgpKSB7XG4gICAgICAgICAgICAgIHBhbi54ICs9IHg7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChudW1iZXIkMSh5KSkge1xuICAgICAgICAgICAgICBwYW4ueSArPSB5O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLmVtaXQoJ3BhbiB2aWV3cG9ydCcpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAvLyAucGFuQnkoJ3gnLCAxMDApXG4gICAgICAgICAgZGltID0gYXJnMDtcbiAgICAgICAgICB2YWwgPSBhcmcxO1xuXG4gICAgICAgICAgaWYgKChkaW0gPT09ICd4JyB8fCBkaW0gPT09ICd5JykgJiYgbnVtYmVyJDEodmFsKSkge1xuICAgICAgICAgICAgcGFuW2RpbV0gKz0gdmFsO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuZW1pdCgncGFuIHZpZXdwb3J0Jyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIC8vIGludmFsaWRcbiAgICAgIH1cblxuICAgICAgdGhpcy5ub3RpZnkoJ3ZpZXdwb3J0Jyk7XG4gICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgICB9LFxuICAgIGZpdDogZnVuY3Rpb24gZml0KGVsZW1lbnRzLCBwYWRkaW5nKSB7XG4gICAgICB2YXIgdmlld3BvcnRTdGF0ZSA9IHRoaXMuZ2V0Rml0Vmlld3BvcnQoZWxlbWVudHMsIHBhZGRpbmcpO1xuXG4gICAgICBpZiAodmlld3BvcnRTdGF0ZSkge1xuICAgICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuICAgICAgICBfcC56b29tID0gdmlld3BvcnRTdGF0ZS56b29tO1xuICAgICAgICBfcC5wYW4gPSB2aWV3cG9ydFN0YXRlLnBhbjtcbiAgICAgICAgdGhpcy5lbWl0KCdwYW4gem9vbSB2aWV3cG9ydCcpO1xuICAgICAgICB0aGlzLm5vdGlmeSgndmlld3BvcnQnKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICBnZXRGaXRWaWV3cG9ydDogZnVuY3Rpb24gZ2V0Rml0Vmlld3BvcnQoZWxlbWVudHMsIHBhZGRpbmcpIHtcbiAgICAgIGlmIChudW1iZXIkMShlbGVtZW50cykgJiYgcGFkZGluZyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIC8vIGVsZW1lbnRzIGlzIG9wdGlvbmFsXG4gICAgICAgIHBhZGRpbmcgPSBlbGVtZW50cztcbiAgICAgICAgZWxlbWVudHMgPSB1bmRlZmluZWQ7XG4gICAgICB9XG5cbiAgICAgIGlmICghdGhpcy5fcHJpdmF0ZS5wYW5uaW5nRW5hYmxlZCB8fCAhdGhpcy5fcHJpdmF0ZS56b29taW5nRW5hYmxlZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciBiYjtcblxuICAgICAgaWYgKHN0cmluZyhlbGVtZW50cykpIHtcbiAgICAgICAgdmFyIHNlbCA9IGVsZW1lbnRzO1xuICAgICAgICBlbGVtZW50cyA9IHRoaXMuJChzZWwpO1xuICAgICAgfSBlbHNlIGlmIChib3VuZGluZ0JveChlbGVtZW50cykpIHtcbiAgICAgICAgLy8gYXNzdW1lIGJiXG4gICAgICAgIHZhciBiYmUgPSBlbGVtZW50cztcbiAgICAgICAgYmIgPSB7XG4gICAgICAgICAgeDE6IGJiZS54MSxcbiAgICAgICAgICB5MTogYmJlLnkxLFxuICAgICAgICAgIHgyOiBiYmUueDIsXG4gICAgICAgICAgeTI6IGJiZS55MlxuICAgICAgICB9O1xuICAgICAgICBiYi53ID0gYmIueDIgLSBiYi54MTtcbiAgICAgICAgYmIuaCA9IGJiLnkyIC0gYmIueTE7XG4gICAgICB9IGVsc2UgaWYgKCFlbGVtZW50T3JDb2xsZWN0aW9uKGVsZW1lbnRzKSkge1xuICAgICAgICBlbGVtZW50cyA9IHRoaXMubXV0YWJsZUVsZW1lbnRzKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbGVtZW50T3JDb2xsZWN0aW9uKGVsZW1lbnRzKSAmJiBlbGVtZW50cy5lbXB0eSgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gY2FuJ3QgZml0IHRvIG5vdGhpbmdcblxuXG4gICAgICBiYiA9IGJiIHx8IGVsZW1lbnRzLmJvdW5kaW5nQm94KCk7XG4gICAgICB2YXIgdyA9IHRoaXMud2lkdGgoKTtcbiAgICAgIHZhciBoID0gdGhpcy5oZWlnaHQoKTtcbiAgICAgIHZhciB6b29tO1xuICAgICAgcGFkZGluZyA9IG51bWJlciQxKHBhZGRpbmcpID8gcGFkZGluZyA6IDA7XG5cbiAgICAgIGlmICghaXNOYU4odykgJiYgIWlzTmFOKGgpICYmIHcgPiAwICYmIGggPiAwICYmICFpc05hTihiYi53KSAmJiAhaXNOYU4oYmIuaCkgJiYgYmIudyA+IDAgJiYgYmIuaCA+IDApIHtcbiAgICAgICAgem9vbSA9IE1hdGgubWluKCh3IC0gMiAqIHBhZGRpbmcpIC8gYmIudywgKGggLSAyICogcGFkZGluZykgLyBiYi5oKTsgLy8gY3JvcCB6b29tXG5cbiAgICAgICAgem9vbSA9IHpvb20gPiB0aGlzLl9wcml2YXRlLm1heFpvb20gPyB0aGlzLl9wcml2YXRlLm1heFpvb20gOiB6b29tO1xuICAgICAgICB6b29tID0gem9vbSA8IHRoaXMuX3ByaXZhdGUubWluWm9vbSA/IHRoaXMuX3ByaXZhdGUubWluWm9vbSA6IHpvb207XG4gICAgICAgIHZhciBwYW4gPSB7XG4gICAgICAgICAgLy8gbm93IHBhbiB0byBtaWRkbGVcbiAgICAgICAgICB4OiAodyAtIHpvb20gKiAoYmIueDEgKyBiYi54MikpIC8gMixcbiAgICAgICAgICB5OiAoaCAtIHpvb20gKiAoYmIueTEgKyBiYi55MikpIC8gMlxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHpvb206IHpvb20sXG4gICAgICAgICAgcGFuOiBwYW5cbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuO1xuICAgIH0sXG4gICAgem9vbVJhbmdlOiBmdW5jdGlvbiB6b29tUmFuZ2UobWluLCBtYXgpIHtcbiAgICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG5cbiAgICAgIGlmIChtYXggPT0gbnVsbCkge1xuICAgICAgICB2YXIgb3B0cyA9IG1pbjtcbiAgICAgICAgbWluID0gb3B0cy5taW47XG4gICAgICAgIG1heCA9IG9wdHMubWF4O1xuICAgICAgfVxuXG4gICAgICBpZiAobnVtYmVyJDEobWluKSAmJiBudW1iZXIkMShtYXgpICYmIG1pbiA8PSBtYXgpIHtcbiAgICAgICAgX3AubWluWm9vbSA9IG1pbjtcbiAgICAgICAgX3AubWF4Wm9vbSA9IG1heDtcbiAgICAgIH0gZWxzZSBpZiAobnVtYmVyJDEobWluKSAmJiBtYXggPT09IHVuZGVmaW5lZCAmJiBtaW4gPD0gX3AubWF4Wm9vbSkge1xuICAgICAgICBfcC5taW5ab29tID0gbWluO1xuICAgICAgfSBlbHNlIGlmIChudW1iZXIkMShtYXgpICYmIG1pbiA9PT0gdW5kZWZpbmVkICYmIG1heCA+PSBfcC5taW5ab29tKSB7XG4gICAgICAgIF9wLm1heFpvb20gPSBtYXg7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgbWluWm9vbTogZnVuY3Rpb24gbWluWm9vbSh6b29tKSB7XG4gICAgICBpZiAoem9vbSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLm1pblpvb207XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdGhpcy56b29tUmFuZ2Uoe1xuICAgICAgICAgIG1pbjogem9vbVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9LFxuICAgIG1heFpvb206IGZ1bmN0aW9uIG1heFpvb20oem9vbSkge1xuICAgICAgaWYgKHpvb20gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5tYXhab29tO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuem9vbVJhbmdlKHtcbiAgICAgICAgICBtYXg6IHpvb21cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSxcbiAgICBnZXRab29tZWRWaWV3cG9ydDogZnVuY3Rpb24gZ2V0Wm9vbWVkVmlld3BvcnQocGFyYW1zKSB7XG4gICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuICAgICAgdmFyIGN1cnJlbnRQYW4gPSBfcC5wYW47XG4gICAgICB2YXIgY3VycmVudFpvb20gPSBfcC56b29tO1xuICAgICAgdmFyIHBvczsgLy8gaW4gcmVuZGVyZWQgcHhcblxuICAgICAgdmFyIHpvb207XG4gICAgICB2YXIgYmFpbCA9IGZhbHNlO1xuXG4gICAgICBpZiAoIV9wLnpvb21pbmdFbmFibGVkKSB7XG4gICAgICAgIC8vIHpvb21pbmcgZGlzYWJsZWRcbiAgICAgICAgYmFpbCA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIGlmIChudW1iZXIkMShwYXJhbXMpKSB7XG4gICAgICAgIC8vIHRoZW4gc2V0IHRoZSB6b29tXG4gICAgICAgIHpvb20gPSBwYXJhbXM7XG4gICAgICB9IGVsc2UgaWYgKHBsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgLy8gdGhlbiB6b29tIGFib3V0IGEgcG9pbnRcbiAgICAgICAgem9vbSA9IHBhcmFtcy5sZXZlbDtcblxuICAgICAgICBpZiAocGFyYW1zLnBvc2l0aW9uICE9IG51bGwpIHtcbiAgICAgICAgICBwb3MgPSBtb2RlbFRvUmVuZGVyZWRQb3NpdGlvbihwYXJhbXMucG9zaXRpb24sIGN1cnJlbnRab29tLCBjdXJyZW50UGFuKTtcbiAgICAgICAgfSBlbHNlIGlmIChwYXJhbXMucmVuZGVyZWRQb3NpdGlvbiAhPSBudWxsKSB7XG4gICAgICAgICAgcG9zID0gcGFyYW1zLnJlbmRlcmVkUG9zaXRpb247XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocG9zICE9IG51bGwgJiYgIV9wLnBhbm5pbmdFbmFibGVkKSB7XG4gICAgICAgICAgLy8gcGFubmluZyBkaXNhYmxlZFxuICAgICAgICAgIGJhaWwgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICB9IC8vIGNyb3Agem9vbVxuXG5cbiAgICAgIHpvb20gPSB6b29tID4gX3AubWF4Wm9vbSA/IF9wLm1heFpvb20gOiB6b29tO1xuICAgICAgem9vbSA9IHpvb20gPCBfcC5taW5ab29tID8gX3AubWluWm9vbSA6IHpvb207IC8vIGNhbid0IHpvb20gd2l0aCBpbnZhbGlkIHBhcmFtc1xuXG4gICAgICBpZiAoYmFpbCB8fCAhbnVtYmVyJDEoem9vbSkgfHwgem9vbSA9PT0gY3VycmVudFpvb20gfHwgcG9zICE9IG51bGwgJiYgKCFudW1iZXIkMShwb3MueCkgfHwgIW51bWJlciQxKHBvcy55KSkpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIGlmIChwb3MgIT0gbnVsbCkge1xuICAgICAgICAvLyBzZXQgem9vbSBhYm91dCBwb3NpdGlvblxuICAgICAgICB2YXIgcGFuMSA9IGN1cnJlbnRQYW47XG4gICAgICAgIHZhciB6b29tMSA9IGN1cnJlbnRab29tO1xuICAgICAgICB2YXIgem9vbTIgPSB6b29tO1xuICAgICAgICB2YXIgcGFuMiA9IHtcbiAgICAgICAgICB4OiAtem9vbTIgLyB6b29tMSAqIChwb3MueCAtIHBhbjEueCkgKyBwb3MueCxcbiAgICAgICAgICB5OiAtem9vbTIgLyB6b29tMSAqIChwb3MueSAtIHBhbjEueSkgKyBwb3MueVxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHpvb21lZDogdHJ1ZSxcbiAgICAgICAgICBwYW5uZWQ6IHRydWUsXG4gICAgICAgICAgem9vbTogem9vbTIsXG4gICAgICAgICAgcGFuOiBwYW4yXG4gICAgICAgIH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBqdXN0IHNldCB0aGUgem9vbVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHpvb21lZDogdHJ1ZSxcbiAgICAgICAgICBwYW5uZWQ6IGZhbHNlLFxuICAgICAgICAgIHpvb206IHpvb20sXG4gICAgICAgICAgcGFuOiBjdXJyZW50UGFuXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfSxcbiAgICB6b29tOiBmdW5jdGlvbiB6b29tKHBhcmFtcykge1xuICAgICAgaWYgKHBhcmFtcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIC8vIGdldFxuICAgICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS56b29tO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gc2V0XG4gICAgICAgIHZhciB2cCA9IHRoaXMuZ2V0Wm9vbWVkVmlld3BvcnQocGFyYW1zKTtcbiAgICAgICAgdmFyIF9wID0gdGhpcy5fcHJpdmF0ZTtcblxuICAgICAgICBpZiAodnAgPT0gbnVsbCB8fCAhdnAuem9vbWVkKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICBfcC56b29tID0gdnAuem9vbTtcblxuICAgICAgICBpZiAodnAucGFubmVkKSB7XG4gICAgICAgICAgX3AucGFuLnggPSB2cC5wYW4ueDtcbiAgICAgICAgICBfcC5wYW4ueSA9IHZwLnBhbi55O1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lbWl0KCd6b29tJyArICh2cC5wYW5uZWQgPyAnIHBhbicgOiAnJykgKyAnIHZpZXdwb3J0Jyk7XG4gICAgICAgIHRoaXMubm90aWZ5KCd2aWV3cG9ydCcpO1xuICAgICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgICAgIH1cbiAgICB9LFxuICAgIHZpZXdwb3J0OiBmdW5jdGlvbiB2aWV3cG9ydChvcHRzKSB7XG4gICAgICB2YXIgX3AgPSB0aGlzLl9wcml2YXRlO1xuICAgICAgdmFyIHpvb21EZWZkID0gdHJ1ZTtcbiAgICAgIHZhciBwYW5EZWZkID0gdHJ1ZTtcbiAgICAgIHZhciBldmVudHMgPSBbXTsgLy8gdG8gdHJpZ2dlclxuXG4gICAgICB2YXIgem9vbUZhaWxlZCA9IGZhbHNlO1xuICAgICAgdmFyIHBhbkZhaWxlZCA9IGZhbHNlO1xuXG4gICAgICBpZiAoIW9wdHMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9XG5cbiAgICAgIGlmICghbnVtYmVyJDEob3B0cy56b29tKSkge1xuICAgICAgICB6b29tRGVmZCA9IGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXBsYWluT2JqZWN0KG9wdHMucGFuKSkge1xuICAgICAgICBwYW5EZWZkID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlmICghem9vbURlZmQgJiYgIXBhbkRlZmQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9XG5cbiAgICAgIGlmICh6b29tRGVmZCkge1xuICAgICAgICB2YXIgeiA9IG9wdHMuem9vbTtcblxuICAgICAgICBpZiAoeiA8IF9wLm1pblpvb20gfHwgeiA+IF9wLm1heFpvb20gfHwgIV9wLnpvb21pbmdFbmFibGVkKSB7XG4gICAgICAgICAgem9vbUZhaWxlZCA9IHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgX3Auem9vbSA9IHo7XG4gICAgICAgICAgZXZlbnRzLnB1c2goJ3pvb20nKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAocGFuRGVmZCAmJiAoIXpvb21GYWlsZWQgfHwgIW9wdHMuY2FuY2VsT25GYWlsZWRab29tKSAmJiBfcC5wYW5uaW5nRW5hYmxlZCkge1xuICAgICAgICB2YXIgcCA9IG9wdHMucGFuO1xuXG4gICAgICAgIGlmIChudW1iZXIkMShwLngpKSB7XG4gICAgICAgICAgX3AucGFuLnggPSBwLng7XG4gICAgICAgICAgcGFuRmFpbGVkID0gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobnVtYmVyJDEocC55KSkge1xuICAgICAgICAgIF9wLnBhbi55ID0gcC55O1xuICAgICAgICAgIHBhbkZhaWxlZCA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFwYW5GYWlsZWQpIHtcbiAgICAgICAgICBldmVudHMucHVzaCgncGFuJyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGV2ZW50cy5wdXNoKCd2aWV3cG9ydCcpO1xuICAgICAgICB0aGlzLmVtaXQoZXZlbnRzLmpvaW4oJyAnKSk7XG4gICAgICAgIHRoaXMubm90aWZ5KCd2aWV3cG9ydCcpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgICB9LFxuICAgIGNlbnRlcjogZnVuY3Rpb24gY2VudGVyKGVsZW1lbnRzKSB7XG4gICAgICB2YXIgcGFuID0gdGhpcy5nZXRDZW50ZXJQYW4oZWxlbWVudHMpO1xuXG4gICAgICBpZiAocGFuKSB7XG4gICAgICAgIHRoaXMuX3ByaXZhdGUucGFuID0gcGFuO1xuICAgICAgICB0aGlzLmVtaXQoJ3BhbiB2aWV3cG9ydCcpO1xuICAgICAgICB0aGlzLm5vdGlmeSgndmlld3BvcnQnKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfSxcbiAgICBnZXRDZW50ZXJQYW46IGZ1bmN0aW9uIGdldENlbnRlclBhbihlbGVtZW50cywgem9vbSkge1xuICAgICAgaWYgKCF0aGlzLl9wcml2YXRlLnBhbm5pbmdFbmFibGVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHN0cmluZyhlbGVtZW50cykpIHtcbiAgICAgICAgdmFyIHNlbGVjdG9yID0gZWxlbWVudHM7XG4gICAgICAgIGVsZW1lbnRzID0gdGhpcy5tdXRhYmxlRWxlbWVudHMoKS5maWx0ZXIoc2VsZWN0b3IpO1xuICAgICAgfSBlbHNlIGlmICghZWxlbWVudE9yQ29sbGVjdGlvbihlbGVtZW50cykpIHtcbiAgICAgICAgZWxlbWVudHMgPSB0aGlzLm11dGFibGVFbGVtZW50cygpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZWxlbWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gY2FuJ3QgY2VudHJlIHBhbiB0byBub3RoaW5nXG5cblxuICAgICAgdmFyIGJiID0gZWxlbWVudHMuYm91bmRpbmdCb3goKTtcbiAgICAgIHZhciB3ID0gdGhpcy53aWR0aCgpO1xuICAgICAgdmFyIGggPSB0aGlzLmhlaWdodCgpO1xuICAgICAgem9vbSA9IHpvb20gPT09IHVuZGVmaW5lZCA/IHRoaXMuX3ByaXZhdGUuem9vbSA6IHpvb207XG4gICAgICB2YXIgcGFuID0ge1xuICAgICAgICAvLyBtaWRkbGVcbiAgICAgICAgeDogKHcgLSB6b29tICogKGJiLngxICsgYmIueDIpKSAvIDIsXG4gICAgICAgIHk6IChoIC0gem9vbSAqIChiYi55MSArIGJiLnkyKSkgLyAyXG4gICAgICB9O1xuICAgICAgcmV0dXJuIHBhbjtcbiAgICB9LFxuICAgIHJlc2V0OiBmdW5jdGlvbiByZXNldCgpIHtcbiAgICAgIGlmICghdGhpcy5fcHJpdmF0ZS5wYW5uaW5nRW5hYmxlZCB8fCAhdGhpcy5fcHJpdmF0ZS56b29taW5nRW5hYmxlZCkge1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cblxuICAgICAgdGhpcy52aWV3cG9ydCh7XG4gICAgICAgIHBhbjoge1xuICAgICAgICAgIHg6IDAsXG4gICAgICAgICAgeTogMFxuICAgICAgICB9LFxuICAgICAgICB6b29tOiAxXG4gICAgICB9KTtcbiAgICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICAgIH0sXG4gICAgaW52YWxpZGF0ZVNpemU6IGZ1bmN0aW9uIGludmFsaWRhdGVTaXplKCkge1xuICAgICAgdGhpcy5fcHJpdmF0ZS5zaXplQ2FjaGUgPSBudWxsO1xuICAgIH0sXG4gICAgc2l6ZTogZnVuY3Rpb24gc2l6ZSgpIHtcbiAgICAgIHZhciBfcCA9IHRoaXMuX3ByaXZhdGU7XG4gICAgICB2YXIgY29udGFpbmVyID0gX3AuY29udGFpbmVyO1xuICAgICAgdmFyIGN5ID0gdGhpcztcbiAgICAgIHJldHVybiBfcC5zaXplQ2FjaGUgPSBfcC5zaXplQ2FjaGUgfHwgKGNvbnRhaW5lciA/IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHN0eWxlID0gY3kud2luZG93KCkuZ2V0Q29tcHV0ZWRTdHlsZShjb250YWluZXIpO1xuXG4gICAgICAgIHZhciB2YWwgPSBmdW5jdGlvbiB2YWwobmFtZSkge1xuICAgICAgICAgIHJldHVybiBwYXJzZUZsb2F0KHN0eWxlLmdldFByb3BlcnR5VmFsdWUobmFtZSkpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgd2lkdGg6IGNvbnRhaW5lci5jbGllbnRXaWR0aCAtIHZhbCgncGFkZGluZy1sZWZ0JykgLSB2YWwoJ3BhZGRpbmctcmlnaHQnKSxcbiAgICAgICAgICBoZWlnaHQ6IGNvbnRhaW5lci5jbGllbnRIZWlnaHQgLSB2YWwoJ3BhZGRpbmctdG9wJykgLSB2YWwoJ3BhZGRpbmctYm90dG9tJylcbiAgICAgICAgfTtcbiAgICAgIH0oKSA6IHtcbiAgICAgICAgLy8gZmFsbGJhY2sgaWYgbm8gY29udGFpbmVyIChub3QgMCBiL2MgY2FuIGJlIHVzZWQgZm9yIGRpdmlkaW5nIGV0YylcbiAgICAgICAgd2lkdGg6IDEsXG4gICAgICAgIGhlaWdodDogMVxuICAgICAgfSk7XG4gICAgfSxcbiAgICB3aWR0aDogZnVuY3Rpb24gd2lkdGgoKSB7XG4gICAgICByZXR1cm4gdGhpcy5zaXplKCkud2lkdGg7XG4gICAgfSxcbiAgICBoZWlnaHQ6IGZ1bmN0aW9uIGhlaWdodCgpIHtcbiAgICAgIHJldHVybiB0aGlzLnNpemUoKS5oZWlnaHQ7XG4gICAgfSxcbiAgICBleHRlbnQ6IGZ1bmN0aW9uIGV4dGVudCgpIHtcbiAgICAgIHZhciBwYW4gPSB0aGlzLl9wcml2YXRlLnBhbjtcbiAgICAgIHZhciB6b29tID0gdGhpcy5fcHJpdmF0ZS56b29tO1xuICAgICAgdmFyIHJiID0gdGhpcy5yZW5kZXJlZEV4dGVudCgpO1xuICAgICAgdmFyIGIgPSB7XG4gICAgICAgIHgxOiAocmIueDEgLSBwYW4ueCkgLyB6b29tLFxuICAgICAgICB4MjogKHJiLngyIC0gcGFuLngpIC8gem9vbSxcbiAgICAgICAgeTE6IChyYi55MSAtIHBhbi55KSAvIHpvb20sXG4gICAgICAgIHkyOiAocmIueTIgLSBwYW4ueSkgLyB6b29tXG4gICAgICB9O1xuICAgICAgYi53ID0gYi54MiAtIGIueDE7XG4gICAgICBiLmggPSBiLnkyIC0gYi55MTtcbiAgICAgIHJldHVybiBiO1xuICAgIH0sXG4gICAgcmVuZGVyZWRFeHRlbnQ6IGZ1bmN0aW9uIHJlbmRlcmVkRXh0ZW50KCkge1xuICAgICAgdmFyIHdpZHRoID0gdGhpcy53aWR0aCgpO1xuICAgICAgdmFyIGhlaWdodCA9IHRoaXMuaGVpZ2h0KCk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB4MTogMCxcbiAgICAgICAgeTE6IDAsXG4gICAgICAgIHgyOiB3aWR0aCxcbiAgICAgICAgeTI6IGhlaWdodCxcbiAgICAgICAgdzogd2lkdGgsXG4gICAgICAgIGg6IGhlaWdodFxuICAgICAgfTtcbiAgICB9LFxuICAgIG11bHRpQ2xpY2tEZWJvdW5jZVRpbWU6IGZ1bmN0aW9uIG11bHRpQ2xpY2tEZWJvdW5jZVRpbWUoX2ludCkge1xuICAgICAgaWYgKF9pbnQpIHRoaXMuX3ByaXZhdGUubXVsdGlDbGlja0RlYm91bmNlVGltZSA9IF9pbnQ7ZWxzZSByZXR1cm4gdGhpcy5fcHJpdmF0ZS5tdWx0aUNsaWNrRGVib3VuY2VUaW1lO1xuICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgfVxuICB9OyAvLyBhbGlhc2VzXG5cbiAgY29yZWZuJDEuY2VudHJlID0gY29yZWZuJDEuY2VudGVyOyAvLyBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxuXG4gIGNvcmVmbiQxLmF1dG9sb2NrTm9kZXMgPSBjb3JlZm4kMS5hdXRvbG9jaztcbiAgY29yZWZuJDEuYXV0b3VuZ3JhYmlmeU5vZGVzID0gY29yZWZuJDEuYXV0b3VuZ3JhYmlmeTtcblxuICB2YXIgZm4gPSB7XG4gICAgZGF0YTogZGVmaW5lLmRhdGEoe1xuICAgICAgZmllbGQ6ICdkYXRhJyxcbiAgICAgIGJpbmRpbmdFdmVudDogJ2RhdGEnLFxuICAgICAgYWxsb3dCaW5kaW5nOiB0cnVlLFxuICAgICAgYWxsb3dTZXR0aW5nOiB0cnVlLFxuICAgICAgc2V0dGluZ0V2ZW50OiAnZGF0YScsXG4gICAgICBzZXR0aW5nVHJpZ2dlcnNFdmVudDogdHJ1ZSxcbiAgICAgIHRyaWdnZXJGbk5hbWU6ICd0cmlnZ2VyJyxcbiAgICAgIGFsbG93R2V0dGluZzogdHJ1ZSxcbiAgICAgIHVwZGF0ZVN0eWxlOiB0cnVlXG4gICAgfSksXG4gICAgcmVtb3ZlRGF0YTogZGVmaW5lLnJlbW92ZURhdGEoe1xuICAgICAgZmllbGQ6ICdkYXRhJyxcbiAgICAgIGV2ZW50OiAnZGF0YScsXG4gICAgICB0cmlnZ2VyRm5OYW1lOiAndHJpZ2dlcicsXG4gICAgICB0cmlnZ2VyRXZlbnQ6IHRydWUsXG4gICAgICB1cGRhdGVTdHlsZTogdHJ1ZVxuICAgIH0pLFxuICAgIHNjcmF0Y2g6IGRlZmluZS5kYXRhKHtcbiAgICAgIGZpZWxkOiAnc2NyYXRjaCcsXG4gICAgICBiaW5kaW5nRXZlbnQ6ICdzY3JhdGNoJyxcbiAgICAgIGFsbG93QmluZGluZzogdHJ1ZSxcbiAgICAgIGFsbG93U2V0dGluZzogdHJ1ZSxcbiAgICAgIHNldHRpbmdFdmVudDogJ3NjcmF0Y2gnLFxuICAgICAgc2V0dGluZ1RyaWdnZXJzRXZlbnQ6IHRydWUsXG4gICAgICB0cmlnZ2VyRm5OYW1lOiAndHJpZ2dlcicsXG4gICAgICBhbGxvd0dldHRpbmc6IHRydWUsXG4gICAgICB1cGRhdGVTdHlsZTogdHJ1ZVxuICAgIH0pLFxuICAgIHJlbW92ZVNjcmF0Y2g6IGRlZmluZS5yZW1vdmVEYXRhKHtcbiAgICAgIGZpZWxkOiAnc2NyYXRjaCcsXG4gICAgICBldmVudDogJ3NjcmF0Y2gnLFxuICAgICAgdHJpZ2dlckZuTmFtZTogJ3RyaWdnZXInLFxuICAgICAgdHJpZ2dlckV2ZW50OiB0cnVlLFxuICAgICAgdXBkYXRlU3R5bGU6IHRydWVcbiAgICB9KVxuICB9OyAvLyBhbGlhc2VzXG5cbiAgZm4uYXR0ciA9IGZuLmRhdGE7XG4gIGZuLnJlbW92ZUF0dHIgPSBmbi5yZW1vdmVEYXRhO1xuXG4gIHZhciBDb3JlID0gZnVuY3Rpb24gQ29yZShvcHRzKSB7XG4gICAgdmFyIGN5ID0gdGhpcztcbiAgICBvcHRzID0gZXh0ZW5kKHt9LCBvcHRzKTtcbiAgICB2YXIgY29udGFpbmVyID0gb3B0cy5jb250YWluZXI7IC8vIGFsbG93IGZvciBwYXNzaW5nIGEgd3JhcHBlZCBqcXVlcnkgb2JqZWN0XG4gICAgLy8gZS5nLiBjeXRvc2NhcGUoeyBjb250YWluZXI6ICQoJyNjeScpIH0pXG5cbiAgICBpZiAoY29udGFpbmVyICYmICFodG1sRWxlbWVudChjb250YWluZXIpICYmIGh0bWxFbGVtZW50KGNvbnRhaW5lclswXSkpIHtcbiAgICAgIGNvbnRhaW5lciA9IGNvbnRhaW5lclswXTtcbiAgICB9XG5cbiAgICB2YXIgcmVnID0gY29udGFpbmVyID8gY29udGFpbmVyLl9jeXJlZyA6IG51bGw7IC8vIGUuZy4gYWxyZWFkeSByZWdpc3RlcmVkIHNvbWUgaW5mbyAoZS5nLiByZWFkaWVzKSB2aWEganF1ZXJ5XG5cbiAgICByZWcgPSByZWcgfHwge307XG5cbiAgICBpZiAocmVnICYmIHJlZy5jeSkge1xuICAgICAgcmVnLmN5LmRlc3Ryb3koKTtcbiAgICAgIHJlZyA9IHt9OyAvLyBvbGQgaW5zdGFuY2UgPT4gcmVwbGFjZSByZWcgY29tcGxldGVseVxuICAgIH1cblxuICAgIHZhciByZWFkaWVzID0gcmVnLnJlYWRpZXMgPSByZWcucmVhZGllcyB8fCBbXTtcblxuICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgIGNvbnRhaW5lci5fY3lyZWcgPSByZWc7XG4gICAgfSAvLyBtYWtlIHN1cmUgY29udGFpbmVyIGFzc29jJ2QgcmVnIHBvaW50cyB0byB0aGlzIGN5XG5cblxuICAgIHJlZy5jeSA9IGN5O1xuICAgIHZhciBoZWFkID0gX3dpbmRvdyAhPT0gdW5kZWZpbmVkICYmIGNvbnRhaW5lciAhPT0gdW5kZWZpbmVkICYmICFvcHRzLmhlYWRsZXNzO1xuICAgIHZhciBvcHRpb25zID0gb3B0cztcbiAgICBvcHRpb25zLmxheW91dCA9IGV4dGVuZCh7XG4gICAgICBuYW1lOiBoZWFkID8gJ2dyaWQnIDogJ251bGwnXG4gICAgfSwgb3B0aW9ucy5sYXlvdXQpO1xuICAgIG9wdGlvbnMucmVuZGVyZXIgPSBleHRlbmQoe1xuICAgICAgbmFtZTogaGVhZCA/ICdjYW52YXMnIDogJ251bGwnXG4gICAgfSwgb3B0aW9ucy5yZW5kZXJlcik7XG5cbiAgICB2YXIgZGVmVmFsID0gZnVuY3Rpb24gZGVmVmFsKGRlZiwgdmFsLCBhbHRWYWwpIHtcbiAgICAgIGlmICh2YWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgICAgfSBlbHNlIGlmIChhbHRWYWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gYWx0VmFsO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGRlZjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIF9wID0gdGhpcy5fcHJpdmF0ZSA9IHtcbiAgICAgIGNvbnRhaW5lcjogY29udGFpbmVyLFxuICAgICAgLy8gaHRtbCBkb20gZWxlIGNvbnRhaW5lclxuICAgICAgcmVhZHk6IGZhbHNlLFxuICAgICAgLy8gd2hldGhlciByZWFkeSBoYXMgYmVlbiB0cmlnZ2VyZWRcbiAgICAgIG9wdGlvbnM6IG9wdGlvbnMsXG4gICAgICAvLyBjYWNoZWQgb3B0aW9uc1xuICAgICAgZWxlbWVudHM6IG5ldyBDb2xsZWN0aW9uKHRoaXMpLFxuICAgICAgLy8gZWxlbWVudHMgaW4gdGhlIGdyYXBoXG4gICAgICBsaXN0ZW5lcnM6IFtdLFxuICAgICAgLy8gbGlzdCBvZiBsaXN0ZW5lcnNcbiAgICAgIGFuaUVsZXM6IG5ldyBDb2xsZWN0aW9uKHRoaXMpLFxuICAgICAgLy8gZWxlbWVudHMgYmVpbmcgYW5pbWF0ZWRcbiAgICAgIGRhdGE6IG9wdGlvbnMuZGF0YSB8fCB7fSxcbiAgICAgIC8vIGRhdGEgZm9yIHRoZSBjb3JlXG4gICAgICBzY3JhdGNoOiB7fSxcbiAgICAgIC8vIHNjcmF0Y2ggb2JqZWN0IGZvciBjb3JlXG4gICAgICBsYXlvdXQ6IG51bGwsXG4gICAgICByZW5kZXJlcjogbnVsbCxcbiAgICAgIGRlc3Ryb3llZDogZmFsc2UsXG4gICAgICAvLyB3aGV0aGVyIGRlc3Ryb3kgd2FzIGNhbGxlZFxuICAgICAgbm90aWZpY2F0aW9uc0VuYWJsZWQ6IHRydWUsXG4gICAgICAvLyB3aGV0aGVyIG5vdGlmaWNhdGlvbnMgYXJlIHNlbnQgdG8gdGhlIHJlbmRlcmVyXG4gICAgICBtaW5ab29tOiAxZS01MCxcbiAgICAgIG1heFpvb206IDFlNTAsXG4gICAgICB6b29taW5nRW5hYmxlZDogZGVmVmFsKHRydWUsIG9wdGlvbnMuem9vbWluZ0VuYWJsZWQpLFxuICAgICAgdXNlclpvb21pbmdFbmFibGVkOiBkZWZWYWwodHJ1ZSwgb3B0aW9ucy51c2VyWm9vbWluZ0VuYWJsZWQpLFxuICAgICAgcGFubmluZ0VuYWJsZWQ6IGRlZlZhbCh0cnVlLCBvcHRpb25zLnBhbm5pbmdFbmFibGVkKSxcbiAgICAgIHVzZXJQYW5uaW5nRW5hYmxlZDogZGVmVmFsKHRydWUsIG9wdGlvbnMudXNlclBhbm5pbmdFbmFibGVkKSxcbiAgICAgIGJveFNlbGVjdGlvbkVuYWJsZWQ6IGRlZlZhbCh0cnVlLCBvcHRpb25zLmJveFNlbGVjdGlvbkVuYWJsZWQpLFxuICAgICAgYXV0b2xvY2s6IGRlZlZhbChmYWxzZSwgb3B0aW9ucy5hdXRvbG9jaywgb3B0aW9ucy5hdXRvbG9ja05vZGVzKSxcbiAgICAgIGF1dG91bmdyYWJpZnk6IGRlZlZhbChmYWxzZSwgb3B0aW9ucy5hdXRvdW5ncmFiaWZ5LCBvcHRpb25zLmF1dG91bmdyYWJpZnlOb2RlcyksXG4gICAgICBhdXRvdW5zZWxlY3RpZnk6IGRlZlZhbChmYWxzZSwgb3B0aW9ucy5hdXRvdW5zZWxlY3RpZnkpLFxuICAgICAgc3R5bGVFbmFibGVkOiBvcHRpb25zLnN0eWxlRW5hYmxlZCA9PT0gdW5kZWZpbmVkID8gaGVhZCA6IG9wdGlvbnMuc3R5bGVFbmFibGVkLFxuICAgICAgem9vbTogbnVtYmVyJDEob3B0aW9ucy56b29tKSA/IG9wdGlvbnMuem9vbSA6IDEsXG4gICAgICBwYW46IHtcbiAgICAgICAgeDogcGxhaW5PYmplY3Qob3B0aW9ucy5wYW4pICYmIG51bWJlciQxKG9wdGlvbnMucGFuLngpID8gb3B0aW9ucy5wYW4ueCA6IDAsXG4gICAgICAgIHk6IHBsYWluT2JqZWN0KG9wdGlvbnMucGFuKSAmJiBudW1iZXIkMShvcHRpb25zLnBhbi55KSA/IG9wdGlvbnMucGFuLnkgOiAwXG4gICAgICB9LFxuICAgICAgYW5pbWF0aW9uOiB7XG4gICAgICAgIC8vIG9iamVjdCBmb3IgY3VycmVudGx5LXJ1bm5pbmcgYW5pbWF0aW9uc1xuICAgICAgICBjdXJyZW50OiBbXSxcbiAgICAgICAgcXVldWU6IFtdXG4gICAgICB9LFxuICAgICAgaGFzQ29tcG91bmROb2RlczogZmFsc2UsXG4gICAgICBtdWx0aUNsaWNrRGVib3VuY2VUaW1lOiBkZWZWYWwoMjUwLCBvcHRpb25zLm11bHRpQ2xpY2tEZWJvdW5jZVRpbWUpXG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlRW1pdHRlcigpOyAvLyBzZXQgc2VsZWN0aW9uIHR5cGVcblxuICAgIHRoaXMuc2VsZWN0aW9uVHlwZShvcHRpb25zLnNlbGVjdGlvblR5cGUpOyAvLyBpbml0IHpvb20gYm91bmRzXG5cbiAgICB0aGlzLnpvb21SYW5nZSh7XG4gICAgICBtaW46IG9wdGlvbnMubWluWm9vbSxcbiAgICAgIG1heDogb3B0aW9ucy5tYXhab29tXG4gICAgfSk7XG5cbiAgICB2YXIgbG9hZEV4dERhdGEgPSBmdW5jdGlvbiBsb2FkRXh0RGF0YShleHREYXRhLCBuZXh0KSB7XG4gICAgICB2YXIgYW55SXNQcm9taXNlID0gZXh0RGF0YS5zb21lKHByb21pc2UpO1xuXG4gICAgICBpZiAoYW55SXNQcm9taXNlKSB7XG4gICAgICAgIHJldHVybiBQcm9taXNlJDEuYWxsKGV4dERhdGEpLnRoZW4obmV4dCk7IC8vIGxvYWQgYWxsIGRhdGEgYXN5bmNocm9ub3VzbHksIHRoZW4gZXhlYyByZXN0IG9mIGluaXRcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG5leHQoZXh0RGF0YSk7IC8vIGV4ZWMgc3luY2hyb25vdXNseSBmb3IgY29udmVuaWVuY2VcbiAgICAgIH1cbiAgICB9OyAvLyBzdGFydCB3aXRoIHRoZSBkZWZhdWx0IHN0eWxlc2hlZXQgc28gd2UgaGF2ZSBzb21ldGhpbmcgYmVmb3JlIGxvYWRpbmcgYW4gZXh0ZXJuYWwgc3R5bGVzaGVldFxuXG5cbiAgICBpZiAoX3Auc3R5bGVFbmFibGVkKSB7XG4gICAgICBjeS5zZXRTdHlsZShbXSk7XG4gICAgfSAvLyBjcmVhdGUgdGhlIHJlbmRlcmVyXG5cblxuICAgIHZhciByZW5kZXJlck9wdGlvbnMgPSBleHRlbmQoe30sIG9wdGlvbnMsIG9wdGlvbnMucmVuZGVyZXIpOyAvLyBhbGxvdyByZW5kZXJpbmcgaGludHMgaW4gdG9wIGxldmVsIG9wdGlvbnNcblxuICAgIGN5LmluaXRSZW5kZXJlcihyZW5kZXJlck9wdGlvbnMpO1xuXG4gICAgdmFyIHNldEVsZXNBbmRMYXlvdXQgPSBmdW5jdGlvbiBzZXRFbGVzQW5kTGF5b3V0KGVsZW1lbnRzLCBvbmxvYWQsIG9uZG9uZSkge1xuICAgICAgY3kubm90aWZpY2F0aW9ucyhmYWxzZSk7IC8vIHJlbW92ZSBvbGQgZWxlbWVudHNcblxuICAgICAgdmFyIG9sZEVsZXMgPSBjeS5tdXRhYmxlRWxlbWVudHMoKTtcblxuICAgICAgaWYgKG9sZEVsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBvbGRFbGVzLnJlbW92ZSgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZWxlbWVudHMgIT0gbnVsbCkge1xuICAgICAgICBpZiAocGxhaW5PYmplY3QoZWxlbWVudHMpIHx8IGFycmF5KGVsZW1lbnRzKSkge1xuICAgICAgICAgIGN5LmFkZChlbGVtZW50cyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY3kub25lKCdsYXlvdXRyZWFkeScsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGN5Lm5vdGlmaWNhdGlvbnModHJ1ZSk7XG4gICAgICAgIGN5LmVtaXQoZSk7IC8vIHdlIG1pc3NlZCB0aGlzIGV2ZW50IGJ5IHR1cm5pbmcgbm90aWZpY2F0aW9ucyBvZmYsIHNvIHBhc3MgaXQgb25cblxuICAgICAgICBjeS5vbmUoJ2xvYWQnLCBvbmxvYWQpO1xuICAgICAgICBjeS5lbWl0QW5kTm90aWZ5KCdsb2FkJyk7XG4gICAgICB9KS5vbmUoJ2xheW91dHN0b3AnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGN5Lm9uZSgnZG9uZScsIG9uZG9uZSk7XG4gICAgICAgIGN5LmVtaXQoJ2RvbmUnKTtcbiAgICAgIH0pO1xuICAgICAgdmFyIGxheW91dE9wdHMgPSBleHRlbmQoe30sIGN5Ll9wcml2YXRlLm9wdGlvbnMubGF5b3V0KTtcbiAgICAgIGxheW91dE9wdHMuZWxlcyA9IGN5LmVsZW1lbnRzKCk7XG4gICAgICBjeS5sYXlvdXQobGF5b3V0T3B0cykucnVuKCk7XG4gICAgfTtcblxuICAgIGxvYWRFeHREYXRhKFtvcHRpb25zLnN0eWxlLCBvcHRpb25zLmVsZW1lbnRzXSwgZnVuY3Rpb24gKHRoZW5zKSB7XG4gICAgICB2YXIgaW5pdFN0eWxlID0gdGhlbnNbMF07XG4gICAgICB2YXIgaW5pdEVsZXMgPSB0aGVuc1sxXTsgLy8gaW5pdCBzdHlsZVxuXG4gICAgICBpZiAoX3Auc3R5bGVFbmFibGVkKSB7XG4gICAgICAgIGN5LnN0eWxlKCkuYXBwZW5kKGluaXRTdHlsZSk7XG4gICAgICB9IC8vIGluaXRpYWwgbG9hZFxuXG5cbiAgICAgIHNldEVsZXNBbmRMYXlvdXQoaW5pdEVsZXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gb25yZWFkeVxuICAgICAgICBjeS5zdGFydEFuaW1hdGlvbkxvb3AoKTtcbiAgICAgICAgX3AucmVhZHkgPSB0cnVlOyAvLyBpZiBhIHJlYWR5IGNhbGxiYWNrIGlzIHNwZWNpZmllZCBhcyBhbiBvcHRpb24sIHRoZSBiaW5kIGl0XG5cbiAgICAgICAgaWYgKGZuJDYob3B0aW9ucy5yZWFkeSkpIHtcbiAgICAgICAgICBjeS5vbigncmVhZHknLCBvcHRpb25zLnJlYWR5KTtcbiAgICAgICAgfSAvLyBiaW5kIGFsbCB0aGUgcmVhZHkgaGFuZGxlcnMgcmVnaXN0ZXJlZCBiZWZvcmUgY3JlYXRpbmcgdGhpcyBpbnN0YW5jZVxuXG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZWFkaWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgdmFyIGZuID0gcmVhZGllc1tpXTtcbiAgICAgICAgICBjeS5vbigncmVhZHknLCBmbik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocmVnKSB7XG4gICAgICAgICAgcmVnLnJlYWRpZXMgPSBbXTtcbiAgICAgICAgfSAvLyBjbGVhciBiL2Mgd2UndmUgYm91bmQgdGhlbSBhbGwgYW5kIGRvbid0IHdhbnQgdG8ga2VlcCBpdCBhcm91bmQgaW4gY2FzZSBhIG5ldyBjb3JlIHVzZXMgdGhlIHNhbWUgZGl2IGV0Y1xuXG5cbiAgICAgICAgY3kuZW1pdCgncmVhZHknKTtcbiAgICAgIH0sIG9wdGlvbnMuZG9uZSk7XG4gICAgfSk7XG4gIH07XG5cbiAgdmFyIGNvcmVmbiA9IENvcmUucHJvdG90eXBlOyAvLyBzaG9ydCBhbGlhc1xuXG4gIGV4dGVuZChjb3JlZm4sIHtcbiAgICBpbnN0YW5jZVN0cmluZzogZnVuY3Rpb24gaW5zdGFuY2VTdHJpbmcoKSB7XG4gICAgICByZXR1cm4gJ2NvcmUnO1xuICAgIH0sXG4gICAgaXNSZWFkeTogZnVuY3Rpb24gaXNSZWFkeSgpIHtcbiAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLnJlYWR5O1xuICAgIH0sXG4gICAgZGVzdHJveWVkOiBmdW5jdGlvbiBkZXN0cm95ZWQoKSB7XG4gICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5kZXN0cm95ZWQ7XG4gICAgfSxcbiAgICByZWFkeTogZnVuY3Rpb24gcmVhZHkoZm4pIHtcbiAgICAgIGlmICh0aGlzLmlzUmVhZHkoKSkge1xuICAgICAgICB0aGlzLmVtaXR0ZXIoKS5lbWl0KCdyZWFkeScsIFtdLCBmbik7IC8vIGp1c3QgY2FsbHMgZm4gYXMgdGhvdWdoIHRyaWdnZXJlZCB2aWEgcmVhZHkgZXZlbnRcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMub24oJ3JlYWR5JywgZm4pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIGRlc3Ryb3k6IGZ1bmN0aW9uIGRlc3Ryb3koKSB7XG4gICAgICB2YXIgY3kgPSB0aGlzO1xuICAgICAgaWYgKGN5LmRlc3Ryb3llZCgpKSByZXR1cm47XG4gICAgICBjeS5zdG9wQW5pbWF0aW9uTG9vcCgpO1xuICAgICAgY3kuZGVzdHJveVJlbmRlcmVyKCk7XG4gICAgICB0aGlzLmVtaXQoJ2Rlc3Ryb3knKTtcbiAgICAgIGN5Ll9wcml2YXRlLmRlc3Ryb3llZCA9IHRydWU7XG4gICAgICByZXR1cm4gY3k7XG4gICAgfSxcbiAgICBoYXNFbGVtZW50V2l0aElkOiBmdW5jdGlvbiBoYXNFbGVtZW50V2l0aElkKGlkKSB7XG4gICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5lbGVtZW50cy5oYXNFbGVtZW50V2l0aElkKGlkKTtcbiAgICB9LFxuICAgIGdldEVsZW1lbnRCeUlkOiBmdW5jdGlvbiBnZXRFbGVtZW50QnlJZChpZCkge1xuICAgICAgcmV0dXJuIHRoaXMuX3ByaXZhdGUuZWxlbWVudHMuZ2V0RWxlbWVudEJ5SWQoaWQpO1xuICAgIH0sXG4gICAgaGFzQ29tcG91bmROb2RlczogZnVuY3Rpb24gaGFzQ29tcG91bmROb2RlcygpIHtcbiAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLmhhc0NvbXBvdW5kTm9kZXM7XG4gICAgfSxcbiAgICBoZWFkbGVzczogZnVuY3Rpb24gaGVhZGxlc3MoKSB7XG4gICAgICByZXR1cm4gdGhpcy5fcHJpdmF0ZS5yZW5kZXJlci5pc0hlYWRsZXNzKCk7XG4gICAgfSxcbiAgICBzdHlsZUVuYWJsZWQ6IGZ1bmN0aW9uIHN0eWxlRW5hYmxlZCgpIHtcbiAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLnN0eWxlRW5hYmxlZDtcbiAgICB9LFxuICAgIGFkZFRvUG9vbDogZnVuY3Rpb24gYWRkVG9Qb29sKGVsZXMpIHtcbiAgICAgIHRoaXMuX3ByaXZhdGUuZWxlbWVudHMubWVyZ2UoZWxlcyk7XG5cbiAgICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICAgIH0sXG4gICAgcmVtb3ZlRnJvbVBvb2w6IGZ1bmN0aW9uIHJlbW92ZUZyb21Qb29sKGVsZXMpIHtcbiAgICAgIHRoaXMuX3ByaXZhdGUuZWxlbWVudHMudW5tZXJnZShlbGVzKTtcblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICBjb250YWluZXI6IGZ1bmN0aW9uIGNvbnRhaW5lcigpIHtcbiAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLmNvbnRhaW5lciB8fCBudWxsO1xuICAgIH0sXG4gICAgd2luZG93OiBmdW5jdGlvbiB3aW5kb3coKSB7XG4gICAgICB2YXIgY29udGFpbmVyID0gdGhpcy5fcHJpdmF0ZS5jb250YWluZXI7XG4gICAgICBpZiAoY29udGFpbmVyID09IG51bGwpIHJldHVybiBfd2luZG93O1xuICAgICAgdmFyIG93bmVyRG9jdW1lbnQgPSB0aGlzLl9wcml2YXRlLmNvbnRhaW5lci5vd25lckRvY3VtZW50O1xuXG4gICAgICBpZiAob3duZXJEb2N1bWVudCA9PT0gdW5kZWZpbmVkIHx8IG93bmVyRG9jdW1lbnQgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gX3dpbmRvdztcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcgfHwgX3dpbmRvdztcbiAgICB9LFxuICAgIG1vdW50OiBmdW5jdGlvbiBtb3VudChjb250YWluZXIpIHtcbiAgICAgIGlmIChjb250YWluZXIgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciBjeSA9IHRoaXM7XG4gICAgICB2YXIgX3AgPSBjeS5fcHJpdmF0ZTtcbiAgICAgIHZhciBvcHRpb25zID0gX3Aub3B0aW9ucztcblxuICAgICAgaWYgKCFodG1sRWxlbWVudChjb250YWluZXIpICYmIGh0bWxFbGVtZW50KGNvbnRhaW5lclswXSkpIHtcbiAgICAgICAgY29udGFpbmVyID0gY29udGFpbmVyWzBdO1xuICAgICAgfVxuXG4gICAgICBjeS5zdG9wQW5pbWF0aW9uTG9vcCgpO1xuICAgICAgY3kuZGVzdHJveVJlbmRlcmVyKCk7XG4gICAgICBfcC5jb250YWluZXIgPSBjb250YWluZXI7XG4gICAgICBfcC5zdHlsZUVuYWJsZWQgPSB0cnVlO1xuICAgICAgY3kuaW52YWxpZGF0ZVNpemUoKTtcbiAgICAgIGN5LmluaXRSZW5kZXJlcihleHRlbmQoe30sIG9wdGlvbnMsIG9wdGlvbnMucmVuZGVyZXIsIHtcbiAgICAgICAgLy8gYWxsb3cgY3VzdG9tIHJlbmRlcmVyIG5hbWUgdG8gYmUgcmUtdXNlZCwgb3RoZXJ3aXNlIHVzZSBjYW52YXNcbiAgICAgICAgbmFtZTogb3B0aW9ucy5yZW5kZXJlci5uYW1lID09PSAnbnVsbCcgPyAnY2FudmFzJyA6IG9wdGlvbnMucmVuZGVyZXIubmFtZVxuICAgICAgfSkpO1xuICAgICAgY3kuc3RhcnRBbmltYXRpb25Mb29wKCk7XG4gICAgICBjeS5zdHlsZShvcHRpb25zLnN0eWxlKTtcbiAgICAgIGN5LmVtaXQoJ21vdW50Jyk7XG4gICAgICByZXR1cm4gY3k7XG4gICAgfSxcbiAgICB1bm1vdW50OiBmdW5jdGlvbiB1bm1vdW50KCkge1xuICAgICAgdmFyIGN5ID0gdGhpcztcbiAgICAgIGN5LnN0b3BBbmltYXRpb25Mb29wKCk7XG4gICAgICBjeS5kZXN0cm95UmVuZGVyZXIoKTtcbiAgICAgIGN5LmluaXRSZW5kZXJlcih7XG4gICAgICAgIG5hbWU6ICdudWxsJ1xuICAgICAgfSk7XG4gICAgICBjeS5lbWl0KCd1bm1vdW50Jyk7XG4gICAgICByZXR1cm4gY3k7XG4gICAgfSxcbiAgICBvcHRpb25zOiBmdW5jdGlvbiBvcHRpb25zKCkge1xuICAgICAgcmV0dXJuIGNvcHkodGhpcy5fcHJpdmF0ZS5vcHRpb25zKTtcbiAgICB9LFxuICAgIGpzb246IGZ1bmN0aW9uIGpzb24ob2JqKSB7XG4gICAgICB2YXIgY3kgPSB0aGlzO1xuICAgICAgdmFyIF9wID0gY3kuX3ByaXZhdGU7XG4gICAgICB2YXIgZWxlcyA9IGN5Lm11dGFibGVFbGVtZW50cygpO1xuXG4gICAgICB2YXIgZ2V0RnJlc2hSZWYgPSBmdW5jdGlvbiBnZXRGcmVzaFJlZihlbGUpIHtcbiAgICAgICAgcmV0dXJuIGN5LmdldEVsZW1lbnRCeUlkKGVsZS5pZCgpKTtcbiAgICAgIH07XG5cbiAgICAgIGlmIChwbGFpbk9iamVjdChvYmopKSB7XG4gICAgICAgIC8vIHNldFxuICAgICAgICBjeS5zdGFydEJhdGNoKCk7XG5cbiAgICAgICAgaWYgKG9iai5lbGVtZW50cykge1xuICAgICAgICAgIHZhciBpZEluSnNvbiA9IHt9O1xuXG4gICAgICAgICAgdmFyIHVwZGF0ZUVsZXMgPSBmdW5jdGlvbiB1cGRhdGVFbGVzKGpzb25zLCBncikge1xuICAgICAgICAgICAgdmFyIHRvQWRkID0gW107XG4gICAgICAgICAgICB2YXIgdG9Nb2QgPSBbXTtcblxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBqc29ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICB2YXIganNvbiA9IGpzb25zW2ldO1xuXG4gICAgICAgICAgICAgIGlmICghanNvbi5kYXRhLmlkKSB7XG4gICAgICAgICAgICAgICAgd2FybignY3kuanNvbigpIGNhbm5vdCBoYW5kbGUgZWxlbWVudHMgd2l0aG91dCBhbiBJRCBhdHRyaWJ1dGUnKTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHZhciBpZCA9ICcnICsganNvbi5kYXRhLmlkOyAvLyBpZCBtdXN0IGJlIHN0cmluZ1xuXG4gICAgICAgICAgICAgIHZhciBlbGUgPSBjeS5nZXRFbGVtZW50QnlJZChpZCk7XG4gICAgICAgICAgICAgIGlkSW5Kc29uW2lkXSA9IHRydWU7XG5cbiAgICAgICAgICAgICAgaWYgKGVsZS5sZW5ndGggIT09IDApIHtcbiAgICAgICAgICAgICAgICAvLyBleGlzdGluZyBlbGVtZW50IHNob3VsZCBiZSB1cGRhdGVkXG4gICAgICAgICAgICAgICAgdG9Nb2QucHVzaCh7XG4gICAgICAgICAgICAgICAgICBlbGU6IGVsZSxcbiAgICAgICAgICAgICAgICAgIGpzb246IGpzb25cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBvdGhlcndpc2Ugc2hvdWxkIGJlIGFkZGVkXG4gICAgICAgICAgICAgICAgaWYgKGdyKSB7XG4gICAgICAgICAgICAgICAgICBqc29uLmdyb3VwID0gZ3I7XG4gICAgICAgICAgICAgICAgICB0b0FkZC5wdXNoKGpzb24pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICB0b0FkZC5wdXNoKGpzb24pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjeS5hZGQodG9BZGQpO1xuXG4gICAgICAgICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgdG9Nb2QubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgIHZhciBfdG9Nb2QkX2kgPSB0b01vZFtfaV0sXG4gICAgICAgICAgICAgICAgICBfZWxlID0gX3RvTW9kJF9pLmVsZSxcbiAgICAgICAgICAgICAgICAgIF9qc29uID0gX3RvTW9kJF9pLmpzb247XG5cbiAgICAgICAgICAgICAgX2VsZS5qc29uKF9qc29uKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgaWYgKGFycmF5KG9iai5lbGVtZW50cykpIHtcbiAgICAgICAgICAgIC8vIGVsZW1lbnRzOiBbXVxuICAgICAgICAgICAgdXBkYXRlRWxlcyhvYmouZWxlbWVudHMpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBlbGVtZW50czogeyBub2RlczogW10sIGVkZ2VzOiBbXSB9XG4gICAgICAgICAgICB2YXIgZ3JzID0gWydub2RlcycsICdlZGdlcyddO1xuXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGdycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICB2YXIgZ3IgPSBncnNbaV07XG4gICAgICAgICAgICAgIHZhciBlbGVtZW50cyA9IG9iai5lbGVtZW50c1tncl07XG5cbiAgICAgICAgICAgICAgaWYgKGFycmF5KGVsZW1lbnRzKSkge1xuICAgICAgICAgICAgICAgIHVwZGF0ZUVsZXMoZWxlbWVudHMsIGdyKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHZhciBwYXJlbnRzVG9SZW1vdmUgPSBjeS5jb2xsZWN0aW9uKCk7XG4gICAgICAgICAgZWxlcy5maWx0ZXIoZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICAgICAgcmV0dXJuICFpZEluSnNvbltlbGUuaWQoKV07XG4gICAgICAgICAgfSkuZm9yRWFjaChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgICAgICBpZiAoZWxlLmlzUGFyZW50KCkpIHtcbiAgICAgICAgICAgICAgcGFyZW50c1RvUmVtb3ZlLm1lcmdlKGVsZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBlbGUucmVtb3ZlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7IC8vIHNvIHRoYXQgY2hpbGRyZW4gYXJlIG5vdCByZW1vdmVkIHcvcGFyZW50XG5cbiAgICAgICAgICBwYXJlbnRzVG9SZW1vdmUuZm9yRWFjaChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgICAgICByZXR1cm4gZWxlLmNoaWxkcmVuKCkubW92ZSh7XG4gICAgICAgICAgICAgIHBhcmVudDogbnVsbFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7IC8vIGludGVybWVkaWF0ZSBwYXJlbnRzIG1heSBiZSBtb3ZlZCBieSBwcmlvciBsaW5lLCBzbyBtYWtlIHN1cmUgd2UgcmVtb3ZlIGJ5IGZyZXNoIHJlZnNcblxuICAgICAgICAgIHBhcmVudHNUb1JlbW92ZS5mb3JFYWNoKGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgICAgICAgIHJldHVybiBnZXRGcmVzaFJlZihlbGUpLnJlbW92ZSgpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG9iai5zdHlsZSkge1xuICAgICAgICAgIGN5LnN0eWxlKG9iai5zdHlsZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob2JqLnpvb20gIT0gbnVsbCAmJiBvYmouem9vbSAhPT0gX3Auem9vbSkge1xuICAgICAgICAgIGN5Lnpvb20ob2JqLnpvb20pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG9iai5wYW4pIHtcbiAgICAgICAgICBpZiAob2JqLnBhbi54ICE9PSBfcC5wYW4ueCB8fCBvYmoucGFuLnkgIT09IF9wLnBhbi55KSB7XG4gICAgICAgICAgICBjeS5wYW4ob2JqLnBhbik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG9iai5kYXRhKSB7XG4gICAgICAgICAgY3kuZGF0YShvYmouZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZmllbGRzID0gWydtaW5ab29tJywgJ21heFpvb20nLCAnem9vbWluZ0VuYWJsZWQnLCAndXNlclpvb21pbmdFbmFibGVkJywgJ3Bhbm5pbmdFbmFibGVkJywgJ3VzZXJQYW5uaW5nRW5hYmxlZCcsICdib3hTZWxlY3Rpb25FbmFibGVkJywgJ2F1dG9sb2NrJywgJ2F1dG91bmdyYWJpZnknLCAnYXV0b3Vuc2VsZWN0aWZ5JywgJ211bHRpQ2xpY2tEZWJvdW5jZVRpbWUnXTtcblxuICAgICAgICBmb3IgKHZhciBfaTIgPSAwOyBfaTIgPCBmaWVsZHMubGVuZ3RoOyBfaTIrKykge1xuICAgICAgICAgIHZhciBmID0gZmllbGRzW19pMl07XG5cbiAgICAgICAgICBpZiAob2JqW2ZdICE9IG51bGwpIHtcbiAgICAgICAgICAgIGN5W2ZdKG9ialtmXSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY3kuZW5kQmF0Y2goKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBnZXRcbiAgICAgICAgdmFyIGZsYXQgPSAhIW9iajtcbiAgICAgICAgdmFyIGpzb24gPSB7fTtcblxuICAgICAgICBpZiAoZmxhdCkge1xuICAgICAgICAgIGpzb24uZWxlbWVudHMgPSB0aGlzLmVsZW1lbnRzKCkubWFwKGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgICAgICAgIHJldHVybiBlbGUuanNvbigpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGpzb24uZWxlbWVudHMgPSB7fTtcbiAgICAgICAgICBlbGVzLmZvckVhY2goZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICAgICAgdmFyIGdyb3VwID0gZWxlLmdyb3VwKCk7XG5cbiAgICAgICAgICAgIGlmICghanNvbi5lbGVtZW50c1tncm91cF0pIHtcbiAgICAgICAgICAgICAganNvbi5lbGVtZW50c1tncm91cF0gPSBbXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAganNvbi5lbGVtZW50c1tncm91cF0ucHVzaChlbGUuanNvbigpKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLl9wcml2YXRlLnN0eWxlRW5hYmxlZCkge1xuICAgICAgICAgIGpzb24uc3R5bGUgPSBjeS5zdHlsZSgpLmpzb24oKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGpzb24uZGF0YSA9IGNvcHkoY3kuZGF0YSgpKTtcbiAgICAgICAgdmFyIG9wdGlvbnMgPSBfcC5vcHRpb25zO1xuICAgICAgICBqc29uLnpvb21pbmdFbmFibGVkID0gX3Auem9vbWluZ0VuYWJsZWQ7XG4gICAgICAgIGpzb24udXNlclpvb21pbmdFbmFibGVkID0gX3AudXNlclpvb21pbmdFbmFibGVkO1xuICAgICAgICBqc29uLnpvb20gPSBfcC56b29tO1xuICAgICAgICBqc29uLm1pblpvb20gPSBfcC5taW5ab29tO1xuICAgICAgICBqc29uLm1heFpvb20gPSBfcC5tYXhab29tO1xuICAgICAgICBqc29uLnBhbm5pbmdFbmFibGVkID0gX3AucGFubmluZ0VuYWJsZWQ7XG4gICAgICAgIGpzb24udXNlclBhbm5pbmdFbmFibGVkID0gX3AudXNlclBhbm5pbmdFbmFibGVkO1xuICAgICAgICBqc29uLnBhbiA9IGNvcHkoX3AucGFuKTtcbiAgICAgICAganNvbi5ib3hTZWxlY3Rpb25FbmFibGVkID0gX3AuYm94U2VsZWN0aW9uRW5hYmxlZDtcbiAgICAgICAganNvbi5yZW5kZXJlciA9IGNvcHkob3B0aW9ucy5yZW5kZXJlcik7XG4gICAgICAgIGpzb24uaGlkZUVkZ2VzT25WaWV3cG9ydCA9IG9wdGlvbnMuaGlkZUVkZ2VzT25WaWV3cG9ydDtcbiAgICAgICAganNvbi50ZXh0dXJlT25WaWV3cG9ydCA9IG9wdGlvbnMudGV4dHVyZU9uVmlld3BvcnQ7XG4gICAgICAgIGpzb24ud2hlZWxTZW5zaXRpdml0eSA9IG9wdGlvbnMud2hlZWxTZW5zaXRpdml0eTtcbiAgICAgICAganNvbi5tb3Rpb25CbHVyID0gb3B0aW9ucy5tb3Rpb25CbHVyO1xuICAgICAgICBqc29uLm11bHRpQ2xpY2tEZWJvdW5jZVRpbWUgPSBvcHRpb25zLm11bHRpQ2xpY2tEZWJvdW5jZVRpbWU7XG4gICAgICAgIHJldHVybiBqc29uO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIGNvcmVmbi4kaWQgPSBjb3JlZm4uZ2V0RWxlbWVudEJ5SWQ7XG4gIFtjb3JlZm4kOSwgY29yZWZuJDgsIGVsZXNmbiwgY29yZWZuJDcsIGNvcmVmbiQ2LCBjb3JlZm4kNSwgY29yZWZuJDQsIGNvcmVmbiQzLCBjb3JlZm4kMiwgY29yZWZuJDEsIGZuXS5mb3JFYWNoKGZ1bmN0aW9uIChwcm9wcykge1xuICAgIGV4dGVuZChjb3JlZm4sIHByb3BzKTtcbiAgfSk7XG5cbiAgLyogZXNsaW50LWRpc2FibGUgbm8tdW51c2VkLXZhcnMgKi9cblxuICB2YXIgZGVmYXVsdHMkNyA9IHtcbiAgICBmaXQ6IHRydWUsXG4gICAgLy8gd2hldGhlciB0byBmaXQgdGhlIHZpZXdwb3J0IHRvIHRoZSBncmFwaFxuICAgIGRpcmVjdGVkOiBmYWxzZSxcbiAgICAvLyB3aGV0aGVyIHRoZSB0cmVlIGlzIGRpcmVjdGVkIGRvd253YXJkcyAob3IgZWRnZXMgY2FuIHBvaW50IGluIGFueSBkaXJlY3Rpb24gaWYgZmFsc2UpXG4gICAgcGFkZGluZzogMzAsXG4gICAgLy8gcGFkZGluZyBvbiBmaXRcbiAgICBjaXJjbGU6IGZhbHNlLFxuICAgIC8vIHB1dCBkZXB0aHMgaW4gY29uY2VudHJpYyBjaXJjbGVzIGlmIHRydWUsIHB1dCBkZXB0aHMgdG9wIGRvd24gaWYgZmFsc2VcbiAgICBncmlkOiBmYWxzZSxcbiAgICAvLyB3aGV0aGVyIHRvIGNyZWF0ZSBhbiBldmVuIGdyaWQgaW50byB3aGljaCB0aGUgREFHIGlzIHBsYWNlZCAoY2lyY2xlOmZhbHNlIG9ubHkpXG4gICAgc3BhY2luZ0ZhY3RvcjogMS43NSxcbiAgICAvLyBwb3NpdGl2ZSBzcGFjaW5nIGZhY3RvciwgbGFyZ2VyID0+IG1vcmUgc3BhY2UgYmV0d2VlbiBub2RlcyAoTi5CLiBuL2EgaWYgY2F1c2VzIG92ZXJsYXApXG4gICAgYm91bmRpbmdCb3g6IHVuZGVmaW5lZCxcbiAgICAvLyBjb25zdHJhaW4gbGF5b3V0IGJvdW5kczsgeyB4MSwgeTEsIHgyLCB5MiB9IG9yIHsgeDEsIHkxLCB3LCBoIH1cbiAgICBhdm9pZE92ZXJsYXA6IHRydWUsXG4gICAgLy8gcHJldmVudHMgbm9kZSBvdmVybGFwLCBtYXkgb3ZlcmZsb3cgYm91bmRpbmdCb3ggaWYgbm90IGVub3VnaCBzcGFjZVxuICAgIG5vZGVEaW1lbnNpb25zSW5jbHVkZUxhYmVsczogZmFsc2UsXG4gICAgLy8gRXhjbHVkZXMgdGhlIGxhYmVsIHdoZW4gY2FsY3VsYXRpbmcgbm9kZSBib3VuZGluZyBib3hlcyBmb3IgdGhlIGxheW91dCBhbGdvcml0aG1cbiAgICByb290czogdW5kZWZpbmVkLFxuICAgIC8vIHRoZSByb290cyBvZiB0aGUgdHJlZXNcbiAgICBkZXB0aFNvcnQ6IHVuZGVmaW5lZCxcbiAgICAvLyBhIHNvcnRpbmcgZnVuY3Rpb24gdG8gb3JkZXIgbm9kZXMgYXQgZXF1YWwgZGVwdGguIGUuZy4gZnVuY3Rpb24oYSwgYil7IHJldHVybiBhLmRhdGEoJ3dlaWdodCcpIC0gYi5kYXRhKCd3ZWlnaHQnKSB9XG4gICAgYW5pbWF0ZTogZmFsc2UsXG4gICAgLy8gd2hldGhlciB0byB0cmFuc2l0aW9uIHRoZSBub2RlIHBvc2l0aW9uc1xuICAgIGFuaW1hdGlvbkR1cmF0aW9uOiA1MDAsXG4gICAgLy8gZHVyYXRpb24gb2YgYW5pbWF0aW9uIGluIG1zIGlmIGVuYWJsZWRcbiAgICBhbmltYXRpb25FYXNpbmc6IHVuZGVmaW5lZCxcbiAgICAvLyBlYXNpbmcgb2YgYW5pbWF0aW9uIGlmIGVuYWJsZWQsXG4gICAgYW5pbWF0ZUZpbHRlcjogZnVuY3Rpb24gYW5pbWF0ZUZpbHRlcihub2RlLCBpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuICAgIC8vIGEgZnVuY3Rpb24gdGhhdCBkZXRlcm1pbmVzIHdoZXRoZXIgdGhlIG5vZGUgc2hvdWxkIGJlIGFuaW1hdGVkLiAgQWxsIG5vZGVzIGFuaW1hdGVkIGJ5IGRlZmF1bHQgb24gYW5pbWF0ZSBlbmFibGVkLiAgTm9uLWFuaW1hdGVkIG5vZGVzIGFyZSBwb3NpdGlvbmVkIGltbWVkaWF0ZWx5IHdoZW4gdGhlIGxheW91dCBzdGFydHNcbiAgICByZWFkeTogdW5kZWZpbmVkLFxuICAgIC8vIGNhbGxiYWNrIG9uIGxheW91dHJlYWR5XG4gICAgc3RvcDogdW5kZWZpbmVkLFxuICAgIC8vIGNhbGxiYWNrIG9uIGxheW91dHN0b3BcbiAgICB0cmFuc2Zvcm06IGZ1bmN0aW9uIHRyYW5zZm9ybShub2RlLCBwb3NpdGlvbikge1xuICAgICAgcmV0dXJuIHBvc2l0aW9uO1xuICAgIH0gLy8gdHJhbnNmb3JtIGEgZ2l2ZW4gbm9kZSBwb3NpdGlvbi4gVXNlZnVsIGZvciBjaGFuZ2luZyBmbG93IGRpcmVjdGlvbiBpbiBkaXNjcmV0ZSBsYXlvdXRzXG5cbiAgfTtcbiAgdmFyIGRlcHJlY2F0ZWRPcHRpb25EZWZhdWx0cyA9IHtcbiAgICBtYXhpbWFsOiBmYWxzZSxcbiAgICAvLyB3aGV0aGVyIHRvIHNoaWZ0IG5vZGVzIGRvd24gdGhlaXIgbmF0dXJhbCBCRlMgZGVwdGhzIGluIG9yZGVyIHRvIGF2b2lkIHVwd2FyZHMgZWRnZXMgKERBR1Mgb25seSk7IHNldHRpbmcgYWN5Y2xpYyB0byB0cnVlIHNldHMgbWF4aW1hbCB0byB0cnVlIGFsc29cbiAgICBhY3ljbGljOiBmYWxzZSAvLyB3aGV0aGVyIHRoZSB0cmVlIGlzIGFjeWNsaWMgYW5kIHRodXMgYSBub2RlIGNvdWxkIGJlIHNoaWZ0ZWQgKGR1ZSB0byB0aGUgbWF4aW1hbCBvcHRpb24pIG11bHRpcGxlIHRpbWVzIHdpdGhvdXQgY2F1c2luZyBhbiBpbmZpbml0ZSBsb29wOyBzZXR0aW5nIHRvIHRydWUgc2V0cyBtYXhpbWFsIHRvIHRydWUgYWxzbzsgaWYgeW91IGFyZSB1bmNlcnRhaW4gd2hldGhlciBhIHRyZWUgaXMgYWN5Y2xpYywgc2V0IHRvIGZhbHNlIHRvIGF2b2lkIHBvdGVudGlhbCBpbmZpbml0ZSBsb29wc1xuXG4gIH07XG4gIC8qIGVzbGludC1lbmFibGUgKi9cblxuICB2YXIgZ2V0SW5mbyA9IGZ1bmN0aW9uIGdldEluZm8oZWxlKSB7XG4gICAgcmV0dXJuIGVsZS5zY3JhdGNoKCdicmVhZHRoZmlyc3QnKTtcbiAgfTtcblxuICB2YXIgc2V0SW5mbyA9IGZ1bmN0aW9uIHNldEluZm8oZWxlLCBvYmopIHtcbiAgICByZXR1cm4gZWxlLnNjcmF0Y2goJ2JyZWFkdGhmaXJzdCcsIG9iaik7XG4gIH07XG5cbiAgZnVuY3Rpb24gQnJlYWR0aEZpcnN0TGF5b3V0KG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSBleHRlbmQoe30sIGRlZmF1bHRzJDcsIGRlcHJlY2F0ZWRPcHRpb25EZWZhdWx0cywgb3B0aW9ucyk7XG4gIH1cblxuICBCcmVhZHRoRmlyc3RMYXlvdXQucHJvdG90eXBlLnJ1biA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcGFyYW1zID0gdGhpcy5vcHRpb25zO1xuICAgIHZhciBvcHRpb25zID0gcGFyYW1zO1xuICAgIHZhciBjeSA9IHBhcmFtcy5jeTtcbiAgICB2YXIgZWxlcyA9IG9wdGlvbnMuZWxlcztcbiAgICB2YXIgbm9kZXMgPSBlbGVzLm5vZGVzKCkuZmlsdGVyKGZ1bmN0aW9uIChuKSB7XG4gICAgICByZXR1cm4gIW4uaXNQYXJlbnQoKTtcbiAgICB9KTtcbiAgICB2YXIgZ3JhcGggPSBlbGVzO1xuICAgIHZhciBkaXJlY3RlZCA9IG9wdGlvbnMuZGlyZWN0ZWQ7XG4gICAgdmFyIG1heGltYWwgPSBvcHRpb25zLmFjeWNsaWMgfHwgb3B0aW9ucy5tYXhpbWFsIHx8IG9wdGlvbnMubWF4aW1hbEFkanVzdG1lbnRzID4gMDsgLy8gbWF4aW1hbEFkanVzdG1lbnRzIGZvciBjb21wYXQuIHcvIG9sZCBjb2RlOyBhbHNvLCBzZXR0aW5nIGFjeWNsaWMgdG8gdHJ1ZSBzZXRzIG1heGltYWwgdG8gdHJ1ZVxuXG4gICAgdmFyIGJiID0gbWFrZUJvdW5kaW5nQm94KG9wdGlvbnMuYm91bmRpbmdCb3ggPyBvcHRpb25zLmJvdW5kaW5nQm94IDoge1xuICAgICAgeDE6IDAsXG4gICAgICB5MTogMCxcbiAgICAgIHc6IGN5LndpZHRoKCksXG4gICAgICBoOiBjeS5oZWlnaHQoKVxuICAgIH0pO1xuICAgIHZhciByb290cztcblxuICAgIGlmIChlbGVtZW50T3JDb2xsZWN0aW9uKG9wdGlvbnMucm9vdHMpKSB7XG4gICAgICByb290cyA9IG9wdGlvbnMucm9vdHM7XG4gICAgfSBlbHNlIGlmIChhcnJheShvcHRpb25zLnJvb3RzKSkge1xuICAgICAgdmFyIHJvb3RzQXJyYXkgPSBbXTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcHRpb25zLnJvb3RzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBpZCA9IG9wdGlvbnMucm9vdHNbaV07XG4gICAgICAgIHZhciBlbGUgPSBjeS5nZXRFbGVtZW50QnlJZChpZCk7XG4gICAgICAgIHJvb3RzQXJyYXkucHVzaChlbGUpO1xuICAgICAgfVxuXG4gICAgICByb290cyA9IGN5LmNvbGxlY3Rpb24ocm9vdHNBcnJheSk7XG4gICAgfSBlbHNlIGlmIChzdHJpbmcob3B0aW9ucy5yb290cykpIHtcbiAgICAgIHJvb3RzID0gY3kuJChvcHRpb25zLnJvb3RzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGRpcmVjdGVkKSB7XG4gICAgICAgIHJvb3RzID0gbm9kZXMucm9vdHMoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBjb21wb25lbnRzID0gZWxlcy5jb21wb25lbnRzKCk7XG4gICAgICAgIHJvb3RzID0gY3kuY29sbGVjdGlvbigpO1xuXG4gICAgICAgIHZhciBfbG9vcCA9IGZ1bmN0aW9uIF9sb29wKF9pKSB7XG4gICAgICAgICAgdmFyIGNvbXAgPSBjb21wb25lbnRzW19pXTtcbiAgICAgICAgICB2YXIgbWF4RGVncmVlID0gY29tcC5tYXhEZWdyZWUoZmFsc2UpO1xuICAgICAgICAgIHZhciBjb21wUm9vdHMgPSBjb21wLmZpbHRlcihmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgICAgICByZXR1cm4gZWxlLmRlZ3JlZShmYWxzZSkgPT09IG1heERlZ3JlZTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByb290cyA9IHJvb3RzLmFkZChjb21wUm9vdHMpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBjb21wb25lbnRzLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgIF9sb29wKF9pKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBkZXB0aHMgPSBbXTtcbiAgICB2YXIgZm91bmRCeUJmcyA9IHt9O1xuXG4gICAgdmFyIGFkZFRvRGVwdGggPSBmdW5jdGlvbiBhZGRUb0RlcHRoKGVsZSwgZCkge1xuICAgICAgaWYgKGRlcHRoc1tkXSA9PSBudWxsKSB7XG4gICAgICAgIGRlcHRoc1tkXSA9IFtdO1xuICAgICAgfVxuXG4gICAgICB2YXIgaSA9IGRlcHRoc1tkXS5sZW5ndGg7XG4gICAgICBkZXB0aHNbZF0ucHVzaChlbGUpO1xuICAgICAgc2V0SW5mbyhlbGUsIHtcbiAgICAgICAgaW5kZXg6IGksXG4gICAgICAgIGRlcHRoOiBkXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGNoYW5nZURlcHRoID0gZnVuY3Rpb24gY2hhbmdlRGVwdGgoZWxlLCBuZXdEZXB0aCkge1xuICAgICAgdmFyIF9nZXRJbmZvID0gZ2V0SW5mbyhlbGUpLFxuICAgICAgICAgIGRlcHRoID0gX2dldEluZm8uZGVwdGgsXG4gICAgICAgICAgaW5kZXggPSBfZ2V0SW5mby5pbmRleDtcblxuICAgICAgZGVwdGhzW2RlcHRoXVtpbmRleF0gPSBudWxsO1xuICAgICAgYWRkVG9EZXB0aChlbGUsIG5ld0RlcHRoKTtcbiAgICB9OyAvLyBmaW5kIHRoZSBkZXB0aHMgb2YgdGhlIG5vZGVzXG5cblxuICAgIGdyYXBoLmJmcyh7XG4gICAgICByb290czogcm9vdHMsXG4gICAgICBkaXJlY3RlZDogb3B0aW9ucy5kaXJlY3RlZCxcbiAgICAgIHZpc2l0OiBmdW5jdGlvbiB2aXNpdChub2RlLCBlZGdlLCBwTm9kZSwgaSwgZGVwdGgpIHtcbiAgICAgICAgdmFyIGVsZSA9IG5vZGVbMF07XG4gICAgICAgIHZhciBpZCA9IGVsZS5pZCgpO1xuICAgICAgICBhZGRUb0RlcHRoKGVsZSwgZGVwdGgpO1xuICAgICAgICBmb3VuZEJ5QmZzW2lkXSA9IHRydWU7XG4gICAgICB9XG4gICAgfSk7IC8vIGNoZWNrIGZvciBub2RlcyBub3QgZm91bmQgYnkgYmZzXG5cbiAgICB2YXIgb3JwaGFuTm9kZXMgPSBbXTtcblxuICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IG5vZGVzLmxlbmd0aDsgX2kyKyspIHtcbiAgICAgIHZhciBfZWxlID0gbm9kZXNbX2kyXTtcblxuICAgICAgaWYgKGZvdW5kQnlCZnNbX2VsZS5pZCgpXSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG9ycGhhbk5vZGVzLnB1c2goX2VsZSk7XG4gICAgICB9XG4gICAgfSAvLyBhc3NpZ24gdGhlIG5vZGVzIGEgZGVwdGggYW5kIGluZGV4XG5cblxuICAgIHZhciBhc3NpZ25EZXB0aHNBdCA9IGZ1bmN0aW9uIGFzc2lnbkRlcHRoc0F0KGkpIHtcbiAgICAgIHZhciBlbGVzID0gZGVwdGhzW2ldO1xuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGVsZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdmFyIF9lbGUyID0gZWxlc1tqXTtcblxuICAgICAgICBpZiAoX2VsZTIgPT0gbnVsbCkge1xuICAgICAgICAgIGVsZXMuc3BsaWNlKGosIDEpO1xuICAgICAgICAgIGotLTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNldEluZm8oX2VsZTIsIHtcbiAgICAgICAgICBkZXB0aDogaSxcbiAgICAgICAgICBpbmRleDogalxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGFzc2lnbkRlcHRocyA9IGZ1bmN0aW9uIGFzc2lnbkRlcHRocygpIHtcbiAgICAgIGZvciAodmFyIF9pMyA9IDA7IF9pMyA8IGRlcHRocy5sZW5ndGg7IF9pMysrKSB7XG4gICAgICAgIGFzc2lnbkRlcHRoc0F0KF9pMyk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHZhciBhZGp1c3RNYXhpbWFsbHkgPSBmdW5jdGlvbiBhZGp1c3RNYXhpbWFsbHkoZWxlLCBzaGlmdGVkKSB7XG4gICAgICB2YXIgZUluZm8gPSBnZXRJbmZvKGVsZSk7XG4gICAgICB2YXIgaW5jb21lcnMgPSBlbGUuaW5jb21lcnMoKS5maWx0ZXIoZnVuY3Rpb24gKGVsKSB7XG4gICAgICAgIHJldHVybiBlbC5pc05vZGUoKSAmJiBlbGVzLmhhcyhlbCk7XG4gICAgICB9KTtcbiAgICAgIHZhciBtYXhEZXB0aCA9IC0xO1xuICAgICAgdmFyIGlkID0gZWxlLmlkKCk7XG5cbiAgICAgIGZvciAodmFyIGsgPSAwOyBrIDwgaW5jb21lcnMubGVuZ3RoOyBrKyspIHtcbiAgICAgICAgdmFyIGluY21yID0gaW5jb21lcnNba107XG4gICAgICAgIHZhciBpSW5mbyA9IGdldEluZm8oaW5jbXIpO1xuICAgICAgICBtYXhEZXB0aCA9IE1hdGgubWF4KG1heERlcHRoLCBpSW5mby5kZXB0aCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlSW5mby5kZXB0aCA8PSBtYXhEZXB0aCkge1xuICAgICAgICBpZiAoIW9wdGlvbnMuYWN5Y2xpYyAmJiBzaGlmdGVkW2lkXSkge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIG5ld0RlcHRoID0gbWF4RGVwdGggKyAxO1xuICAgICAgICBjaGFuZ2VEZXB0aChlbGUsIG5ld0RlcHRoKTtcbiAgICAgICAgc2hpZnRlZFtpZF0gPSBuZXdEZXB0aDtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9OyAvLyBmb3IgdGhlIGRpcmVjdGVkIGNhc2UsIHRyeSB0byBtYWtlIHRoZSBlZGdlcyBhbGwgZ28gZG93biAoaS5lLiBkZXB0aCBpID0+IGRlcHRoIGkgKyAxKVxuXG5cbiAgICBpZiAoZGlyZWN0ZWQgJiYgbWF4aW1hbCkge1xuICAgICAgdmFyIFEgPSBbXTtcbiAgICAgIHZhciBzaGlmdGVkID0ge307XG5cbiAgICAgIHZhciBlbnF1ZXVlID0gZnVuY3Rpb24gZW5xdWV1ZShuKSB7XG4gICAgICAgIHJldHVybiBRLnB1c2gobik7XG4gICAgICB9O1xuXG4gICAgICB2YXIgZGVxdWV1ZSA9IGZ1bmN0aW9uIGRlcXVldWUoKSB7XG4gICAgICAgIHJldHVybiBRLnNoaWZ0KCk7XG4gICAgICB9O1xuXG4gICAgICBub2Rlcy5mb3JFYWNoKGZ1bmN0aW9uIChuKSB7XG4gICAgICAgIHJldHVybiBRLnB1c2gobik7XG4gICAgICB9KTtcblxuICAgICAgd2hpbGUgKFEubGVuZ3RoID4gMCkge1xuICAgICAgICB2YXIgX2VsZTMgPSBkZXF1ZXVlKCk7XG5cbiAgICAgICAgdmFyIGRpZFNoaWZ0ID0gYWRqdXN0TWF4aW1hbGx5KF9lbGUzLCBzaGlmdGVkKTtcblxuICAgICAgICBpZiAoZGlkU2hpZnQpIHtcbiAgICAgICAgICBfZWxlMy5vdXRnb2VycygpLmZpbHRlcihmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBlbC5pc05vZGUoKSAmJiBlbGVzLmhhcyhlbCk7XG4gICAgICAgICAgfSkuZm9yRWFjaChlbnF1ZXVlKTtcbiAgICAgICAgfSBlbHNlIGlmIChkaWRTaGlmdCA9PT0gbnVsbCkge1xuICAgICAgICAgIHdhcm4oJ0RldGVjdGVkIGRvdWJsZSBtYXhpbWFsIHNoaWZ0IGZvciBub2RlIGAnICsgX2VsZTMuaWQoKSArICdgLiAgQmFpbGluZyBtYXhpbWFsIGFkanVzdG1lbnQgZHVlIHRvIGN5Y2xlLiAgVXNlIGBvcHRpb25zLm1heGltYWw6IHRydWVgIG9ubHkgb24gREFHcy4nKTtcbiAgICAgICAgICBicmVhazsgLy8gZXhpdCBvbiBmYWlsdXJlXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBhc3NpZ25EZXB0aHMoKTsgLy8gY2xlYXIgaG9sZXNcbiAgICAvLyBmaW5kIG1pbiBkaXN0YW5jZSB3ZSBuZWVkIHRvIGxlYXZlIGJldHdlZW4gbm9kZXNcblxuICAgIHZhciBtaW5EaXN0YW5jZSA9IDA7XG5cbiAgICBpZiAob3B0aW9ucy5hdm9pZE92ZXJsYXApIHtcbiAgICAgIGZvciAodmFyIF9pNCA9IDA7IF9pNCA8IG5vZGVzLmxlbmd0aDsgX2k0KyspIHtcbiAgICAgICAgdmFyIG4gPSBub2Rlc1tfaTRdO1xuICAgICAgICB2YXIgbmJiID0gbi5sYXlvdXREaW1lbnNpb25zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgdyA9IG5iYi53O1xuICAgICAgICB2YXIgaCA9IG5iYi5oO1xuICAgICAgICBtaW5EaXN0YW5jZSA9IE1hdGgubWF4KG1pbkRpc3RhbmNlLCB3LCBoKTtcbiAgICAgIH1cbiAgICB9IC8vIGdldCB0aGUgd2VpZ2h0ZWQgcGVyY2VudCBmb3IgYW4gZWxlbWVudCBiYXNlZCBvbiBpdHMgY29ubmVjdGl2aXR5IHRvIG90aGVyIGxldmVsc1xuXG5cbiAgICB2YXIgY2FjaGVkV2VpZ2h0ZWRQZXJjZW50ID0ge307XG5cbiAgICB2YXIgZ2V0V2VpZ2h0ZWRQZXJjZW50ID0gZnVuY3Rpb24gZ2V0V2VpZ2h0ZWRQZXJjZW50KGVsZSkge1xuICAgICAgaWYgKGNhY2hlZFdlaWdodGVkUGVyY2VudFtlbGUuaWQoKV0pIHtcbiAgICAgICAgcmV0dXJuIGNhY2hlZFdlaWdodGVkUGVyY2VudFtlbGUuaWQoKV07XG4gICAgICB9XG5cbiAgICAgIHZhciBlbGVEZXB0aCA9IGdldEluZm8oZWxlKS5kZXB0aDtcbiAgICAgIHZhciBuZWlnaGJvcnMgPSBlbGUubmVpZ2hib3Job29kKCk7XG4gICAgICB2YXIgcGVyY2VudCA9IDA7XG4gICAgICB2YXIgc2FtcGxlcyA9IDA7XG5cbiAgICAgIGZvciAodmFyIF9pNSA9IDA7IF9pNSA8IG5laWdoYm9ycy5sZW5ndGg7IF9pNSsrKSB7XG4gICAgICAgIHZhciBuZWlnaGJvciA9IG5laWdoYm9yc1tfaTVdO1xuXG4gICAgICAgIGlmIChuZWlnaGJvci5pc0VkZ2UoKSB8fCBuZWlnaGJvci5pc1BhcmVudCgpIHx8ICFub2Rlcy5oYXMobmVpZ2hib3IpKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYmYgPSBnZXRJbmZvKG5laWdoYm9yKTtcblxuICAgICAgICBpZiAoYmYgPT0gbnVsbCkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGluZGV4ID0gYmYuaW5kZXg7XG4gICAgICAgIHZhciBkZXB0aCA9IGJmLmRlcHRoOyAvLyB1bmFzc2lnbmVkIG5laWdoYm91cnMgc2hvdWxkbid0IGFmZmVjdCB0aGUgb3JkZXJpbmdcblxuICAgICAgICBpZiAoaW5kZXggPT0gbnVsbCB8fCBkZXB0aCA9PSBudWxsKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgbkRlcHRoID0gZGVwdGhzW2RlcHRoXS5sZW5ndGg7XG5cbiAgICAgICAgaWYgKGRlcHRoIDwgZWxlRGVwdGgpIHtcbiAgICAgICAgICAvLyBvbmx5IGdldCBpbmZsdWVuY2VkIGJ5IGVsZW1lbnRzIGFib3ZlXG4gICAgICAgICAgcGVyY2VudCArPSBpbmRleCAvIG5EZXB0aDtcbiAgICAgICAgICBzYW1wbGVzKys7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgc2FtcGxlcyA9IE1hdGgubWF4KDEsIHNhbXBsZXMpO1xuICAgICAgcGVyY2VudCA9IHBlcmNlbnQgLyBzYW1wbGVzO1xuXG4gICAgICBpZiAoc2FtcGxlcyA9PT0gMCkge1xuICAgICAgICAvLyBwdXQgbG9uZSBub2RlcyBhdCB0aGUgc3RhcnRcbiAgICAgICAgcGVyY2VudCA9IDA7XG4gICAgICB9XG5cbiAgICAgIGNhY2hlZFdlaWdodGVkUGVyY2VudFtlbGUuaWQoKV0gPSBwZXJjZW50O1xuICAgICAgcmV0dXJuIHBlcmNlbnQ7XG4gICAgfTsgLy8gcmVhcnJhbmdlIHRoZSBpbmRpY2VzIGluIGVhY2ggZGVwdGggbGV2ZWwgYmFzZWQgb24gY29ubmVjdGl2aXR5XG5cblxuICAgIHZhciBzb3J0Rm4gPSBmdW5jdGlvbiBzb3J0Rm4oYSwgYikge1xuICAgICAgdmFyIGFwY3QgPSBnZXRXZWlnaHRlZFBlcmNlbnQoYSk7XG4gICAgICB2YXIgYnBjdCA9IGdldFdlaWdodGVkUGVyY2VudChiKTtcbiAgICAgIHZhciBkaWZmID0gYXBjdCAtIGJwY3Q7XG5cbiAgICAgIGlmIChkaWZmID09PSAwKSB7XG4gICAgICAgIHJldHVybiBhc2NlbmRpbmcoYS5pZCgpLCBiLmlkKCkpOyAvLyBtYWtlIHN1cmUgc29ydCBkb2Vzbid0IGhhdmUgZG9uJ3QtY2FyZSBjb21wYXJpc29uc1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGRpZmY7XG4gICAgICB9XG4gICAgfTtcblxuICAgIGlmIChvcHRpb25zLmRlcHRoU29ydCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBzb3J0Rm4gPSBvcHRpb25zLmRlcHRoU29ydDtcbiAgICB9IC8vIHNvcnQgZWFjaCBsZXZlbCB0byBtYWtlIGNvbm5lY3RlZCBub2RlcyBjbG9zZXJcblxuXG4gICAgZm9yICh2YXIgX2k2ID0gMDsgX2k2IDwgZGVwdGhzLmxlbmd0aDsgX2k2KyspIHtcbiAgICAgIGRlcHRoc1tfaTZdLnNvcnQoc29ydEZuKTtcblxuICAgICAgYXNzaWduRGVwdGhzQXQoX2k2KTtcbiAgICB9IC8vIGFzc2lnbiBvcnBoYW4gbm9kZXMgdG8gYSBuZXcgdG9wLWxldmVsIGRlcHRoXG5cblxuICAgIHZhciBvcnBoYW5EZXB0aCA9IFtdO1xuXG4gICAgZm9yICh2YXIgX2k3ID0gMDsgX2k3IDwgb3JwaGFuTm9kZXMubGVuZ3RoOyBfaTcrKykge1xuICAgICAgb3JwaGFuRGVwdGgucHVzaChvcnBoYW5Ob2Rlc1tfaTddKTtcbiAgICB9XG5cbiAgICBkZXB0aHMudW5zaGlmdChvcnBoYW5EZXB0aCk7XG4gICAgYXNzaWduRGVwdGhzKCk7XG4gICAgdmFyIGJpZ2dlc3REZXB0aFNpemUgPSAwO1xuXG4gICAgZm9yICh2YXIgX2k4ID0gMDsgX2k4IDwgZGVwdGhzLmxlbmd0aDsgX2k4KyspIHtcbiAgICAgIGJpZ2dlc3REZXB0aFNpemUgPSBNYXRoLm1heChkZXB0aHNbX2k4XS5sZW5ndGgsIGJpZ2dlc3REZXB0aFNpemUpO1xuICAgIH1cblxuICAgIHZhciBjZW50ZXIgPSB7XG4gICAgICB4OiBiYi54MSArIGJiLncgLyAyLFxuICAgICAgeTogYmIueDEgKyBiYi5oIC8gMlxuICAgIH07XG4gICAgdmFyIG1heERlcHRoU2l6ZSA9IGRlcHRocy5yZWR1Y2UoZnVuY3Rpb24gKG1heCwgZWxlcykge1xuICAgICAgcmV0dXJuIE1hdGgubWF4KG1heCwgZWxlcy5sZW5ndGgpO1xuICAgIH0sIDApO1xuXG4gICAgdmFyIGdldFBvc2l0aW9uID0gZnVuY3Rpb24gZ2V0UG9zaXRpb24oZWxlKSB7XG4gICAgICB2YXIgX2dldEluZm8yID0gZ2V0SW5mbyhlbGUpLFxuICAgICAgICAgIGRlcHRoID0gX2dldEluZm8yLmRlcHRoLFxuICAgICAgICAgIGluZGV4ID0gX2dldEluZm8yLmluZGV4O1xuXG4gICAgICB2YXIgZGVwdGhTaXplID0gZGVwdGhzW2RlcHRoXS5sZW5ndGg7XG4gICAgICB2YXIgZGlzdGFuY2VYID0gTWF0aC5tYXgoYmIudyAvICgob3B0aW9ucy5ncmlkID8gbWF4RGVwdGhTaXplIDogZGVwdGhTaXplKSArIDEpLCBtaW5EaXN0YW5jZSk7XG4gICAgICB2YXIgZGlzdGFuY2VZID0gTWF0aC5tYXgoYmIuaCAvIChkZXB0aHMubGVuZ3RoICsgMSksIG1pbkRpc3RhbmNlKTtcbiAgICAgIHZhciByYWRpdXNTdGVwU2l6ZSA9IE1hdGgubWluKGJiLncgLyAyIC8gZGVwdGhzLmxlbmd0aCwgYmIuaCAvIDIgLyBkZXB0aHMubGVuZ3RoKTtcbiAgICAgIHJhZGl1c1N0ZXBTaXplID0gTWF0aC5tYXgocmFkaXVzU3RlcFNpemUsIG1pbkRpc3RhbmNlKTtcblxuICAgICAgaWYgKCFvcHRpb25zLmNpcmNsZSkge1xuICAgICAgICB2YXIgZXBvcyA9IHtcbiAgICAgICAgICB4OiBjZW50ZXIueCArIChpbmRleCArIDEgLSAoZGVwdGhTaXplICsgMSkgLyAyKSAqIGRpc3RhbmNlWCxcbiAgICAgICAgICB5OiAoZGVwdGggKyAxKSAqIGRpc3RhbmNlWVxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gZXBvcztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciByYWRpdXMgPSByYWRpdXNTdGVwU2l6ZSAqIGRlcHRoICsgcmFkaXVzU3RlcFNpemUgLSAoZGVwdGhzLmxlbmd0aCA+IDAgJiYgZGVwdGhzWzBdLmxlbmd0aCA8PSAzID8gcmFkaXVzU3RlcFNpemUgLyAyIDogMCk7XG4gICAgICAgIHZhciB0aGV0YSA9IDIgKiBNYXRoLlBJIC8gZGVwdGhzW2RlcHRoXS5sZW5ndGggKiBpbmRleDtcblxuICAgICAgICBpZiAoZGVwdGggPT09IDAgJiYgZGVwdGhzWzBdLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIHJhZGl1cyA9IDE7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHg6IGNlbnRlci54ICsgcmFkaXVzICogTWF0aC5jb3ModGhldGEpLFxuICAgICAgICAgIHk6IGNlbnRlci55ICsgcmFkaXVzICogTWF0aC5zaW4odGhldGEpXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfTtcblxuICAgIGVsZXMubm9kZXMoKS5sYXlvdXRQb3NpdGlvbnModGhpcywgb3B0aW9ucywgZ2V0UG9zaXRpb24pO1xuICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICB9O1xuXG4gIHZhciBkZWZhdWx0cyQ2ID0ge1xuICAgIGZpdDogdHJ1ZSxcbiAgICAvLyB3aGV0aGVyIHRvIGZpdCB0aGUgdmlld3BvcnQgdG8gdGhlIGdyYXBoXG4gICAgcGFkZGluZzogMzAsXG4gICAgLy8gdGhlIHBhZGRpbmcgb24gZml0XG4gICAgYm91bmRpbmdCb3g6IHVuZGVmaW5lZCxcbiAgICAvLyBjb25zdHJhaW4gbGF5b3V0IGJvdW5kczsgeyB4MSwgeTEsIHgyLCB5MiB9IG9yIHsgeDEsIHkxLCB3LCBoIH1cbiAgICBhdm9pZE92ZXJsYXA6IHRydWUsXG4gICAgLy8gcHJldmVudHMgbm9kZSBvdmVybGFwLCBtYXkgb3ZlcmZsb3cgYm91bmRpbmdCb3ggYW5kIHJhZGl1cyBpZiBub3QgZW5vdWdoIHNwYWNlXG4gICAgbm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzOiBmYWxzZSxcbiAgICAvLyBFeGNsdWRlcyB0aGUgbGFiZWwgd2hlbiBjYWxjdWxhdGluZyBub2RlIGJvdW5kaW5nIGJveGVzIGZvciB0aGUgbGF5b3V0IGFsZ29yaXRobVxuICAgIHNwYWNpbmdGYWN0b3I6IHVuZGVmaW5lZCxcbiAgICAvLyBBcHBsaWVzIGEgbXVsdGlwbGljYXRpdmUgZmFjdG9yICg+MCkgdG8gZXhwYW5kIG9yIGNvbXByZXNzIHRoZSBvdmVyYWxsIGFyZWEgdGhhdCB0aGUgbm9kZXMgdGFrZSB1cFxuICAgIHJhZGl1czogdW5kZWZpbmVkLFxuICAgIC8vIHRoZSByYWRpdXMgb2YgdGhlIGNpcmNsZVxuICAgIHN0YXJ0QW5nbGU6IDMgLyAyICogTWF0aC5QSSxcbiAgICAvLyB3aGVyZSBub2RlcyBzdGFydCBpbiByYWRpYW5zXG4gICAgc3dlZXA6IHVuZGVmaW5lZCxcbiAgICAvLyBob3cgbWFueSByYWRpYW5zIHNob3VsZCBiZSBiZXR3ZWVuIHRoZSBmaXJzdCBhbmQgbGFzdCBub2RlIChkZWZhdWx0cyB0byBmdWxsIGNpcmNsZSlcbiAgICBjbG9ja3dpc2U6IHRydWUsXG4gICAgLy8gd2hldGhlciB0aGUgbGF5b3V0IHNob3VsZCBnbyBjbG9ja3dpc2UgKHRydWUpIG9yIGNvdW50ZXJjbG9ja3dpc2UvYW50aWNsb2Nrd2lzZSAoZmFsc2UpXG4gICAgc29ydDogdW5kZWZpbmVkLFxuICAgIC8vIGEgc29ydGluZyBmdW5jdGlvbiB0byBvcmRlciB0aGUgbm9kZXM7IGUuZy4gZnVuY3Rpb24oYSwgYil7IHJldHVybiBhLmRhdGEoJ3dlaWdodCcpIC0gYi5kYXRhKCd3ZWlnaHQnKSB9XG4gICAgYW5pbWF0ZTogZmFsc2UsXG4gICAgLy8gd2hldGhlciB0byB0cmFuc2l0aW9uIHRoZSBub2RlIHBvc2l0aW9uc1xuICAgIGFuaW1hdGlvbkR1cmF0aW9uOiA1MDAsXG4gICAgLy8gZHVyYXRpb24gb2YgYW5pbWF0aW9uIGluIG1zIGlmIGVuYWJsZWRcbiAgICBhbmltYXRpb25FYXNpbmc6IHVuZGVmaW5lZCxcbiAgICAvLyBlYXNpbmcgb2YgYW5pbWF0aW9uIGlmIGVuYWJsZWRcbiAgICBhbmltYXRlRmlsdGVyOiBmdW5jdGlvbiBhbmltYXRlRmlsdGVyKG5vZGUsIGkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG4gICAgLy8gYSBmdW5jdGlvbiB0aGF0IGRldGVybWluZXMgd2hldGhlciB0aGUgbm9kZSBzaG91bGQgYmUgYW5pbWF0ZWQuICBBbGwgbm9kZXMgYW5pbWF0ZWQgYnkgZGVmYXVsdCBvbiBhbmltYXRlIGVuYWJsZWQuICBOb24tYW5pbWF0ZWQgbm9kZXMgYXJlIHBvc2l0aW9uZWQgaW1tZWRpYXRlbHkgd2hlbiB0aGUgbGF5b3V0IHN0YXJ0c1xuICAgIHJlYWR5OiB1bmRlZmluZWQsXG4gICAgLy8gY2FsbGJhY2sgb24gbGF5b3V0cmVhZHlcbiAgICBzdG9wOiB1bmRlZmluZWQsXG4gICAgLy8gY2FsbGJhY2sgb24gbGF5b3V0c3RvcFxuICAgIHRyYW5zZm9ybTogZnVuY3Rpb24gdHJhbnNmb3JtKG5vZGUsIHBvc2l0aW9uKSB7XG4gICAgICByZXR1cm4gcG9zaXRpb247XG4gICAgfSAvLyB0cmFuc2Zvcm0gYSBnaXZlbiBub2RlIHBvc2l0aW9uLiBVc2VmdWwgZm9yIGNoYW5naW5nIGZsb3cgZGlyZWN0aW9uIGluIGRpc2NyZXRlIGxheW91dHMgXG5cbiAgfTtcblxuICBmdW5jdGlvbiBDaXJjbGVMYXlvdXQob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IGV4dGVuZCh7fSwgZGVmYXVsdHMkNiwgb3B0aW9ucyk7XG4gIH1cblxuICBDaXJjbGVMYXlvdXQucHJvdG90eXBlLnJ1biA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcGFyYW1zID0gdGhpcy5vcHRpb25zO1xuICAgIHZhciBvcHRpb25zID0gcGFyYW1zO1xuICAgIHZhciBjeSA9IHBhcmFtcy5jeTtcbiAgICB2YXIgZWxlcyA9IG9wdGlvbnMuZWxlcztcbiAgICB2YXIgY2xvY2t3aXNlID0gb3B0aW9ucy5jb3VudGVyY2xvY2t3aXNlICE9PSB1bmRlZmluZWQgPyAhb3B0aW9ucy5jb3VudGVyY2xvY2t3aXNlIDogb3B0aW9ucy5jbG9ja3dpc2U7XG4gICAgdmFyIG5vZGVzID0gZWxlcy5ub2RlcygpLm5vdCgnOnBhcmVudCcpO1xuXG4gICAgaWYgKG9wdGlvbnMuc29ydCkge1xuICAgICAgbm9kZXMgPSBub2Rlcy5zb3J0KG9wdGlvbnMuc29ydCk7XG4gICAgfVxuXG4gICAgdmFyIGJiID0gbWFrZUJvdW5kaW5nQm94KG9wdGlvbnMuYm91bmRpbmdCb3ggPyBvcHRpb25zLmJvdW5kaW5nQm94IDoge1xuICAgICAgeDE6IDAsXG4gICAgICB5MTogMCxcbiAgICAgIHc6IGN5LndpZHRoKCksXG4gICAgICBoOiBjeS5oZWlnaHQoKVxuICAgIH0pO1xuICAgIHZhciBjZW50ZXIgPSB7XG4gICAgICB4OiBiYi54MSArIGJiLncgLyAyLFxuICAgICAgeTogYmIueTEgKyBiYi5oIC8gMlxuICAgIH07XG4gICAgdmFyIHN3ZWVwID0gb3B0aW9ucy5zd2VlcCA9PT0gdW5kZWZpbmVkID8gMiAqIE1hdGguUEkgLSAyICogTWF0aC5QSSAvIG5vZGVzLmxlbmd0aCA6IG9wdGlvbnMuc3dlZXA7XG4gICAgdmFyIGRUaGV0YSA9IHN3ZWVwIC8gTWF0aC5tYXgoMSwgbm9kZXMubGVuZ3RoIC0gMSk7XG4gICAgdmFyIHI7XG4gICAgdmFyIG1pbkRpc3RhbmNlID0gMDtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBuID0gbm9kZXNbaV07XG4gICAgICB2YXIgbmJiID0gbi5sYXlvdXREaW1lbnNpb25zKG9wdGlvbnMpO1xuICAgICAgdmFyIHcgPSBuYmIudztcbiAgICAgIHZhciBoID0gbmJiLmg7XG4gICAgICBtaW5EaXN0YW5jZSA9IE1hdGgubWF4KG1pbkRpc3RhbmNlLCB3LCBoKTtcbiAgICB9XG5cbiAgICBpZiAobnVtYmVyJDEob3B0aW9ucy5yYWRpdXMpKSB7XG4gICAgICByID0gb3B0aW9ucy5yYWRpdXM7XG4gICAgfSBlbHNlIGlmIChub2Rlcy5sZW5ndGggPD0gMSkge1xuICAgICAgciA9IDA7XG4gICAgfSBlbHNlIHtcbiAgICAgIHIgPSBNYXRoLm1pbihiYi5oLCBiYi53KSAvIDIgLSBtaW5EaXN0YW5jZTtcbiAgICB9IC8vIGNhbGN1bGF0ZSB0aGUgcmFkaXVzXG5cblxuICAgIGlmIChub2Rlcy5sZW5ndGggPiAxICYmIG9wdGlvbnMuYXZvaWRPdmVybGFwKSB7XG4gICAgICAvLyBidXQgb25seSBpZiBtb3JlIHRoYW4gb25lIG5vZGUgKGNhbid0IG92ZXJsYXApXG4gICAgICBtaW5EaXN0YW5jZSAqPSAxLjc1OyAvLyBqdXN0IHRvIGhhdmUgc29tZSBuaWNlIHNwYWNpbmdcblxuICAgICAgdmFyIGRjb3MgPSBNYXRoLmNvcyhkVGhldGEpIC0gTWF0aC5jb3MoMCk7XG4gICAgICB2YXIgZHNpbiA9IE1hdGguc2luKGRUaGV0YSkgLSBNYXRoLnNpbigwKTtcbiAgICAgIHZhciByTWluID0gTWF0aC5zcXJ0KG1pbkRpc3RhbmNlICogbWluRGlzdGFuY2UgLyAoZGNvcyAqIGRjb3MgKyBkc2luICogZHNpbikpOyAvLyBzLnQuIG5vIG5vZGVzIG92ZXJsYXBwaW5nXG5cbiAgICAgIHIgPSBNYXRoLm1heChyTWluLCByKTtcbiAgICB9XG5cbiAgICB2YXIgZ2V0UG9zID0gZnVuY3Rpb24gZ2V0UG9zKGVsZSwgaSkge1xuICAgICAgdmFyIHRoZXRhID0gb3B0aW9ucy5zdGFydEFuZ2xlICsgaSAqIGRUaGV0YSAqIChjbG9ja3dpc2UgPyAxIDogLTEpO1xuICAgICAgdmFyIHJ4ID0gciAqIE1hdGguY29zKHRoZXRhKTtcbiAgICAgIHZhciByeSA9IHIgKiBNYXRoLnNpbih0aGV0YSk7XG4gICAgICB2YXIgcG9zID0ge1xuICAgICAgICB4OiBjZW50ZXIueCArIHJ4LFxuICAgICAgICB5OiBjZW50ZXIueSArIHJ5XG4gICAgICB9O1xuICAgICAgcmV0dXJuIHBvcztcbiAgICB9O1xuXG4gICAgZWxlcy5ub2RlcygpLmxheW91dFBvc2l0aW9ucyh0aGlzLCBvcHRpb25zLCBnZXRQb3MpO1xuICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICB9O1xuXG4gIHZhciBkZWZhdWx0cyQ1ID0ge1xuICAgIGZpdDogdHJ1ZSxcbiAgICAvLyB3aGV0aGVyIHRvIGZpdCB0aGUgdmlld3BvcnQgdG8gdGhlIGdyYXBoXG4gICAgcGFkZGluZzogMzAsXG4gICAgLy8gdGhlIHBhZGRpbmcgb24gZml0XG4gICAgc3RhcnRBbmdsZTogMyAvIDIgKiBNYXRoLlBJLFxuICAgIC8vIHdoZXJlIG5vZGVzIHN0YXJ0IGluIHJhZGlhbnNcbiAgICBzd2VlcDogdW5kZWZpbmVkLFxuICAgIC8vIGhvdyBtYW55IHJhZGlhbnMgc2hvdWxkIGJlIGJldHdlZW4gdGhlIGZpcnN0IGFuZCBsYXN0IG5vZGUgKGRlZmF1bHRzIHRvIGZ1bGwgY2lyY2xlKVxuICAgIGNsb2Nrd2lzZTogdHJ1ZSxcbiAgICAvLyB3aGV0aGVyIHRoZSBsYXlvdXQgc2hvdWxkIGdvIGNsb2Nrd2lzZSAodHJ1ZSkgb3IgY291bnRlcmNsb2Nrd2lzZS9hbnRpY2xvY2t3aXNlIChmYWxzZSlcbiAgICBlcXVpZGlzdGFudDogZmFsc2UsXG4gICAgLy8gd2hldGhlciBsZXZlbHMgaGF2ZSBhbiBlcXVhbCByYWRpYWwgZGlzdGFuY2UgYmV0d2VuIHRoZW0sIG1heSBjYXVzZSBib3VuZGluZyBib3ggb3ZlcmZsb3dcbiAgICBtaW5Ob2RlU3BhY2luZzogMTAsXG4gICAgLy8gbWluIHNwYWNpbmcgYmV0d2VlbiBvdXRzaWRlIG9mIG5vZGVzICh1c2VkIGZvciByYWRpdXMgYWRqdXN0bWVudClcbiAgICBib3VuZGluZ0JveDogdW5kZWZpbmVkLFxuICAgIC8vIGNvbnN0cmFpbiBsYXlvdXQgYm91bmRzOyB7IHgxLCB5MSwgeDIsIHkyIH0gb3IgeyB4MSwgeTEsIHcsIGggfVxuICAgIGF2b2lkT3ZlcmxhcDogdHJ1ZSxcbiAgICAvLyBwcmV2ZW50cyBub2RlIG92ZXJsYXAsIG1heSBvdmVyZmxvdyBib3VuZGluZ0JveCBpZiBub3QgZW5vdWdoIHNwYWNlXG4gICAgbm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzOiBmYWxzZSxcbiAgICAvLyBFeGNsdWRlcyB0aGUgbGFiZWwgd2hlbiBjYWxjdWxhdGluZyBub2RlIGJvdW5kaW5nIGJveGVzIGZvciB0aGUgbGF5b3V0IGFsZ29yaXRobVxuICAgIGhlaWdodDogdW5kZWZpbmVkLFxuICAgIC8vIGhlaWdodCBvZiBsYXlvdXQgYXJlYSAob3ZlcnJpZGVzIGNvbnRhaW5lciBoZWlnaHQpXG4gICAgd2lkdGg6IHVuZGVmaW5lZCxcbiAgICAvLyB3aWR0aCBvZiBsYXlvdXQgYXJlYSAob3ZlcnJpZGVzIGNvbnRhaW5lciB3aWR0aClcbiAgICBzcGFjaW5nRmFjdG9yOiB1bmRlZmluZWQsXG4gICAgLy8gQXBwbGllcyBhIG11bHRpcGxpY2F0aXZlIGZhY3RvciAoPjApIHRvIGV4cGFuZCBvciBjb21wcmVzcyB0aGUgb3ZlcmFsbCBhcmVhIHRoYXQgdGhlIG5vZGVzIHRha2UgdXBcbiAgICBjb25jZW50cmljOiBmdW5jdGlvbiBjb25jZW50cmljKG5vZGUpIHtcbiAgICAgIC8vIHJldHVybnMgbnVtZXJpYyB2YWx1ZSBmb3IgZWFjaCBub2RlLCBwbGFjaW5nIGhpZ2hlciBub2RlcyBpbiBsZXZlbHMgdG93YXJkcyB0aGUgY2VudHJlXG4gICAgICByZXR1cm4gbm9kZS5kZWdyZWUoKTtcbiAgICB9LFxuICAgIGxldmVsV2lkdGg6IGZ1bmN0aW9uIGxldmVsV2lkdGgobm9kZXMpIHtcbiAgICAgIC8vIHRoZSB2YXJpYXRpb24gb2YgY29uY2VudHJpYyB2YWx1ZXMgaW4gZWFjaCBsZXZlbFxuICAgICAgcmV0dXJuIG5vZGVzLm1heERlZ3JlZSgpIC8gNDtcbiAgICB9LFxuICAgIGFuaW1hdGU6IGZhbHNlLFxuICAgIC8vIHdoZXRoZXIgdG8gdHJhbnNpdGlvbiB0aGUgbm9kZSBwb3NpdGlvbnNcbiAgICBhbmltYXRpb25EdXJhdGlvbjogNTAwLFxuICAgIC8vIGR1cmF0aW9uIG9mIGFuaW1hdGlvbiBpbiBtcyBpZiBlbmFibGVkXG4gICAgYW5pbWF0aW9uRWFzaW5nOiB1bmRlZmluZWQsXG4gICAgLy8gZWFzaW5nIG9mIGFuaW1hdGlvbiBpZiBlbmFibGVkXG4gICAgYW5pbWF0ZUZpbHRlcjogZnVuY3Rpb24gYW5pbWF0ZUZpbHRlcihub2RlLCBpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuICAgIC8vIGEgZnVuY3Rpb24gdGhhdCBkZXRlcm1pbmVzIHdoZXRoZXIgdGhlIG5vZGUgc2hvdWxkIGJlIGFuaW1hdGVkLiAgQWxsIG5vZGVzIGFuaW1hdGVkIGJ5IGRlZmF1bHQgb24gYW5pbWF0ZSBlbmFibGVkLiAgTm9uLWFuaW1hdGVkIG5vZGVzIGFyZSBwb3NpdGlvbmVkIGltbWVkaWF0ZWx5IHdoZW4gdGhlIGxheW91dCBzdGFydHNcbiAgICByZWFkeTogdW5kZWZpbmVkLFxuICAgIC8vIGNhbGxiYWNrIG9uIGxheW91dHJlYWR5XG4gICAgc3RvcDogdW5kZWZpbmVkLFxuICAgIC8vIGNhbGxiYWNrIG9uIGxheW91dHN0b3BcbiAgICB0cmFuc2Zvcm06IGZ1bmN0aW9uIHRyYW5zZm9ybShub2RlLCBwb3NpdGlvbikge1xuICAgICAgcmV0dXJuIHBvc2l0aW9uO1xuICAgIH0gLy8gdHJhbnNmb3JtIGEgZ2l2ZW4gbm9kZSBwb3NpdGlvbi4gVXNlZnVsIGZvciBjaGFuZ2luZyBmbG93IGRpcmVjdGlvbiBpbiBkaXNjcmV0ZSBsYXlvdXRzXG5cbiAgfTtcblxuICBmdW5jdGlvbiBDb25jZW50cmljTGF5b3V0KG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSBleHRlbmQoe30sIGRlZmF1bHRzJDUsIG9wdGlvbnMpO1xuICB9XG5cbiAgQ29uY2VudHJpY0xheW91dC5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBwYXJhbXMgPSB0aGlzLm9wdGlvbnM7XG4gICAgdmFyIG9wdGlvbnMgPSBwYXJhbXM7XG4gICAgdmFyIGNsb2Nrd2lzZSA9IG9wdGlvbnMuY291bnRlcmNsb2Nrd2lzZSAhPT0gdW5kZWZpbmVkID8gIW9wdGlvbnMuY291bnRlcmNsb2Nrd2lzZSA6IG9wdGlvbnMuY2xvY2t3aXNlO1xuICAgIHZhciBjeSA9IHBhcmFtcy5jeTtcbiAgICB2YXIgZWxlcyA9IG9wdGlvbnMuZWxlcztcbiAgICB2YXIgbm9kZXMgPSBlbGVzLm5vZGVzKCkubm90KCc6cGFyZW50Jyk7XG4gICAgdmFyIGJiID0gbWFrZUJvdW5kaW5nQm94KG9wdGlvbnMuYm91bmRpbmdCb3ggPyBvcHRpb25zLmJvdW5kaW5nQm94IDoge1xuICAgICAgeDE6IDAsXG4gICAgICB5MTogMCxcbiAgICAgIHc6IGN5LndpZHRoKCksXG4gICAgICBoOiBjeS5oZWlnaHQoKVxuICAgIH0pO1xuICAgIHZhciBjZW50ZXIgPSB7XG4gICAgICB4OiBiYi54MSArIGJiLncgLyAyLFxuICAgICAgeTogYmIueTEgKyBiYi5oIC8gMlxuICAgIH07XG4gICAgdmFyIG5vZGVWYWx1ZXMgPSBbXTsgLy8geyBub2RlLCB2YWx1ZSB9XG5cbiAgICB2YXIgbWF4Tm9kZVNpemUgPSAwO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIG5vZGUgPSBub2Rlc1tpXTtcbiAgICAgIHZhciB2YWx1ZSA9IHZvaWQgMDsgLy8gY2FsY3VsYXRlIHRoZSBub2RlIHZhbHVlXG5cbiAgICAgIHZhbHVlID0gb3B0aW9ucy5jb25jZW50cmljKG5vZGUpO1xuICAgICAgbm9kZVZhbHVlcy5wdXNoKHtcbiAgICAgICAgdmFsdWU6IHZhbHVlLFxuICAgICAgICBub2RlOiBub2RlXG4gICAgICB9KTsgLy8gZm9yIHN0eWxlIG1hcHBpbmdcblxuICAgICAgbm9kZS5fcHJpdmF0ZS5zY3JhdGNoLmNvbmNlbnRyaWMgPSB2YWx1ZTtcbiAgICB9IC8vIGluIGNhc2Ugd2UgdXNlZCB0aGUgYGNvbmNlbnRyaWNgIGluIHN0eWxlXG5cblxuICAgIG5vZGVzLnVwZGF0ZVN0eWxlKCk7IC8vIGNhbGN1bGF0ZSBtYXggc2l6ZSBub3cgYmFzZWQgb24gcG90ZW50aWFsbHkgdXBkYXRlZCBtYXBwZXJzXG5cbiAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgbm9kZXMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICB2YXIgX25vZGUgPSBub2Rlc1tfaV07XG5cbiAgICAgIHZhciBuYmIgPSBfbm9kZS5sYXlvdXREaW1lbnNpb25zKG9wdGlvbnMpO1xuXG4gICAgICBtYXhOb2RlU2l6ZSA9IE1hdGgubWF4KG1heE5vZGVTaXplLCBuYmIudywgbmJiLmgpO1xuICAgIH0gLy8gc29ydCBub2RlIHZhbHVlcyBpbiBkZXNjcmVhc2luZyBvcmRlclxuXG5cbiAgICBub2RlVmFsdWVzLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgIHJldHVybiBiLnZhbHVlIC0gYS52YWx1ZTtcbiAgICB9KTtcbiAgICB2YXIgbGV2ZWxXaWR0aCA9IG9wdGlvbnMubGV2ZWxXaWR0aChub2Rlcyk7IC8vIHB1dCB0aGUgdmFsdWVzIGludG8gbGV2ZWxzXG5cbiAgICB2YXIgbGV2ZWxzID0gW1tdXTtcbiAgICB2YXIgY3VycmVudExldmVsID0gbGV2ZWxzWzBdO1xuXG4gICAgZm9yICh2YXIgX2kyID0gMDsgX2kyIDwgbm9kZVZhbHVlcy5sZW5ndGg7IF9pMisrKSB7XG4gICAgICB2YXIgdmFsID0gbm9kZVZhbHVlc1tfaTJdO1xuXG4gICAgICBpZiAoY3VycmVudExldmVsLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdmFyIGRpZmYgPSBNYXRoLmFicyhjdXJyZW50TGV2ZWxbMF0udmFsdWUgLSB2YWwudmFsdWUpO1xuXG4gICAgICAgIGlmIChkaWZmID49IGxldmVsV2lkdGgpIHtcbiAgICAgICAgICBjdXJyZW50TGV2ZWwgPSBbXTtcbiAgICAgICAgICBsZXZlbHMucHVzaChjdXJyZW50TGV2ZWwpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGN1cnJlbnRMZXZlbC5wdXNoKHZhbCk7XG4gICAgfSAvLyBjcmVhdGUgcG9zaXRpb25zIGZyb20gbGV2ZWxzXG5cblxuICAgIHZhciBtaW5EaXN0ID0gbWF4Tm9kZVNpemUgKyBvcHRpb25zLm1pbk5vZGVTcGFjaW5nOyAvLyBtaW4gZGlzdCBiZXR3ZWVuIG5vZGVzXG5cbiAgICBpZiAoIW9wdGlvbnMuYXZvaWRPdmVybGFwKSB7XG4gICAgICAvLyB0aGVuIHN0cmljdGx5IGNvbnN0cmFpbiB0byBiYlxuICAgICAgdmFyIGZpcnN0THZsSGFzTXVsdGkgPSBsZXZlbHMubGVuZ3RoID4gMCAmJiBsZXZlbHNbMF0ubGVuZ3RoID4gMTtcbiAgICAgIHZhciBtYXhSID0gTWF0aC5taW4oYmIudywgYmIuaCkgLyAyIC0gbWluRGlzdDtcbiAgICAgIHZhciByU3RlcCA9IG1heFIgLyAobGV2ZWxzLmxlbmd0aCArIGZpcnN0THZsSGFzTXVsdGkgPyAxIDogMCk7XG4gICAgICBtaW5EaXN0ID0gTWF0aC5taW4obWluRGlzdCwgclN0ZXApO1xuICAgIH0gLy8gZmluZCB0aGUgbWV0cmljcyBmb3IgZWFjaCBsZXZlbFxuXG5cbiAgICB2YXIgciA9IDA7XG5cbiAgICBmb3IgKHZhciBfaTMgPSAwOyBfaTMgPCBsZXZlbHMubGVuZ3RoOyBfaTMrKykge1xuICAgICAgdmFyIGxldmVsID0gbGV2ZWxzW19pM107XG4gICAgICB2YXIgc3dlZXAgPSBvcHRpb25zLnN3ZWVwID09PSB1bmRlZmluZWQgPyAyICogTWF0aC5QSSAtIDIgKiBNYXRoLlBJIC8gbGV2ZWwubGVuZ3RoIDogb3B0aW9ucy5zd2VlcDtcbiAgICAgIHZhciBkVGhldGEgPSBsZXZlbC5kVGhldGEgPSBzd2VlcCAvIE1hdGgubWF4KDEsIGxldmVsLmxlbmd0aCAtIDEpOyAvLyBjYWxjdWxhdGUgdGhlIHJhZGl1c1xuXG4gICAgICBpZiAobGV2ZWwubGVuZ3RoID4gMSAmJiBvcHRpb25zLmF2b2lkT3ZlcmxhcCkge1xuICAgICAgICAvLyBidXQgb25seSBpZiBtb3JlIHRoYW4gb25lIG5vZGUgKGNhbid0IG92ZXJsYXApXG4gICAgICAgIHZhciBkY29zID0gTWF0aC5jb3MoZFRoZXRhKSAtIE1hdGguY29zKDApO1xuICAgICAgICB2YXIgZHNpbiA9IE1hdGguc2luKGRUaGV0YSkgLSBNYXRoLnNpbigwKTtcbiAgICAgICAgdmFyIHJNaW4gPSBNYXRoLnNxcnQobWluRGlzdCAqIG1pbkRpc3QgLyAoZGNvcyAqIGRjb3MgKyBkc2luICogZHNpbikpOyAvLyBzLnQuIG5vIG5vZGVzIG92ZXJsYXBwaW5nXG5cbiAgICAgICAgciA9IE1hdGgubWF4KHJNaW4sIHIpO1xuICAgICAgfVxuXG4gICAgICBsZXZlbC5yID0gcjtcbiAgICAgIHIgKz0gbWluRGlzdDtcbiAgICB9XG5cbiAgICBpZiAob3B0aW9ucy5lcXVpZGlzdGFudCkge1xuICAgICAgdmFyIHJEZWx0YU1heCA9IDA7XG4gICAgICB2YXIgX3IgPSAwO1xuXG4gICAgICBmb3IgKHZhciBfaTQgPSAwOyBfaTQgPCBsZXZlbHMubGVuZ3RoOyBfaTQrKykge1xuICAgICAgICB2YXIgX2xldmVsID0gbGV2ZWxzW19pNF07XG4gICAgICAgIHZhciByRGVsdGEgPSBfbGV2ZWwuciAtIF9yO1xuICAgICAgICByRGVsdGFNYXggPSBNYXRoLm1heChyRGVsdGFNYXgsIHJEZWx0YSk7XG4gICAgICB9XG5cbiAgICAgIF9yID0gMDtcblxuICAgICAgZm9yICh2YXIgX2k1ID0gMDsgX2k1IDwgbGV2ZWxzLmxlbmd0aDsgX2k1KyspIHtcbiAgICAgICAgdmFyIF9sZXZlbDIgPSBsZXZlbHNbX2k1XTtcblxuICAgICAgICBpZiAoX2k1ID09PSAwKSB7XG4gICAgICAgICAgX3IgPSBfbGV2ZWwyLnI7XG4gICAgICAgIH1cblxuICAgICAgICBfbGV2ZWwyLnIgPSBfcjtcbiAgICAgICAgX3IgKz0gckRlbHRhTWF4O1xuICAgICAgfVxuICAgIH0gLy8gY2FsY3VsYXRlIHRoZSBub2RlIHBvc2l0aW9uc1xuXG5cbiAgICB2YXIgcG9zID0ge307IC8vIGlkID0+IHBvc2l0aW9uXG5cbiAgICBmb3IgKHZhciBfaTYgPSAwOyBfaTYgPCBsZXZlbHMubGVuZ3RoOyBfaTYrKykge1xuICAgICAgdmFyIF9sZXZlbDMgPSBsZXZlbHNbX2k2XTtcbiAgICAgIHZhciBfZFRoZXRhID0gX2xldmVsMy5kVGhldGE7XG4gICAgICB2YXIgX3IyID0gX2xldmVsMy5yO1xuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IF9sZXZlbDMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdmFyIF92YWwgPSBfbGV2ZWwzW2pdO1xuICAgICAgICB2YXIgdGhldGEgPSBvcHRpb25zLnN0YXJ0QW5nbGUgKyAoY2xvY2t3aXNlID8gMSA6IC0xKSAqIF9kVGhldGEgKiBqO1xuICAgICAgICB2YXIgcCA9IHtcbiAgICAgICAgICB4OiBjZW50ZXIueCArIF9yMiAqIE1hdGguY29zKHRoZXRhKSxcbiAgICAgICAgICB5OiBjZW50ZXIueSArIF9yMiAqIE1hdGguc2luKHRoZXRhKVxuICAgICAgICB9O1xuICAgICAgICBwb3NbX3ZhbC5ub2RlLmlkKCldID0gcDtcbiAgICAgIH1cbiAgICB9IC8vIHBvc2l0aW9uIHRoZSBub2Rlc1xuXG5cbiAgICBlbGVzLm5vZGVzKCkubGF5b3V0UG9zaXRpb25zKHRoaXMsIG9wdGlvbnMsIGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgIHZhciBpZCA9IGVsZS5pZCgpO1xuICAgICAgcmV0dXJuIHBvc1tpZF07XG4gICAgfSk7XG4gICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gIH07XG5cbiAgLypcbiAgVGhlIENvU0UgbGF5b3V0IHdhcyB3cml0dGVuIGJ5IEdlcmFyZG8gSHVjay5cbiAgaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2luL2dlcmFyZG9odWNrL1xuXG4gIEJhc2VkIG9uIHRoZSBmb2xsb3dpbmcgYXJ0aWNsZTpcbiAgaHR0cDovL2RsLmFjbS5vcmcvY2l0YXRpb24uY2ZtP2lkPTE0OTgwNDdcblxuICBNb2RpZmljYXRpb25zIHRyYWNrZWQgb24gR2l0aHViLlxuICAqL1xuICB2YXIgREVCVUc7XG4gIC8qKlxuICAgKiBAYnJpZWYgOiAgZGVmYXVsdCBsYXlvdXQgb3B0aW9uc1xuICAgKi9cblxuICB2YXIgZGVmYXVsdHMkNCA9IHtcbiAgICAvLyBDYWxsZWQgb24gYGxheW91dHJlYWR5YFxuICAgIHJlYWR5OiBmdW5jdGlvbiByZWFkeSgpIHt9LFxuICAgIC8vIENhbGxlZCBvbiBgbGF5b3V0c3RvcGBcbiAgICBzdG9wOiBmdW5jdGlvbiBzdG9wKCkge30sXG4gICAgLy8gV2hldGhlciB0byBhbmltYXRlIHdoaWxlIHJ1bm5pbmcgdGhlIGxheW91dFxuICAgIC8vIHRydWUgOiBBbmltYXRlIGNvbnRpbnVvdXNseSBhcyB0aGUgbGF5b3V0IGlzIHJ1bm5pbmdcbiAgICAvLyBmYWxzZSA6IEp1c3Qgc2hvdyB0aGUgZW5kIHJlc3VsdFxuICAgIC8vICdlbmQnIDogQW5pbWF0ZSB3aXRoIHRoZSBlbmQgcmVzdWx0LCBmcm9tIHRoZSBpbml0aWFsIHBvc2l0aW9ucyB0byB0aGUgZW5kIHBvc2l0aW9uc1xuICAgIGFuaW1hdGU6IHRydWUsXG4gICAgLy8gRWFzaW5nIG9mIHRoZSBhbmltYXRpb24gZm9yIGFuaW1hdGU6J2VuZCdcbiAgICBhbmltYXRpb25FYXNpbmc6IHVuZGVmaW5lZCxcbiAgICAvLyBUaGUgZHVyYXRpb24gb2YgdGhlIGFuaW1hdGlvbiBmb3IgYW5pbWF0ZTonZW5kJ1xuICAgIGFuaW1hdGlvbkR1cmF0aW9uOiB1bmRlZmluZWQsXG4gICAgLy8gQSBmdW5jdGlvbiB0aGF0IGRldGVybWluZXMgd2hldGhlciB0aGUgbm9kZSBzaG91bGQgYmUgYW5pbWF0ZWRcbiAgICAvLyBBbGwgbm9kZXMgYW5pbWF0ZWQgYnkgZGVmYXVsdCBvbiBhbmltYXRlIGVuYWJsZWRcbiAgICAvLyBOb24tYW5pbWF0ZWQgbm9kZXMgYXJlIHBvc2l0aW9uZWQgaW1tZWRpYXRlbHkgd2hlbiB0aGUgbGF5b3V0IHN0YXJ0c1xuICAgIGFuaW1hdGVGaWx0ZXI6IGZ1bmN0aW9uIGFuaW1hdGVGaWx0ZXIobm9kZSwgaSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSxcbiAgICAvLyBUaGUgbGF5b3V0IGFuaW1hdGVzIG9ubHkgYWZ0ZXIgdGhpcyBtYW55IG1pbGxpc2Vjb25kcyBmb3IgYW5pbWF0ZTp0cnVlXG4gICAgLy8gKHByZXZlbnRzIGZsYXNoaW5nIG9uIGZhc3QgcnVucylcbiAgICBhbmltYXRpb25UaHJlc2hvbGQ6IDI1MCxcbiAgICAvLyBOdW1iZXIgb2YgaXRlcmF0aW9ucyBiZXR3ZWVuIGNvbnNlY3V0aXZlIHNjcmVlbiBwb3NpdGlvbnMgdXBkYXRlXG4gICAgcmVmcmVzaDogMjAsXG4gICAgLy8gV2hldGhlciB0byBmaXQgdGhlIG5ldHdvcmsgdmlldyBhZnRlciB3aGVuIGRvbmVcbiAgICBmaXQ6IHRydWUsXG4gICAgLy8gUGFkZGluZyBvbiBmaXRcbiAgICBwYWRkaW5nOiAzMCxcbiAgICAvLyBDb25zdHJhaW4gbGF5b3V0IGJvdW5kczsgeyB4MSwgeTEsIHgyLCB5MiB9IG9yIHsgeDEsIHkxLCB3LCBoIH1cbiAgICBib3VuZGluZ0JveDogdW5kZWZpbmVkLFxuICAgIC8vIEV4Y2x1ZGVzIHRoZSBsYWJlbCB3aGVuIGNhbGN1bGF0aW5nIG5vZGUgYm91bmRpbmcgYm94ZXMgZm9yIHRoZSBsYXlvdXQgYWxnb3JpdGhtXG4gICAgbm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzOiBmYWxzZSxcbiAgICAvLyBSYW5kb21pemUgdGhlIGluaXRpYWwgcG9zaXRpb25zIG9mIHRoZSBub2RlcyAodHJ1ZSkgb3IgdXNlIGV4aXN0aW5nIHBvc2l0aW9ucyAoZmFsc2UpXG4gICAgcmFuZG9taXplOiBmYWxzZSxcbiAgICAvLyBFeHRyYSBzcGFjaW5nIGJldHdlZW4gY29tcG9uZW50cyBpbiBub24tY29tcG91bmQgZ3JhcGhzXG4gICAgY29tcG9uZW50U3BhY2luZzogNDAsXG4gICAgLy8gTm9kZSByZXB1bHNpb24gKG5vbiBvdmVybGFwcGluZykgbXVsdGlwbGllclxuICAgIG5vZGVSZXB1bHNpb246IGZ1bmN0aW9uIG5vZGVSZXB1bHNpb24obm9kZSkge1xuICAgICAgcmV0dXJuIDIwNDg7XG4gICAgfSxcbiAgICAvLyBOb2RlIHJlcHVsc2lvbiAob3ZlcmxhcHBpbmcpIG11bHRpcGxpZXJcbiAgICBub2RlT3ZlcmxhcDogNCxcbiAgICAvLyBJZGVhbCBlZGdlIChub24gbmVzdGVkKSBsZW5ndGhcbiAgICBpZGVhbEVkZ2VMZW5ndGg6IGZ1bmN0aW9uIGlkZWFsRWRnZUxlbmd0aChlZGdlKSB7XG4gICAgICByZXR1cm4gMzI7XG4gICAgfSxcbiAgICAvLyBEaXZpc29yIHRvIGNvbXB1dGUgZWRnZSBmb3JjZXNcbiAgICBlZGdlRWxhc3RpY2l0eTogZnVuY3Rpb24gZWRnZUVsYXN0aWNpdHkoZWRnZSkge1xuICAgICAgcmV0dXJuIDMyO1xuICAgIH0sXG4gICAgLy8gTmVzdGluZyBmYWN0b3IgKG11bHRpcGxpZXIpIHRvIGNvbXB1dGUgaWRlYWwgZWRnZSBsZW5ndGggZm9yIG5lc3RlZCBlZGdlc1xuICAgIG5lc3RpbmdGYWN0b3I6IDEuMixcbiAgICAvLyBHcmF2aXR5IGZvcmNlIChjb25zdGFudClcbiAgICBncmF2aXR5OiAxLFxuICAgIC8vIE1heGltdW0gbnVtYmVyIG9mIGl0ZXJhdGlvbnMgdG8gcGVyZm9ybVxuICAgIG51bUl0ZXI6IDEwMDAsXG4gICAgLy8gSW5pdGlhbCB0ZW1wZXJhdHVyZSAobWF4aW11bSBub2RlIGRpc3BsYWNlbWVudClcbiAgICBpbml0aWFsVGVtcDogMTAwMCxcbiAgICAvLyBDb29saW5nIGZhY3RvciAoaG93IHRoZSB0ZW1wZXJhdHVyZSBpcyByZWR1Y2VkIGJldHdlZW4gY29uc2VjdXRpdmUgaXRlcmF0aW9uc1xuICAgIGNvb2xpbmdGYWN0b3I6IDAuOTksXG4gICAgLy8gTG93ZXIgdGVtcGVyYXR1cmUgdGhyZXNob2xkIChiZWxvdyB0aGlzIHBvaW50IHRoZSBsYXlvdXQgd2lsbCBlbmQpXG4gICAgbWluVGVtcDogMS4wXG4gIH07XG4gIC8qKlxuICAgKiBAYnJpZWYgICAgICAgOiBjb25zdHJ1Y3RvclxuICAgKiBAYXJnIG9wdGlvbnMgOiBvYmplY3QgY29udGFpbmluZyBsYXlvdXQgb3B0aW9uc1xuICAgKi9cblxuICBmdW5jdGlvbiBDb3NlTGF5b3V0KG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSBleHRlbmQoe30sIGRlZmF1bHRzJDQsIG9wdGlvbnMpO1xuICAgIHRoaXMub3B0aW9ucy5sYXlvdXQgPSB0aGlzO1xuICB9XG4gIC8qKlxuICAgKiBAYnJpZWYgOiBydW5zIHRoZSBsYXlvdXRcbiAgICovXG5cblxuICBDb3NlTGF5b3V0LnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG4gICAgdmFyIGN5ID0gb3B0aW9ucy5jeTtcbiAgICB2YXIgbGF5b3V0ID0gdGhpcztcbiAgICBsYXlvdXQuc3RvcHBlZCA9IGZhbHNlO1xuXG4gICAgaWYgKG9wdGlvbnMuYW5pbWF0ZSA9PT0gdHJ1ZSB8fCBvcHRpb25zLmFuaW1hdGUgPT09IGZhbHNlKSB7XG4gICAgICBsYXlvdXQuZW1pdCh7XG4gICAgICAgIHR5cGU6ICdsYXlvdXRzdGFydCcsXG4gICAgICAgIGxheW91dDogbGF5b3V0XG4gICAgICB9KTtcbiAgICB9IC8vIFNldCBERUJVRyAtIEdsb2JhbCB2YXJpYWJsZVxuXG5cbiAgICBpZiAodHJ1ZSA9PT0gb3B0aW9ucy5kZWJ1Zykge1xuICAgICAgREVCVUcgPSB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICBERUJVRyA9IGZhbHNlO1xuICAgIH0gLy8gSW5pdGlhbGl6ZSBsYXlvdXQgaW5mb1xuXG5cbiAgICB2YXIgbGF5b3V0SW5mbyA9IGNyZWF0ZUxheW91dEluZm8oY3ksIGxheW91dCwgb3B0aW9ucyk7IC8vIFNob3cgTGF5b3V0SW5mbyBjb250ZW50cyBpZiBkZWJ1Z2dpbmdcblxuICAgIGlmIChERUJVRykge1xuICAgICAgcHJpbnRMYXlvdXRJbmZvKGxheW91dEluZm8pO1xuICAgIH0gLy8gSWYgcmVxdWlyZWQsIHJhbmRvbWl6ZSBub2RlIHBvc2l0aW9uc1xuXG5cbiAgICBpZiAob3B0aW9ucy5yYW5kb21pemUpIHtcbiAgICAgIHJhbmRvbWl6ZVBvc2l0aW9ucyhsYXlvdXRJbmZvKTtcbiAgICB9XG5cbiAgICB2YXIgc3RhcnRUaW1lID0gcGVyZm9ybWFuY2VOb3coKTtcblxuICAgIHZhciByZWZyZXNoID0gZnVuY3Rpb24gcmVmcmVzaCgpIHtcbiAgICAgIHJlZnJlc2hQb3NpdGlvbnMobGF5b3V0SW5mbywgY3ksIG9wdGlvbnMpOyAvLyBGaXQgdGhlIGdyYXBoIGlmIG5lY2Vzc2FyeVxuXG4gICAgICBpZiAodHJ1ZSA9PT0gb3B0aW9ucy5maXQpIHtcbiAgICAgICAgY3kuZml0KG9wdGlvbnMucGFkZGluZyk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHZhciBtYWluTG9vcCA9IGZ1bmN0aW9uIG1haW5Mb29wKGkpIHtcbiAgICAgIGlmIChsYXlvdXQuc3RvcHBlZCB8fCBpID49IG9wdGlvbnMubnVtSXRlcikge1xuICAgICAgICAvLyBsb2dEZWJ1ZyhcIkxheW91dCBtYW51YWxseSBzdG9wcGVkLiBTdG9wcGluZyBjb21wdXRhdGlvbiBpbiBzdGVwIFwiICsgaSk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0gLy8gRG8gb25lIHN0ZXAgaW4gdGhlIHBoaXNpY2FsIHNpbXVsYXRpb25cblxuXG4gICAgICBzdGVwKGxheW91dEluZm8sIG9wdGlvbnMpOyAvLyBVcGRhdGUgdGVtcGVyYXR1cmVcblxuICAgICAgbGF5b3V0SW5mby50ZW1wZXJhdHVyZSA9IGxheW91dEluZm8udGVtcGVyYXR1cmUgKiBvcHRpb25zLmNvb2xpbmdGYWN0b3I7IC8vIGxvZ0RlYnVnKFwiTmV3IHRlbXBlcmF0dXJlOiBcIiArIGxheW91dEluZm8udGVtcGVyYXR1cmUpO1xuXG4gICAgICBpZiAobGF5b3V0SW5mby50ZW1wZXJhdHVyZSA8IG9wdGlvbnMubWluVGVtcCkge1xuICAgICAgICAvLyBsb2dEZWJ1ZyhcIlRlbXBlcmF0dXJlIGRyb3AgYmVsb3cgbWluaW11bSB0aHJlc2hvbGQuIFN0b3BwaW5nIGNvbXB1dGF0aW9uIGluIHN0ZXAgXCIgKyBpKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9O1xuXG4gICAgdmFyIGRvbmUgPSBmdW5jdGlvbiBkb25lKCkge1xuICAgICAgaWYgKG9wdGlvbnMuYW5pbWF0ZSA9PT0gdHJ1ZSB8fCBvcHRpb25zLmFuaW1hdGUgPT09IGZhbHNlKSB7XG4gICAgICAgIHJlZnJlc2goKTsgLy8gTGF5b3V0IGhhcyBmaW5pc2hlZFxuXG4gICAgICAgIGxheW91dC5vbmUoJ2xheW91dHN0b3AnLCBvcHRpb25zLnN0b3ApO1xuICAgICAgICBsYXlvdXQuZW1pdCh7XG4gICAgICAgICAgdHlwZTogJ2xheW91dHN0b3AnLFxuICAgICAgICAgIGxheW91dDogbGF5b3V0XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIG5vZGVzID0gb3B0aW9ucy5lbGVzLm5vZGVzKCk7XG4gICAgICAgIHZhciBnZXRTY2FsZWRQb3MgPSBnZXRTY2FsZUluQm91bmRzRm4obGF5b3V0SW5mbywgb3B0aW9ucywgbm9kZXMpO1xuICAgICAgICBub2Rlcy5sYXlvdXRQb3NpdGlvbnMobGF5b3V0LCBvcHRpb25zLCBnZXRTY2FsZWRQb3MpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgaSA9IDA7XG4gICAgdmFyIGxvb3BSZXQgPSB0cnVlO1xuXG4gICAgaWYgKG9wdGlvbnMuYW5pbWF0ZSA9PT0gdHJ1ZSkge1xuICAgICAgdmFyIGZyYW1lID0gZnVuY3Rpb24gZnJhbWUoKSB7XG4gICAgICAgIHZhciBmID0gMDtcblxuICAgICAgICB3aGlsZSAobG9vcFJldCAmJiBmIDwgb3B0aW9ucy5yZWZyZXNoKSB7XG4gICAgICAgICAgbG9vcFJldCA9IG1haW5Mb29wKGkpO1xuICAgICAgICAgIGkrKztcbiAgICAgICAgICBmKys7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWxvb3BSZXQpIHtcbiAgICAgICAgICAvLyBpdCdzIGRvbmVcbiAgICAgICAgICBzZXBhcmF0ZUNvbXBvbmVudHMobGF5b3V0SW5mbywgb3B0aW9ucyk7XG4gICAgICAgICAgZG9uZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhciBub3cgPSBwZXJmb3JtYW5jZU5vdygpO1xuXG4gICAgICAgICAgaWYgKG5vdyAtIHN0YXJ0VGltZSA+PSBvcHRpb25zLmFuaW1hdGlvblRocmVzaG9sZCkge1xuICAgICAgICAgICAgcmVmcmVzaCgpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZShmcmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIGZyYW1lKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHdoaWxlIChsb29wUmV0KSB7XG4gICAgICAgIGxvb3BSZXQgPSBtYWluTG9vcChpKTtcbiAgICAgICAgaSsrO1xuICAgICAgfVxuXG4gICAgICBzZXBhcmF0ZUNvbXBvbmVudHMobGF5b3V0SW5mbywgb3B0aW9ucyk7XG4gICAgICBkb25lKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gIH07XG4gIC8qKlxuICAgKiBAYnJpZWYgOiBjYWxsZWQgb24gY29udGludW91cyBsYXlvdXRzIHRvIHN0b3AgdGhlbSBiZWZvcmUgdGhleSBmaW5pc2hcbiAgICovXG5cblxuICBDb3NlTGF5b3V0LnByb3RvdHlwZS5zdG9wID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuc3RvcHBlZCA9IHRydWU7XG5cbiAgICBpZiAodGhpcy50aHJlYWQpIHtcbiAgICAgIHRoaXMudGhyZWFkLnN0b3AoKTtcbiAgICB9XG5cbiAgICB0aGlzLmVtaXQoJ2xheW91dHN0b3AnKTtcbiAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgfTtcblxuICBDb3NlTGF5b3V0LnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLnRocmVhZCkge1xuICAgICAgdGhpcy50aHJlYWQuc3RvcCgpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICB9O1xuICAvKipcbiAgICogQGJyaWVmICAgICA6IENyZWF0ZXMgYW4gb2JqZWN0IHdoaWNoIGlzIGNvbnRhaW5zIGFsbCB0aGUgZGF0YVxuICAgKiAgICAgICAgICAgICAgdXNlZCBpbiB0aGUgbGF5b3V0IHByb2Nlc3NcbiAgICogQGFyZyBjeSAgICA6IGN5dG9zY2FwZS5qcyBvYmplY3RcbiAgICogQHJldHVybiAgICA6IGxheW91dEluZm8gb2JqZWN0IGluaXRpYWxpemVkXG4gICAqL1xuXG5cbiAgdmFyIGNyZWF0ZUxheW91dEluZm8gPSBmdW5jdGlvbiBjcmVhdGVMYXlvdXRJbmZvKGN5LCBsYXlvdXQsIG9wdGlvbnMpIHtcbiAgICAvLyBTaG9ydGN1dFxuICAgIHZhciBlZGdlcyA9IG9wdGlvbnMuZWxlcy5lZGdlcygpO1xuICAgIHZhciBub2RlcyA9IG9wdGlvbnMuZWxlcy5ub2RlcygpO1xuICAgIHZhciBiYiA9IG1ha2VCb3VuZGluZ0JveChvcHRpb25zLmJvdW5kaW5nQm94ID8gb3B0aW9ucy5ib3VuZGluZ0JveCA6IHtcbiAgICAgIHgxOiAwLFxuICAgICAgeTE6IDAsXG4gICAgICB3OiBjeS53aWR0aCgpLFxuICAgICAgaDogY3kuaGVpZ2h0KClcbiAgICB9KTtcbiAgICB2YXIgbGF5b3V0SW5mbyA9IHtcbiAgICAgIGlzQ29tcG91bmQ6IGN5Lmhhc0NvbXBvdW5kTm9kZXMoKSxcbiAgICAgIGxheW91dE5vZGVzOiBbXSxcbiAgICAgIGlkVG9JbmRleDoge30sXG4gICAgICBub2RlU2l6ZTogbm9kZXMuc2l6ZSgpLFxuICAgICAgZ3JhcGhTZXQ6IFtdLFxuICAgICAgaW5kZXhUb0dyYXBoOiBbXSxcbiAgICAgIGxheW91dEVkZ2VzOiBbXSxcbiAgICAgIGVkZ2VTaXplOiBlZGdlcy5zaXplKCksXG4gICAgICB0ZW1wZXJhdHVyZTogb3B0aW9ucy5pbml0aWFsVGVtcCxcbiAgICAgIGNsaWVudFdpZHRoOiBiYi53LFxuICAgICAgY2xpZW50SGVpZ2h0OiBiYi5oLFxuICAgICAgYm91bmRpbmdCb3g6IGJiXG4gICAgfTtcbiAgICB2YXIgY29tcG9uZW50cyA9IG9wdGlvbnMuZWxlcy5jb21wb25lbnRzKCk7XG4gICAgdmFyIGlkMmNtcHRJZCA9IHt9O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb21wb25lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgY29tcG9uZW50ID0gY29tcG9uZW50c1tpXTtcblxuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBjb21wb25lbnQubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdmFyIG5vZGUgPSBjb21wb25lbnRbal07XG4gICAgICAgIGlkMmNtcHRJZFtub2RlLmlkKCldID0gaTtcbiAgICAgIH1cbiAgICB9IC8vIEl0ZXJhdGUgb3ZlciBhbGwgbm9kZXMsIGNyZWF0aW5nIGxheW91dCBub2Rlc1xuXG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxheW91dEluZm8ubm9kZVNpemU7IGkrKykge1xuICAgICAgdmFyIG4gPSBub2Rlc1tpXTtcbiAgICAgIHZhciBuYmIgPSBuLmxheW91dERpbWVuc2lvbnMob3B0aW9ucyk7XG4gICAgICB2YXIgdGVtcE5vZGUgPSB7fTtcbiAgICAgIHRlbXBOb2RlLmlzTG9ja2VkID0gbi5sb2NrZWQoKTtcbiAgICAgIHRlbXBOb2RlLmlkID0gbi5kYXRhKCdpZCcpO1xuICAgICAgdGVtcE5vZGUucGFyZW50SWQgPSBuLmRhdGEoJ3BhcmVudCcpO1xuICAgICAgdGVtcE5vZGUuY21wdElkID0gaWQyY21wdElkW24uaWQoKV07XG4gICAgICB0ZW1wTm9kZS5jaGlsZHJlbiA9IFtdO1xuICAgICAgdGVtcE5vZGUucG9zaXRpb25YID0gbi5wb3NpdGlvbigneCcpO1xuICAgICAgdGVtcE5vZGUucG9zaXRpb25ZID0gbi5wb3NpdGlvbigneScpO1xuICAgICAgdGVtcE5vZGUub2Zmc2V0WCA9IDA7XG4gICAgICB0ZW1wTm9kZS5vZmZzZXRZID0gMDtcbiAgICAgIHRlbXBOb2RlLmhlaWdodCA9IG5iYi53O1xuICAgICAgdGVtcE5vZGUud2lkdGggPSBuYmIuaDtcbiAgICAgIHRlbXBOb2RlLm1heFggPSB0ZW1wTm9kZS5wb3NpdGlvblggKyB0ZW1wTm9kZS53aWR0aCAvIDI7XG4gICAgICB0ZW1wTm9kZS5taW5YID0gdGVtcE5vZGUucG9zaXRpb25YIC0gdGVtcE5vZGUud2lkdGggLyAyO1xuICAgICAgdGVtcE5vZGUubWF4WSA9IHRlbXBOb2RlLnBvc2l0aW9uWSArIHRlbXBOb2RlLmhlaWdodCAvIDI7XG4gICAgICB0ZW1wTm9kZS5taW5ZID0gdGVtcE5vZGUucG9zaXRpb25ZIC0gdGVtcE5vZGUuaGVpZ2h0IC8gMjtcbiAgICAgIHRlbXBOb2RlLnBhZExlZnQgPSBwYXJzZUZsb2F0KG4uc3R5bGUoJ3BhZGRpbmcnKSk7XG4gICAgICB0ZW1wTm9kZS5wYWRSaWdodCA9IHBhcnNlRmxvYXQobi5zdHlsZSgncGFkZGluZycpKTtcbiAgICAgIHRlbXBOb2RlLnBhZFRvcCA9IHBhcnNlRmxvYXQobi5zdHlsZSgncGFkZGluZycpKTtcbiAgICAgIHRlbXBOb2RlLnBhZEJvdHRvbSA9IHBhcnNlRmxvYXQobi5zdHlsZSgncGFkZGluZycpKTsgLy8gZm9yY2VzXG5cbiAgICAgIHRlbXBOb2RlLm5vZGVSZXB1bHNpb24gPSBmbiQ2KG9wdGlvbnMubm9kZVJlcHVsc2lvbikgPyBvcHRpb25zLm5vZGVSZXB1bHNpb24obikgOiBvcHRpb25zLm5vZGVSZXB1bHNpb247IC8vIEFkZCBuZXcgbm9kZVxuXG4gICAgICBsYXlvdXRJbmZvLmxheW91dE5vZGVzLnB1c2godGVtcE5vZGUpOyAvLyBBZGQgZW50cnkgdG8gaWQtaW5kZXggbWFwXG5cbiAgICAgIGxheW91dEluZm8uaWRUb0luZGV4W3RlbXBOb2RlLmlkXSA9IGk7XG4gICAgfSAvLyBJbmxpbmUgaW1wbGVtZW50YXRpb24gb2YgYSBxdWV1ZSwgdXNlZCBmb3IgdHJhdmVyc2luZyB0aGUgZ3JhcGggaW4gQkZTIG9yZGVyXG5cblxuICAgIHZhciBxdWV1ZSA9IFtdO1xuICAgIHZhciBzdGFydCA9IDA7IC8vIFBvaW50cyB0byB0aGUgc3RhcnQgdGhlIHF1ZXVlXG5cbiAgICB2YXIgZW5kID0gLTE7IC8vIFBvaW50cyB0byB0aGUgZW5kIG9mIHRoZSBxdWV1ZVxuXG4gICAgdmFyIHRlbXBHcmFwaCA9IFtdOyAvLyBTZWNvbmQgcGFzcyB0byBhZGQgY2hpbGQgaW5mb3JtYXRpb24gYW5kXG4gICAgLy8gaW5pdGlhbGl6ZSBxdWV1ZSBmb3IgaGllcmFyY2hpY2FsIHRyYXZlcnNhbFxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsYXlvdXRJbmZvLm5vZGVTaXplOyBpKyspIHtcbiAgICAgIHZhciBuID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1tpXTtcbiAgICAgIHZhciBwX2lkID0gbi5wYXJlbnRJZDsgLy8gQ2hlY2sgaWYgbm9kZSBuIGhhcyBhIHBhcmVudCBub2RlXG5cbiAgICAgIGlmIChudWxsICE9IHBfaWQpIHtcbiAgICAgICAgLy8gQWRkIG5vZGUgSWQgdG8gcGFyZW50J3MgbGlzdCBvZiBjaGlsZHJlblxuICAgICAgICBsYXlvdXRJbmZvLmxheW91dE5vZGVzW2xheW91dEluZm8uaWRUb0luZGV4W3BfaWRdXS5jaGlsZHJlbi5wdXNoKG4uaWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gSWYgYSBub2RlIGRvZXNuJ3QgaGF2ZSBhIHBhcmVudCwgdGhlbiBpdCdzIGluIHRoZSByb290IGdyYXBoXG4gICAgICAgIHF1ZXVlWysrZW5kXSA9IG4uaWQ7XG4gICAgICAgIHRlbXBHcmFwaC5wdXNoKG4uaWQpO1xuICAgICAgfVxuICAgIH0gLy8gQWRkIHJvb3QgZ3JhcGggdG8gZ3JhcGhTZXRcblxuXG4gICAgbGF5b3V0SW5mby5ncmFwaFNldC5wdXNoKHRlbXBHcmFwaCk7IC8vIFRyYXZlcnNlIHRoZSBncmFwaCwgbGV2ZWwgYnkgbGV2ZWwsXG5cbiAgICB3aGlsZSAoc3RhcnQgPD0gZW5kKSB7XG4gICAgICAvLyBHZXQgdGhlIG5vZGUgdG8gdmlzaXQgYW5kIHJlbW92ZSBpdCBmcm9tIHF1ZXVlXG4gICAgICB2YXIgbm9kZV9pZCA9IHF1ZXVlW3N0YXJ0KytdO1xuICAgICAgdmFyIG5vZGVfaXggPSBsYXlvdXRJbmZvLmlkVG9JbmRleFtub2RlX2lkXTtcbiAgICAgIHZhciBub2RlID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1tub2RlX2l4XTtcbiAgICAgIHZhciBjaGlsZHJlbiA9IG5vZGUuY2hpbGRyZW47XG5cbiAgICAgIGlmIChjaGlsZHJlbi5sZW5ndGggPiAwKSB7XG4gICAgICAgIC8vIEFkZCBjaGlsZHJlbiBub2RlcyBhcyBhIG5ldyBncmFwaCB0byBncmFwaCBzZXRcbiAgICAgICAgbGF5b3V0SW5mby5ncmFwaFNldC5wdXNoKGNoaWxkcmVuKTsgLy8gQWRkIGNoaWxkcmVuIHRvIHF1ZSBxdWV1ZSB0byBiZSB2aXNpdGVkXG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHF1ZXVlWysrZW5kXSA9IGNoaWxkcmVuW2ldO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSAvLyBDcmVhdGUgaW5kZXhUb0dyYXBoIG1hcFxuXG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxheW91dEluZm8uZ3JhcGhTZXQubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBncmFwaCA9IGxheW91dEluZm8uZ3JhcGhTZXRbaV07XG5cbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgZ3JhcGgubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdmFyIGluZGV4ID0gbGF5b3V0SW5mby5pZFRvSW5kZXhbZ3JhcGhbal1dO1xuICAgICAgICBsYXlvdXRJbmZvLmluZGV4VG9HcmFwaFtpbmRleF0gPSBpO1xuICAgICAgfVxuICAgIH0gLy8gSXRlcmF0ZSBvdmVyIGFsbCBlZGdlcywgY3JlYXRpbmcgTGF5b3V0IEVkZ2VzXG5cblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGF5b3V0SW5mby5lZGdlU2l6ZTsgaSsrKSB7XG4gICAgICB2YXIgZSA9IGVkZ2VzW2ldO1xuICAgICAgdmFyIHRlbXBFZGdlID0ge307XG4gICAgICB0ZW1wRWRnZS5pZCA9IGUuZGF0YSgnaWQnKTtcbiAgICAgIHRlbXBFZGdlLnNvdXJjZUlkID0gZS5kYXRhKCdzb3VyY2UnKTtcbiAgICAgIHRlbXBFZGdlLnRhcmdldElkID0gZS5kYXRhKCd0YXJnZXQnKTsgLy8gQ29tcHV0ZSBpZGVhbCBsZW5ndGhcblxuICAgICAgdmFyIGlkZWFsTGVuZ3RoID0gZm4kNihvcHRpb25zLmlkZWFsRWRnZUxlbmd0aCkgPyBvcHRpb25zLmlkZWFsRWRnZUxlbmd0aChlKSA6IG9wdGlvbnMuaWRlYWxFZGdlTGVuZ3RoO1xuICAgICAgdmFyIGVsYXN0aWNpdHkgPSBmbiQ2KG9wdGlvbnMuZWRnZUVsYXN0aWNpdHkpID8gb3B0aW9ucy5lZGdlRWxhc3RpY2l0eShlKSA6IG9wdGlvbnMuZWRnZUVsYXN0aWNpdHk7IC8vIENoZWNrIGlmIGl0J3MgYW4gaW50ZXIgZ3JhcGggZWRnZVxuXG4gICAgICB2YXIgc291cmNlSXggPSBsYXlvdXRJbmZvLmlkVG9JbmRleFt0ZW1wRWRnZS5zb3VyY2VJZF07XG4gICAgICB2YXIgdGFyZ2V0SXggPSBsYXlvdXRJbmZvLmlkVG9JbmRleFt0ZW1wRWRnZS50YXJnZXRJZF07XG4gICAgICB2YXIgc291cmNlR3JhcGggPSBsYXlvdXRJbmZvLmluZGV4VG9HcmFwaFtzb3VyY2VJeF07XG4gICAgICB2YXIgdGFyZ2V0R3JhcGggPSBsYXlvdXRJbmZvLmluZGV4VG9HcmFwaFt0YXJnZXRJeF07XG5cbiAgICAgIGlmIChzb3VyY2VHcmFwaCAhPSB0YXJnZXRHcmFwaCkge1xuICAgICAgICAvLyBGaW5kIGxvd2VzdCBjb21tb24gZ3JhcGggYW5jZXN0b3JcbiAgICAgICAgdmFyIGxjYSA9IGZpbmRMQ0EodGVtcEVkZ2Uuc291cmNlSWQsIHRlbXBFZGdlLnRhcmdldElkLCBsYXlvdXRJbmZvKTsgLy8gQ29tcHV0ZSBzdW0gb2Ygbm9kZSBkZXB0aHMsIHJlbGF0aXZlIHRvIGxjYSBncmFwaFxuXG4gICAgICAgIHZhciBsY2FHcmFwaCA9IGxheW91dEluZm8uZ3JhcGhTZXRbbGNhXTtcbiAgICAgICAgdmFyIGRlcHRoID0gMDsgLy8gU291cmNlIGRlcHRoXG5cbiAgICAgICAgdmFyIHRlbXBOb2RlID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1tzb3VyY2VJeF07XG5cbiAgICAgICAgd2hpbGUgKC0xID09PSBsY2FHcmFwaC5pbmRleE9mKHRlbXBOb2RlLmlkKSkge1xuICAgICAgICAgIHRlbXBOb2RlID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1tsYXlvdXRJbmZvLmlkVG9JbmRleFt0ZW1wTm9kZS5wYXJlbnRJZF1dO1xuICAgICAgICAgIGRlcHRoKys7XG4gICAgICAgIH0gLy8gVGFyZ2V0IGRlcHRoXG5cblxuICAgICAgICB0ZW1wTm9kZSA9IGxheW91dEluZm8ubGF5b3V0Tm9kZXNbdGFyZ2V0SXhdO1xuXG4gICAgICAgIHdoaWxlICgtMSA9PT0gbGNhR3JhcGguaW5kZXhPZih0ZW1wTm9kZS5pZCkpIHtcbiAgICAgICAgICB0ZW1wTm9kZSA9IGxheW91dEluZm8ubGF5b3V0Tm9kZXNbbGF5b3V0SW5mby5pZFRvSW5kZXhbdGVtcE5vZGUucGFyZW50SWRdXTtcbiAgICAgICAgICBkZXB0aCsrO1xuICAgICAgICB9IC8vIGxvZ0RlYnVnKCdMQ0Egb2Ygbm9kZXMgJyArIHRlbXBFZGdlLnNvdXJjZUlkICsgJyBhbmQgJyArIHRlbXBFZGdlLnRhcmdldElkICtcbiAgICAgICAgLy8gIFwiLiBJbmRleDogXCIgKyBsY2EgKyBcIiBDb250ZW50czogXCIgKyBsY2FHcmFwaC50b1N0cmluZygpICtcbiAgICAgICAgLy8gIFwiLiBEZXB0aDogXCIgKyBkZXB0aCk7XG4gICAgICAgIC8vIFVwZGF0ZSBpZGVhbExlbmd0aFxuXG5cbiAgICAgICAgaWRlYWxMZW5ndGggKj0gZGVwdGggKiBvcHRpb25zLm5lc3RpbmdGYWN0b3I7XG4gICAgICB9XG5cbiAgICAgIHRlbXBFZGdlLmlkZWFsTGVuZ3RoID0gaWRlYWxMZW5ndGg7XG4gICAgICB0ZW1wRWRnZS5lbGFzdGljaXR5ID0gZWxhc3RpY2l0eTtcbiAgICAgIGxheW91dEluZm8ubGF5b3V0RWRnZXMucHVzaCh0ZW1wRWRnZSk7XG4gICAgfSAvLyBGaW5hbGx5LCByZXR1cm4gbGF5b3V0SW5mbyBvYmplY3RcblxuXG4gICAgcmV0dXJuIGxheW91dEluZm87XG4gIH07XG4gIC8qKlxuICAgKiBAYnJpZWYgOiBUaGlzIGZ1bmN0aW9uIGZpbmRzIHRoZSBpbmRleCBvZiB0aGUgbG93ZXN0IGNvbW1vblxuICAgKiAgICAgICAgICBncmFwaCBhbmNlc3RvciBiZXR3ZWVuIDIgbm9kZXMgaW4gdGhlIHN1YnRyZWVcbiAgICogICAgICAgICAgKGZyb20gdGhlIGdyYXBoIGhpZXJhcmNoeSBpbmR1Y2VkIHRyZWUpIHdob3NlXG4gICAqICAgICAgICAgIHJvb3QgaXMgZ3JhcGhJeFxuICAgKlxuICAgKiBAYXJnIG5vZGUxOiBub2RlMSdzIElEXG4gICAqIEBhcmcgbm9kZTI6IG5vZGUyJ3MgSURcbiAgICogQGFyZyBsYXlvdXRJbmZvOiBsYXlvdXRJbmZvIG9iamVjdFxuICAgKlxuICAgKi9cblxuXG4gIHZhciBmaW5kTENBID0gZnVuY3Rpb24gZmluZExDQShub2RlMSwgbm9kZTIsIGxheW91dEluZm8pIHtcbiAgICAvLyBGaW5kIHRoZWlyIGNvbW1vbiBhbmNlc3Rlciwgc3RhcnRpbmcgZnJvbSB0aGUgcm9vdCBncmFwaFxuICAgIHZhciByZXMgPSBmaW5kTENBX2F1eChub2RlMSwgbm9kZTIsIDAsIGxheW91dEluZm8pO1xuXG4gICAgaWYgKDIgPiByZXMuY291bnQpIHtcbiAgICAgIC8vIElmIGF1eCBmdW5jdGlvbiBjb3VsZG4ndCBmaW5kIHRoZSBjb21tb24gYW5jZXN0ZXIsXG4gICAgICAvLyB0aGVuIGl0IGlzIHRoZSByb290IGdyYXBoXG4gICAgICByZXR1cm4gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHJlcy5ncmFwaDtcbiAgICB9XG4gIH07XG4gIC8qKlxuICAgKiBAYnJpZWYgICAgICAgICAgOiBBdXhpbGlhcnkgZnVuY3Rpb24gdXNlZCBmb3IgTENBIGNvbXB1dGF0aW9uXG4gICAqXG4gICAqIEBhcmcgbm9kZTEgICAgICA6IG5vZGUxJ3MgSURcbiAgICogQGFyZyBub2RlMiAgICAgIDogbm9kZTIncyBJRFxuICAgKiBAYXJnIGdyYXBoSXggICAgOiBzdWJncmFwaCBpbmRleFxuICAgKiBAYXJnIGxheW91dEluZm8gOiBsYXlvdXRJbmZvIG9iamVjdFxuICAgKlxuICAgKiBAcmV0dXJuICAgICAgICAgOiBvYmplY3Qgb2YgdGhlIGZvcm0ge2NvdW50OiBYLCBncmFwaDogWX0sIHdoZXJlOlxuICAgKiAgICAgICAgICAgICAgICAgICBYIGlzIHRoZSBudW1iZXIgb2YgYW5jZXN0b3JzIChtYXg6IDIpIGZvdW5kIGluXG4gICAqICAgICAgICAgICAgICAgICAgIGdyYXBoSXggKGFuZCBpdCdzIHN1YmdyYXBocyksXG4gICAqICAgICAgICAgICAgICAgICAgIFkgaXMgdGhlIGdyYXBoIGluZGV4IG9mIHRoZSBsb3dlc3QgZ3JhcGggY29udGFpbmluZ1xuICAgKiAgICAgICAgICAgICAgICAgICBhbGwgWCBub2Rlc1xuICAgKi9cblxuXG4gIHZhciBmaW5kTENBX2F1eCA9IGZ1bmN0aW9uIGZpbmRMQ0FfYXV4KG5vZGUxLCBub2RlMiwgZ3JhcGhJeCwgbGF5b3V0SW5mbykge1xuICAgIHZhciBncmFwaCA9IGxheW91dEluZm8uZ3JhcGhTZXRbZ3JhcGhJeF07IC8vIElmIGJvdGggbm9kZXMgYmVsb25ncyB0byBncmFwaEl4XG5cbiAgICBpZiAoLTEgPCBncmFwaC5pbmRleE9mKG5vZGUxKSAmJiAtMSA8IGdyYXBoLmluZGV4T2Yobm9kZTIpKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb3VudDogMixcbiAgICAgICAgZ3JhcGg6IGdyYXBoSXhcbiAgICAgIH07XG4gICAgfSAvLyBNYWtlIHJlY3Vyc2l2ZSBjYWxscyBmb3IgYWxsIHN1YmdyYXBoc1xuXG5cbiAgICB2YXIgYyA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGdyYXBoLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgbm9kZUlkID0gZ3JhcGhbaV07XG4gICAgICB2YXIgbm9kZUl4ID0gbGF5b3V0SW5mby5pZFRvSW5kZXhbbm9kZUlkXTtcbiAgICAgIHZhciBjaGlsZHJlbiA9IGxheW91dEluZm8ubGF5b3V0Tm9kZXNbbm9kZUl4XS5jaGlsZHJlbjsgLy8gSWYgdGhlIG5vZGUgaGFzIG5vIGNoaWxkLCBza2lwIGl0XG5cbiAgICAgIGlmICgwID09PSBjaGlsZHJlbi5sZW5ndGgpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIHZhciBjaGlsZEdyYXBoSXggPSBsYXlvdXRJbmZvLmluZGV4VG9HcmFwaFtsYXlvdXRJbmZvLmlkVG9JbmRleFtjaGlsZHJlblswXV1dO1xuICAgICAgdmFyIHJlc3VsdCA9IGZpbmRMQ0FfYXV4KG5vZGUxLCBub2RlMiwgY2hpbGRHcmFwaEl4LCBsYXlvdXRJbmZvKTtcblxuICAgICAgaWYgKDAgPT09IHJlc3VsdC5jb3VudCkge1xuICAgICAgICAvLyBOZWl0aGVyIG5vZGUxIG5vciBub2RlMiBhcmUgcHJlc2VudCBpbiB0aGlzIHN1YmdyYXBoXG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfSBlbHNlIGlmICgxID09PSByZXN1bHQuY291bnQpIHtcbiAgICAgICAgLy8gT25lIG9mIChub2RlMSwgbm9kZTIpIGlzIHByZXNlbnQgaW4gdGhpcyBzdWJncmFwaFxuICAgICAgICBjKys7XG5cbiAgICAgICAgaWYgKDIgPT09IGMpIHtcbiAgICAgICAgICAvLyBXZSd2ZSBhbHJlYWR5IGZvdW5kIGJvdGggbm9kZXMsIG5vIG5lZWQgdG8ga2VlcCBzZWFyY2hpbmdcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQm90aCBub2RlcyBhcmUgcHJlc2VudCBpbiB0aGlzIHN1YmdyYXBoXG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNvdW50OiBjLFxuICAgICAgZ3JhcGg6IGdyYXBoSXhcbiAgICB9O1xuICB9O1xuICAvKipcbiAgICogQGJyaWVmOiBwcmludHNMYXlvdXRJbmZvIGludG8ganMgY29uc29sZVxuICAgKiAgICAgICAgIE9ubHkgdXNlZCBmb3IgZGViYnVnaW5nXG4gICAqL1xuXG5cbnZhciBwcmludExheW91dEluZm87IFxuICAvKipcbiAgICogQGJyaWVmIDogUmFuZG9taXplcyB0aGUgcG9zaXRpb24gb2YgYWxsIG5vZGVzXG4gICAqL1xuXG5cbiAgdmFyIHJhbmRvbWl6ZVBvc2l0aW9ucyA9IGZ1bmN0aW9uIHJhbmRvbWl6ZVBvc2l0aW9ucyhsYXlvdXRJbmZvLCBjeSkge1xuICAgIHZhciB3aWR0aCA9IGxheW91dEluZm8uY2xpZW50V2lkdGg7XG4gICAgdmFyIGhlaWdodCA9IGxheW91dEluZm8uY2xpZW50SGVpZ2h0O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsYXlvdXRJbmZvLm5vZGVTaXplOyBpKyspIHtcbiAgICAgIHZhciBuID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1tpXTsgLy8gTm8gbmVlZCB0byByYW5kb21pemUgY29tcG91bmQgbm9kZXMgb3IgbG9ja2VkIG5vZGVzXG5cbiAgICAgIGlmICgwID09PSBuLmNoaWxkcmVuLmxlbmd0aCAmJiAhbi5pc0xvY2tlZCkge1xuICAgICAgICBuLnBvc2l0aW9uWCA9IE1hdGgucmFuZG9tKCkgKiB3aWR0aDtcbiAgICAgICAgbi5wb3NpdGlvblkgPSBNYXRoLnJhbmRvbSgpICogaGVpZ2h0O1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICB2YXIgZ2V0U2NhbGVJbkJvdW5kc0ZuID0gZnVuY3Rpb24gZ2V0U2NhbGVJbkJvdW5kc0ZuKGxheW91dEluZm8sIG9wdGlvbnMsIG5vZGVzKSB7XG4gICAgdmFyIGJiID0gbGF5b3V0SW5mby5ib3VuZGluZ0JveDtcbiAgICB2YXIgY29zZUJCID0ge1xuICAgICAgeDE6IEluZmluaXR5LFxuICAgICAgeDI6IC1JbmZpbml0eSxcbiAgICAgIHkxOiBJbmZpbml0eSxcbiAgICAgIHkyOiAtSW5maW5pdHlcbiAgICB9O1xuXG4gICAgaWYgKG9wdGlvbnMuYm91bmRpbmdCb3gpIHtcbiAgICAgIG5vZGVzLmZvckVhY2goZnVuY3Rpb24gKG5vZGUpIHtcbiAgICAgICAgdmFyIGxub2RlID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1tsYXlvdXRJbmZvLmlkVG9JbmRleFtub2RlLmRhdGEoJ2lkJyldXTtcbiAgICAgICAgY29zZUJCLngxID0gTWF0aC5taW4oY29zZUJCLngxLCBsbm9kZS5wb3NpdGlvblgpO1xuICAgICAgICBjb3NlQkIueDIgPSBNYXRoLm1heChjb3NlQkIueDIsIGxub2RlLnBvc2l0aW9uWCk7XG4gICAgICAgIGNvc2VCQi55MSA9IE1hdGgubWluKGNvc2VCQi55MSwgbG5vZGUucG9zaXRpb25ZKTtcbiAgICAgICAgY29zZUJCLnkyID0gTWF0aC5tYXgoY29zZUJCLnkyLCBsbm9kZS5wb3NpdGlvblkpO1xuICAgICAgfSk7XG4gICAgICBjb3NlQkIudyA9IGNvc2VCQi54MiAtIGNvc2VCQi54MTtcbiAgICAgIGNvc2VCQi5oID0gY29zZUJCLnkyIC0gY29zZUJCLnkxO1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbiAoZWxlLCBpKSB7XG4gICAgICB2YXIgbG5vZGUgPSBsYXlvdXRJbmZvLmxheW91dE5vZGVzW2xheW91dEluZm8uaWRUb0luZGV4W2VsZS5kYXRhKCdpZCcpXV07XG5cbiAgICAgIGlmIChvcHRpb25zLmJvdW5kaW5nQm94KSB7XG4gICAgICAgIC8vIHRoZW4gYWRkIGV4dHJhIGJvdW5kaW5nIGJveCBjb25zdHJhaW50XG4gICAgICAgIHZhciBwY3RYID0gKGxub2RlLnBvc2l0aW9uWCAtIGNvc2VCQi54MSkgLyBjb3NlQkIudztcbiAgICAgICAgdmFyIHBjdFkgPSAobG5vZGUucG9zaXRpb25ZIC0gY29zZUJCLnkxKSAvIGNvc2VCQi5oO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHg6IGJiLngxICsgcGN0WCAqIGJiLncsXG4gICAgICAgICAgeTogYmIueTEgKyBwY3RZICogYmIuaFxuICAgICAgICB9O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB4OiBsbm9kZS5wb3NpdGlvblgsXG4gICAgICAgICAgeTogbG5vZGUucG9zaXRpb25ZXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfTtcbiAgfTtcbiAgLyoqXG4gICAqIEBicmllZiAgICAgICAgICA6IFVwZGF0ZXMgdGhlIHBvc2l0aW9ucyBvZiBub2RlcyBpbiB0aGUgbmV0d29ya1xuICAgKiBAYXJnIGxheW91dEluZm8gOiBMYXlvdXRJbmZvIG9iamVjdFxuICAgKiBAYXJnIGN5ICAgICAgICAgOiBDeXRvc2NhcGUgb2JqZWN0XG4gICAqIEBhcmcgb3B0aW9ucyAgICA6IExheW91dCBvcHRpb25zXG4gICAqL1xuXG5cbiAgdmFyIHJlZnJlc2hQb3NpdGlvbnMgPSBmdW5jdGlvbiByZWZyZXNoUG9zaXRpb25zKGxheW91dEluZm8sIGN5LCBvcHRpb25zKSB7XG4gICAgLy8gdmFyIHMgPSAnUmVmcmVzaGluZyBwb3NpdGlvbnMnO1xuICAgIC8vIGxvZ0RlYnVnKHMpO1xuICAgIHZhciBsYXlvdXQgPSBvcHRpb25zLmxheW91dDtcbiAgICB2YXIgbm9kZXMgPSBvcHRpb25zLmVsZXMubm9kZXMoKTtcbiAgICB2YXIgZ2V0U2NhbGVkUG9zID0gZ2V0U2NhbGVJbkJvdW5kc0ZuKGxheW91dEluZm8sIG9wdGlvbnMsIG5vZGVzKTtcbiAgICBub2Rlcy5wb3NpdGlvbnMoZ2V0U2NhbGVkUG9zKTsgLy8gVHJpZ2dlciBsYXlvdXRSZWFkeSBvbmx5IG9uIGZpcnN0IGNhbGxcblxuICAgIGlmICh0cnVlICE9PSBsYXlvdXRJbmZvLnJlYWR5KSB7XG4gICAgICAvLyBzID0gJ1RyaWdnZXJpbmcgbGF5b3V0cmVhZHknO1xuICAgICAgLy8gbG9nRGVidWcocyk7XG4gICAgICBsYXlvdXRJbmZvLnJlYWR5ID0gdHJ1ZTtcbiAgICAgIGxheW91dC5vbmUoJ2xheW91dHJlYWR5Jywgb3B0aW9ucy5yZWFkeSk7XG4gICAgICBsYXlvdXQuZW1pdCh7XG4gICAgICAgIHR5cGU6ICdsYXlvdXRyZWFkeScsXG4gICAgICAgIGxheW91dDogdGhpc1xuICAgICAgfSk7XG4gICAgfVxuICB9O1xuICAvKipcbiAgICogQGJyaWVmIDogTG9ncyBhIGRlYnVnIG1lc3NhZ2UgaW4gSlMgY29uc29sZSwgaWYgREVCVUcgaXMgT05cbiAgICovXG4gIC8vIHZhciBsb2dEZWJ1ZyA9IGZ1bmN0aW9uKHRleHQpIHtcbiAgLy8gICBpZiAoREVCVUcpIHtcbiAgLy8gICAgIGNvbnNvbGUuZGVidWcodGV4dCk7XG4gIC8vICAgfVxuICAvLyB9O1xuXG4gIC8qKlxuICAgKiBAYnJpZWYgICAgICAgICAgOiBQZXJmb3JtcyBvbmUgaXRlcmF0aW9uIG9mIHRoZSBwaHlzaWNhbCBzaW11bGF0aW9uXG4gICAqIEBhcmcgbGF5b3V0SW5mbyA6IExheW91dEluZm8gb2JqZWN0IGFscmVhZHkgaW5pdGlhbGl6ZWRcbiAgICogQGFyZyBjeSAgICAgICAgIDogQ3l0b3NjYXBlIG9iamVjdFxuICAgKiBAYXJnIG9wdGlvbnMgICAgOiBMYXlvdXQgb3B0aW9uc1xuICAgKi9cblxuXG4gIHZhciBzdGVwID0gZnVuY3Rpb24gc3RlcChsYXlvdXRJbmZvLCBvcHRpb25zLCBfc3RlcCkge1xuICAgIC8vIHZhciBzID0gXCJcXG5cXG4jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjXCI7XG4gICAgLy8gcyArPSBcIlxcblNURVA6IFwiICsgc3RlcDtcbiAgICAvLyBzICs9IFwiXFxuIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI1xcblwiO1xuICAgIC8vIGxvZ0RlYnVnKHMpO1xuICAgIC8vIENhbGN1bGF0ZSBub2RlIHJlcHVsc2lvbnNcbiAgICBjYWxjdWxhdGVOb2RlRm9yY2VzKGxheW91dEluZm8sIG9wdGlvbnMpOyAvLyBDYWxjdWxhdGUgZWRnZSBmb3JjZXNcblxuICAgIGNhbGN1bGF0ZUVkZ2VGb3JjZXMobGF5b3V0SW5mbyk7IC8vIENhbGN1bGF0ZSBncmF2aXR5IGZvcmNlc1xuXG4gICAgY2FsY3VsYXRlR3Jhdml0eUZvcmNlcyhsYXlvdXRJbmZvLCBvcHRpb25zKTsgLy8gUHJvcGFnYXRlIGZvcmNlcyBmcm9tIHBhcmVudCB0byBjaGlsZFxuXG4gICAgcHJvcGFnYXRlRm9yY2VzKGxheW91dEluZm8pOyAvLyBVcGRhdGUgcG9zaXRpb25zIGJhc2VkIG9uIGNhbGN1bGF0ZWQgZm9yY2VzXG5cbiAgICB1cGRhdGVQb3NpdGlvbnMobGF5b3V0SW5mbyk7XG4gIH07XG4gIC8qKlxuICAgKiBAYnJpZWYgOiBDb21wdXRlcyB0aGUgbm9kZSByZXB1bHNpb24gZm9yY2VzXG4gICAqL1xuXG5cbiAgdmFyIGNhbGN1bGF0ZU5vZGVGb3JjZXMgPSBmdW5jdGlvbiBjYWxjdWxhdGVOb2RlRm9yY2VzKGxheW91dEluZm8sIG9wdGlvbnMpIHtcbiAgICAvLyBHbyB0aHJvdWdoIGVhY2ggb2YgdGhlIGdyYXBocyBpbiBncmFwaFNldFxuICAgIC8vIE5vZGVzIG9ubHkgcmVwZWwgZWFjaCBvdGhlciBpZiB0aGV5IGJlbG9uZyB0byB0aGUgc2FtZSBncmFwaFxuICAgIC8vIHZhciBzID0gJ2NhbGN1bGF0ZU5vZGVGb3JjZXMnO1xuICAgIC8vIGxvZ0RlYnVnKHMpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGF5b3V0SW5mby5ncmFwaFNldC5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGdyYXBoID0gbGF5b3V0SW5mby5ncmFwaFNldFtpXTtcbiAgICAgIHZhciBudW1Ob2RlcyA9IGdyYXBoLmxlbmd0aDsgLy8gcyA9IFwiU2V0OiBcIiArIGdyYXBoLnRvU3RyaW5nKCk7XG4gICAgICAvLyBsb2dEZWJ1ZyhzKTtcbiAgICAgIC8vIE5vdyBnZXQgYWxsIHRoZSBwYWlycyBvZiBub2Rlc1xuICAgICAgLy8gT25seSBnZXQgZWFjaCBwYWlyIG9uY2UsIChBLCBCKSA9IChCLCBBKVxuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IG51bU5vZGVzOyBqKyspIHtcbiAgICAgICAgdmFyIG5vZGUxID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1tsYXlvdXRJbmZvLmlkVG9JbmRleFtncmFwaFtqXV1dO1xuXG4gICAgICAgIGZvciAodmFyIGsgPSBqICsgMTsgayA8IG51bU5vZGVzOyBrKyspIHtcbiAgICAgICAgICB2YXIgbm9kZTIgPSBsYXlvdXRJbmZvLmxheW91dE5vZGVzW2xheW91dEluZm8uaWRUb0luZGV4W2dyYXBoW2tdXV07XG4gICAgICAgICAgbm9kZVJlcHVsc2lvbihub2RlMSwgbm9kZTIsIGxheW91dEluZm8sIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIHZhciByYW5kb21EaXN0YW5jZSA9IGZ1bmN0aW9uIHJhbmRvbURpc3RhbmNlKG1heCkge1xuICAgIHJldHVybiAtbWF4ICsgMiAqIG1heCAqIE1hdGgucmFuZG9tKCk7XG4gIH07XG4gIC8qKlxuICAgKiBAYnJpZWYgOiBDb21wdXRlIHRoZSBub2RlIHJlcHVsc2lvbiBmb3JjZXMgYmV0d2VlbiBhIHBhaXIgb2Ygbm9kZXNcbiAgICovXG5cblxuICB2YXIgbm9kZVJlcHVsc2lvbiA9IGZ1bmN0aW9uIG5vZGVSZXB1bHNpb24obm9kZTEsIG5vZGUyLCBsYXlvdXRJbmZvLCBvcHRpb25zKSB7XG4gICAgLy8gdmFyIHMgPSBcIk5vZGUgcmVwdWxzaW9uLiBOb2RlMTogXCIgKyBub2RlMS5pZCArIFwiIE5vZGUyOiBcIiArIG5vZGUyLmlkO1xuICAgIHZhciBjbXB0SWQxID0gbm9kZTEuY21wdElkO1xuICAgIHZhciBjbXB0SWQyID0gbm9kZTIuY21wdElkO1xuXG4gICAgaWYgKGNtcHRJZDEgIT09IGNtcHRJZDIgJiYgIWxheW91dEluZm8uaXNDb21wb3VuZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH0gLy8gR2V0IGRpcmVjdGlvbiBvZiBsaW5lIGNvbm5lY3RpbmcgYm90aCBub2RlIGNlbnRlcnNcblxuXG4gICAgdmFyIGRpcmVjdGlvblggPSBub2RlMi5wb3NpdGlvblggLSBub2RlMS5wb3NpdGlvblg7XG4gICAgdmFyIGRpcmVjdGlvblkgPSBub2RlMi5wb3NpdGlvblkgLSBub2RlMS5wb3NpdGlvblk7XG4gICAgdmFyIG1heFJhbmREaXN0ID0gMTsgLy8gcyArPSBcIlxcbmRpcmVjdGlvblg6IFwiICsgZGlyZWN0aW9uWCArIFwiLCBkaXJlY3Rpb25ZOiBcIiArIGRpcmVjdGlvblk7XG4gICAgLy8gSWYgYm90aCBjZW50ZXJzIGFyZSB0aGUgc2FtZSwgYXBwbHkgYSByYW5kb20gZm9yY2VcblxuICAgIGlmICgwID09PSBkaXJlY3Rpb25YICYmIDAgPT09IGRpcmVjdGlvblkpIHtcbiAgICAgIGRpcmVjdGlvblggPSByYW5kb21EaXN0YW5jZShtYXhSYW5kRGlzdCk7XG4gICAgICBkaXJlY3Rpb25ZID0gcmFuZG9tRGlzdGFuY2UobWF4UmFuZERpc3QpO1xuICAgIH1cblxuICAgIHZhciBvdmVybGFwID0gbm9kZXNPdmVybGFwKG5vZGUxLCBub2RlMiwgZGlyZWN0aW9uWCwgZGlyZWN0aW9uWSk7XG5cbiAgICBpZiAob3ZlcmxhcCA+IDApIHtcbiAgICAgIC8vIHMgKz0gXCJcXG5Ob2RlcyBETyBvdmVybGFwLlwiO1xuICAgICAgLy8gcyArPSBcIlxcbk92ZXJsYXA6IFwiICsgb3ZlcmxhcDtcbiAgICAgIC8vIElmIG5vZGVzIG92ZXJsYXAsIHJlcHVsc2lvbiBmb3JjZSBpcyBwcm9wb3J0aW9uYWxcbiAgICAgIC8vIHRvIHRoZSBvdmVybGFwXG4gICAgICB2YXIgZm9yY2UgPSBvcHRpb25zLm5vZGVPdmVybGFwICogb3ZlcmxhcDsgLy8gQ29tcHV0ZSB0aGUgbW9kdWxlIGFuZCBjb21wb25lbnRzIG9mIHRoZSBmb3JjZSB2ZWN0b3JcblxuICAgICAgdmFyIGRpc3RhbmNlID0gTWF0aC5zcXJ0KGRpcmVjdGlvblggKiBkaXJlY3Rpb25YICsgZGlyZWN0aW9uWSAqIGRpcmVjdGlvblkpOyAvLyBzICs9IFwiXFxuRGlzdGFuY2U6IFwiICsgZGlzdGFuY2U7XG5cbiAgICAgIHZhciBmb3JjZVggPSBmb3JjZSAqIGRpcmVjdGlvblggLyBkaXN0YW5jZTtcbiAgICAgIHZhciBmb3JjZVkgPSBmb3JjZSAqIGRpcmVjdGlvblkgLyBkaXN0YW5jZTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gcyArPSBcIlxcbk5vZGVzIGRvIE5PVCBvdmVybGFwLlwiO1xuICAgICAgLy8gSWYgdGhlcmUncyBubyBvdmVybGFwLCBmb3JjZSBpcyBpbnZlcnNlbHkgcHJvcG9ydGlvbmFsXG4gICAgICAvLyB0byBzcXVhcmVkIGRpc3RhbmNlXG4gICAgICAvLyBHZXQgY2xpcHBpbmcgcG9pbnRzIGZvciBib3RoIG5vZGVzXG4gICAgICB2YXIgcG9pbnQxID0gZmluZENsaXBwaW5nUG9pbnQobm9kZTEsIGRpcmVjdGlvblgsIGRpcmVjdGlvblkpO1xuICAgICAgdmFyIHBvaW50MiA9IGZpbmRDbGlwcGluZ1BvaW50KG5vZGUyLCAtMSAqIGRpcmVjdGlvblgsIC0xICogZGlyZWN0aW9uWSk7IC8vIFVzZSBjbGlwcGluZyBwb2ludHMgdG8gY29tcHV0ZSBkaXN0YW5jZVxuXG4gICAgICB2YXIgZGlzdGFuY2VYID0gcG9pbnQyLnggLSBwb2ludDEueDtcbiAgICAgIHZhciBkaXN0YW5jZVkgPSBwb2ludDIueSAtIHBvaW50MS55O1xuICAgICAgdmFyIGRpc3RhbmNlU3FyID0gZGlzdGFuY2VYICogZGlzdGFuY2VYICsgZGlzdGFuY2VZICogZGlzdGFuY2VZO1xuICAgICAgdmFyIGRpc3RhbmNlID0gTWF0aC5zcXJ0KGRpc3RhbmNlU3FyKTsgLy8gcyArPSBcIlxcbkRpc3RhbmNlOiBcIiArIGRpc3RhbmNlO1xuICAgICAgLy8gQ29tcHV0ZSB0aGUgbW9kdWxlIGFuZCBjb21wb25lbnRzIG9mIHRoZSBmb3JjZSB2ZWN0b3JcblxuICAgICAgdmFyIGZvcmNlID0gKG5vZGUxLm5vZGVSZXB1bHNpb24gKyBub2RlMi5ub2RlUmVwdWxzaW9uKSAvIGRpc3RhbmNlU3FyO1xuICAgICAgdmFyIGZvcmNlWCA9IGZvcmNlICogZGlzdGFuY2VYIC8gZGlzdGFuY2U7XG4gICAgICB2YXIgZm9yY2VZID0gZm9yY2UgKiBkaXN0YW5jZVkgLyBkaXN0YW5jZTtcbiAgICB9IC8vIEFwcGx5IGZvcmNlXG5cblxuICAgIGlmICghbm9kZTEuaXNMb2NrZWQpIHtcbiAgICAgIG5vZGUxLm9mZnNldFggLT0gZm9yY2VYO1xuICAgICAgbm9kZTEub2Zmc2V0WSAtPSBmb3JjZVk7XG4gICAgfVxuXG4gICAgaWYgKCFub2RlMi5pc0xvY2tlZCkge1xuICAgICAgbm9kZTIub2Zmc2V0WCArPSBmb3JjZVg7XG4gICAgICBub2RlMi5vZmZzZXRZICs9IGZvcmNlWTtcbiAgICB9IC8vIHMgKz0gXCJcXG5Gb3JjZVg6IFwiICsgZm9yY2VYICsgXCIgRm9yY2VZOiBcIiArIGZvcmNlWTtcbiAgICAvLyBsb2dEZWJ1ZyhzKTtcblxuXG4gICAgcmV0dXJuO1xuICB9O1xuICAvKipcbiAgICogQGJyaWVmICA6IERldGVybWluZXMgd2hldGhlciB0d28gbm9kZXMgb3ZlcmxhcCBvciBub3RcbiAgICogQHJldHVybiA6IEFtb3VudCBvZiBvdmVybGFwcGluZyAoMCA9PiBubyBvdmVybGFwKVxuICAgKi9cblxuXG4gIHZhciBub2Rlc092ZXJsYXAgPSBmdW5jdGlvbiBub2Rlc092ZXJsYXAobm9kZTEsIG5vZGUyLCBkWCwgZFkpIHtcbiAgICBpZiAoZFggPiAwKSB7XG4gICAgICB2YXIgb3ZlcmxhcFggPSBub2RlMS5tYXhYIC0gbm9kZTIubWluWDtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIG92ZXJsYXBYID0gbm9kZTIubWF4WCAtIG5vZGUxLm1pblg7XG4gICAgfVxuXG4gICAgaWYgKGRZID4gMCkge1xuICAgICAgdmFyIG92ZXJsYXBZID0gbm9kZTEubWF4WSAtIG5vZGUyLm1pblk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBvdmVybGFwWSA9IG5vZGUyLm1heFkgLSBub2RlMS5taW5ZO1xuICAgIH1cblxuICAgIGlmIChvdmVybGFwWCA+PSAwICYmIG92ZXJsYXBZID49IDApIHtcbiAgICAgIHJldHVybiBNYXRoLnNxcnQob3ZlcmxhcFggKiBvdmVybGFwWCArIG92ZXJsYXBZICogb3ZlcmxhcFkpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gIH07XG4gIC8qKlxuICAgKiBAYnJpZWYgOiBGaW5kcyB0aGUgcG9pbnQgaW4gd2hpY2ggYW4gZWRnZSAoZGlyZWN0aW9uIGRYLCBkWSkgaW50ZXJzZWN0c1xuICAgKiAgICAgICAgICB0aGUgcmVjdGFuZ3VsYXIgYm91bmRpbmcgYm94IG9mIGl0J3Mgc291cmNlL3RhcmdldCBub2RlXG4gICAqL1xuXG5cbiAgdmFyIGZpbmRDbGlwcGluZ1BvaW50ID0gZnVuY3Rpb24gZmluZENsaXBwaW5nUG9pbnQobm9kZSwgZFgsIGRZKSB7XG4gICAgLy8gU2hvcmN1dHNcbiAgICB2YXIgWCA9IG5vZGUucG9zaXRpb25YO1xuICAgIHZhciBZID0gbm9kZS5wb3NpdGlvblk7XG4gICAgdmFyIEggPSBub2RlLmhlaWdodCB8fCAxO1xuICAgIHZhciBXID0gbm9kZS53aWR0aCB8fCAxO1xuICAgIHZhciBkaXJTbG9wZSA9IGRZIC8gZFg7XG4gICAgdmFyIG5vZGVTbG9wZSA9IEggLyBXOyAvLyB2YXIgcyA9ICdDb21wdXRpbmcgY2xpcHBpbmcgcG9pbnQgb2Ygbm9kZSAnICsgbm9kZS5pZCArXG4gICAgLy8gICBcIiAuIEhlaWdodDogIFwiICsgSCArIFwiLCBXaWR0aDogXCIgKyBXICtcbiAgICAvLyAgIFwiXFxuRGlyZWN0aW9uIFwiICsgZFggKyBcIiwgXCIgKyBkWTtcbiAgICAvL1xuICAgIC8vIENvbXB1dGUgaW50ZXJzZWN0aW9uXG5cbiAgICB2YXIgcmVzID0ge307IC8vIENhc2U6IFZlcnRpY2FsIGRpcmVjdGlvbiAodXApXG5cbiAgICBpZiAoMCA9PT0gZFggJiYgMCA8IGRZKSB7XG4gICAgICByZXMueCA9IFg7IC8vIHMgKz0gXCJcXG5VcCBkaXJlY3Rpb25cIjtcblxuICAgICAgcmVzLnkgPSBZICsgSCAvIDI7XG4gICAgICByZXR1cm4gcmVzO1xuICAgIH0gLy8gQ2FzZTogVmVydGljYWwgZGlyZWN0aW9uIChkb3duKVxuXG5cbiAgICBpZiAoMCA9PT0gZFggJiYgMCA+IGRZKSB7XG4gICAgICByZXMueCA9IFg7XG4gICAgICByZXMueSA9IFkgKyBIIC8gMjsgLy8gcyArPSBcIlxcbkRvd24gZGlyZWN0aW9uXCI7XG5cbiAgICAgIHJldHVybiByZXM7XG4gICAgfSAvLyBDYXNlOiBJbnRlcnNlY3RzIHRoZSByaWdodCBib3JkZXJcblxuXG4gICAgaWYgKDAgPCBkWCAmJiAtMSAqIG5vZGVTbG9wZSA8PSBkaXJTbG9wZSAmJiBkaXJTbG9wZSA8PSBub2RlU2xvcGUpIHtcbiAgICAgIHJlcy54ID0gWCArIFcgLyAyO1xuICAgICAgcmVzLnkgPSBZICsgVyAqIGRZIC8gMiAvIGRYOyAvLyBzICs9IFwiXFxuUmlnaHRib3JkZXJcIjtcblxuICAgICAgcmV0dXJuIHJlcztcbiAgICB9IC8vIENhc2U6IEludGVyc2VjdHMgdGhlIGxlZnQgYm9yZGVyXG5cblxuICAgIGlmICgwID4gZFggJiYgLTEgKiBub2RlU2xvcGUgPD0gZGlyU2xvcGUgJiYgZGlyU2xvcGUgPD0gbm9kZVNsb3BlKSB7XG4gICAgICByZXMueCA9IFggLSBXIC8gMjtcbiAgICAgIHJlcy55ID0gWSAtIFcgKiBkWSAvIDIgLyBkWDsgLy8gcyArPSBcIlxcbkxlZnRib3JkZXJcIjtcblxuICAgICAgcmV0dXJuIHJlcztcbiAgICB9IC8vIENhc2U6IEludGVyc2VjdHMgdGhlIHRvcCBib3JkZXJcblxuXG4gICAgaWYgKDAgPCBkWSAmJiAoZGlyU2xvcGUgPD0gLTEgKiBub2RlU2xvcGUgfHwgZGlyU2xvcGUgPj0gbm9kZVNsb3BlKSkge1xuICAgICAgcmVzLnggPSBYICsgSCAqIGRYIC8gMiAvIGRZO1xuICAgICAgcmVzLnkgPSBZICsgSCAvIDI7IC8vIHMgKz0gXCJcXG5Ub3AgYm9yZGVyXCI7XG5cbiAgICAgIHJldHVybiByZXM7XG4gICAgfSAvLyBDYXNlOiBJbnRlcnNlY3RzIHRoZSBib3R0b20gYm9yZGVyXG5cblxuICAgIGlmICgwID4gZFkgJiYgKGRpclNsb3BlIDw9IC0xICogbm9kZVNsb3BlIHx8IGRpclNsb3BlID49IG5vZGVTbG9wZSkpIHtcbiAgICAgIHJlcy54ID0gWCAtIEggKiBkWCAvIDIgLyBkWTtcbiAgICAgIHJlcy55ID0gWSAtIEggLyAyOyAvLyBzICs9IFwiXFxuQm90dG9tIGJvcmRlclwiO1xuXG4gICAgICByZXR1cm4gcmVzO1xuICAgIH0gLy8gcyArPSBcIlxcbkNsaXBwaW5nIHBvaW50IGZvdW5kIGF0IFwiICsgcmVzLnggKyBcIiwgXCIgKyByZXMueTtcbiAgICAvLyBsb2dEZWJ1ZyhzKTtcblxuXG4gICAgcmV0dXJuIHJlcztcbiAgfTtcbiAgLyoqXG4gICAqIEBicmllZiA6IENhbGN1bGF0ZXMgYWxsIGVkZ2UgZm9yY2VzXG4gICAqL1xuXG5cbiAgdmFyIGNhbGN1bGF0ZUVkZ2VGb3JjZXMgPSBmdW5jdGlvbiBjYWxjdWxhdGVFZGdlRm9yY2VzKGxheW91dEluZm8sIG9wdGlvbnMpIHtcbiAgICAvLyBJdGVyYXRlIG92ZXIgYWxsIGVkZ2VzXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsYXlvdXRJbmZvLmVkZ2VTaXplOyBpKyspIHtcbiAgICAgIC8vIEdldCBlZGdlLCBzb3VyY2UgJiB0YXJnZXQgbm9kZXNcbiAgICAgIHZhciBlZGdlID0gbGF5b3V0SW5mby5sYXlvdXRFZGdlc1tpXTtcbiAgICAgIHZhciBzb3VyY2VJeCA9IGxheW91dEluZm8uaWRUb0luZGV4W2VkZ2Uuc291cmNlSWRdO1xuICAgICAgdmFyIHNvdXJjZSA9IGxheW91dEluZm8ubGF5b3V0Tm9kZXNbc291cmNlSXhdO1xuICAgICAgdmFyIHRhcmdldEl4ID0gbGF5b3V0SW5mby5pZFRvSW5kZXhbZWRnZS50YXJnZXRJZF07XG4gICAgICB2YXIgdGFyZ2V0ID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1t0YXJnZXRJeF07IC8vIEdldCBkaXJlY3Rpb24gb2YgbGluZSBjb25uZWN0aW5nIGJvdGggbm9kZSBjZW50ZXJzXG5cbiAgICAgIHZhciBkaXJlY3Rpb25YID0gdGFyZ2V0LnBvc2l0aW9uWCAtIHNvdXJjZS5wb3NpdGlvblg7XG4gICAgICB2YXIgZGlyZWN0aW9uWSA9IHRhcmdldC5wb3NpdGlvblkgLSBzb3VyY2UucG9zaXRpb25ZOyAvLyBJZiBib3RoIGNlbnRlcnMgYXJlIHRoZSBzYW1lLCBkbyBub3RoaW5nLlxuICAgICAgLy8gQSByYW5kb20gZm9yY2UgaGFzIGFscmVhZHkgYmVlbiBhcHBsaWVkIGFzIG5vZGUgcmVwdWxzaW9uXG5cbiAgICAgIGlmICgwID09PSBkaXJlY3Rpb25YICYmIDAgPT09IGRpcmVjdGlvblkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9IC8vIEdldCBjbGlwcGluZyBwb2ludHMgZm9yIGJvdGggbm9kZXNcblxuXG4gICAgICB2YXIgcG9pbnQxID0gZmluZENsaXBwaW5nUG9pbnQoc291cmNlLCBkaXJlY3Rpb25YLCBkaXJlY3Rpb25ZKTtcbiAgICAgIHZhciBwb2ludDIgPSBmaW5kQ2xpcHBpbmdQb2ludCh0YXJnZXQsIC0xICogZGlyZWN0aW9uWCwgLTEgKiBkaXJlY3Rpb25ZKTtcbiAgICAgIHZhciBseCA9IHBvaW50Mi54IC0gcG9pbnQxLng7XG4gICAgICB2YXIgbHkgPSBwb2ludDIueSAtIHBvaW50MS55O1xuICAgICAgdmFyIGwgPSBNYXRoLnNxcnQobHggKiBseCArIGx5ICogbHkpO1xuICAgICAgdmFyIGZvcmNlID0gTWF0aC5wb3coZWRnZS5pZGVhbExlbmd0aCAtIGwsIDIpIC8gZWRnZS5lbGFzdGljaXR5O1xuXG4gICAgICBpZiAoMCAhPT0gbCkge1xuICAgICAgICB2YXIgZm9yY2VYID0gZm9yY2UgKiBseCAvIGw7XG4gICAgICAgIHZhciBmb3JjZVkgPSBmb3JjZSAqIGx5IC8gbDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBmb3JjZVggPSAwO1xuICAgICAgICB2YXIgZm9yY2VZID0gMDtcbiAgICAgIH0gLy8gQWRkIHRoaXMgZm9yY2UgdG8gdGFyZ2V0IGFuZCBzb3VyY2Ugbm9kZXNcblxuXG4gICAgICBpZiAoIXNvdXJjZS5pc0xvY2tlZCkge1xuICAgICAgICBzb3VyY2Uub2Zmc2V0WCArPSBmb3JjZVg7XG4gICAgICAgIHNvdXJjZS5vZmZzZXRZICs9IGZvcmNlWTtcbiAgICAgIH1cblxuICAgICAgaWYgKCF0YXJnZXQuaXNMb2NrZWQpIHtcbiAgICAgICAgdGFyZ2V0Lm9mZnNldFggLT0gZm9yY2VYO1xuICAgICAgICB0YXJnZXQub2Zmc2V0WSAtPSBmb3JjZVk7XG4gICAgICB9IC8vIHZhciBzID0gJ0VkZ2UgZm9yY2UgYmV0d2VlbiBub2RlcyAnICsgc291cmNlLmlkICsgJyBhbmQgJyArIHRhcmdldC5pZDtcbiAgICAgIC8vIHMgKz0gXCJcXG5EaXN0YW5jZTogXCIgKyBsICsgXCIgRm9yY2U6IChcIiArIGZvcmNlWCArIFwiLCBcIiArIGZvcmNlWSArIFwiKVwiO1xuICAgICAgLy8gbG9nRGVidWcocyk7XG5cbiAgICB9XG4gIH07XG4gIC8qKlxuICAgKiBAYnJpZWYgOiBDb21wdXRlcyBncmF2aXR5IGZvcmNlcyBmb3IgYWxsIG5vZGVzXG4gICAqL1xuXG5cbiAgdmFyIGNhbGN1bGF0ZUdyYXZpdHlGb3JjZXMgPSBmdW5jdGlvbiBjYWxjdWxhdGVHcmF2aXR5Rm9yY2VzKGxheW91dEluZm8sIG9wdGlvbnMpIHtcbiAgICBpZiAob3B0aW9ucy5ncmF2aXR5ID09PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGRpc3RUaHJlc2hvbGQgPSAxOyAvLyB2YXIgcyA9ICdjYWxjdWxhdGVHcmF2aXR5Rm9yY2VzJztcbiAgICAvLyBsb2dEZWJ1ZyhzKTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGF5b3V0SW5mby5ncmFwaFNldC5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGdyYXBoID0gbGF5b3V0SW5mby5ncmFwaFNldFtpXTtcbiAgICAgIHZhciBudW1Ob2RlcyA9IGdyYXBoLmxlbmd0aDsgLy8gcyA9IFwiU2V0OiBcIiArIGdyYXBoLnRvU3RyaW5nKCk7XG4gICAgICAvLyBsb2dEZWJ1ZyhzKTtcbiAgICAgIC8vIENvbXB1dGUgZ3JhcGggY2VudGVyXG5cbiAgICAgIGlmICgwID09PSBpKSB7XG4gICAgICAgIHZhciBjZW50ZXJYID0gbGF5b3V0SW5mby5jbGllbnRIZWlnaHQgLyAyO1xuICAgICAgICB2YXIgY2VudGVyWSA9IGxheW91dEluZm8uY2xpZW50V2lkdGggLyAyO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gR2V0IFBhcmVudCBub2RlIGZvciB0aGlzIGdyYXBoLCBhbmQgdXNlIGl0cyBwb3NpdGlvbiBhcyBjZW50ZXJcbiAgICAgICAgdmFyIHRlbXAgPSBsYXlvdXRJbmZvLmxheW91dE5vZGVzW2xheW91dEluZm8uaWRUb0luZGV4W2dyYXBoWzBdXV07XG4gICAgICAgIHZhciBwYXJlbnQgPSBsYXlvdXRJbmZvLmxheW91dE5vZGVzW2xheW91dEluZm8uaWRUb0luZGV4W3RlbXAucGFyZW50SWRdXTtcbiAgICAgICAgdmFyIGNlbnRlclggPSBwYXJlbnQucG9zaXRpb25YO1xuICAgICAgICB2YXIgY2VudGVyWSA9IHBhcmVudC5wb3NpdGlvblk7XG4gICAgICB9IC8vIHMgPSBcIkNlbnRlciBmb3VuZCBhdDogXCIgKyBjZW50ZXJYICsgXCIsIFwiICsgY2VudGVyWTtcbiAgICAgIC8vIGxvZ0RlYnVnKHMpO1xuICAgICAgLy8gQXBwbHkgZm9yY2UgdG8gYWxsIG5vZGVzIGluIGdyYXBoXG5cblxuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBudW1Ob2RlczsgaisrKSB7XG4gICAgICAgIHZhciBub2RlID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1tsYXlvdXRJbmZvLmlkVG9JbmRleFtncmFwaFtqXV1dOyAvLyBzID0gXCJOb2RlOiBcIiArIG5vZGUuaWQ7XG5cbiAgICAgICAgaWYgKG5vZGUuaXNMb2NrZWQpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBkeCA9IGNlbnRlclggLSBub2RlLnBvc2l0aW9uWDtcbiAgICAgICAgdmFyIGR5ID0gY2VudGVyWSAtIG5vZGUucG9zaXRpb25ZO1xuICAgICAgICB2YXIgZCA9IE1hdGguc3FydChkeCAqIGR4ICsgZHkgKiBkeSk7XG5cbiAgICAgICAgaWYgKGQgPiBkaXN0VGhyZXNob2xkKSB7XG4gICAgICAgICAgdmFyIGZ4ID0gb3B0aW9ucy5ncmF2aXR5ICogZHggLyBkO1xuICAgICAgICAgIHZhciBmeSA9IG9wdGlvbnMuZ3Jhdml0eSAqIGR5IC8gZDtcbiAgICAgICAgICBub2RlLm9mZnNldFggKz0gZng7XG4gICAgICAgICAgbm9kZS5vZmZzZXRZICs9IGZ5OyAvLyBzICs9IFwiOiBBcHBsaWVkIGZvcmNlOiBcIiArIGZ4ICsgXCIsIFwiICsgZnk7XG4gICAgICAgIH0gLy8gbG9nRGVidWcocyk7XG5cbiAgICAgIH1cbiAgICB9XG4gIH07XG4gIC8qKlxuICAgKiBAYnJpZWYgICAgICAgICAgOiBUaGlzIGZ1bmN0aW9uIHByb3BhZ2F0ZXMgdGhlIGV4aXN0aW5nIG9mZnNldHMgZnJvbVxuICAgKiAgICAgICAgICAgICAgICAgICBwYXJlbnQgbm9kZXMgdG8gaXRzIGRlc2NlbmRlbnRzLlxuICAgKiBAYXJnIGxheW91dEluZm8gOiBsYXlvdXRJbmZvIE9iamVjdFxuICAgKiBAYXJnIGN5ICAgICAgICAgOiBjeXRvc2NhcGUgT2JqZWN0XG4gICAqIEBhcmcgb3B0aW9ucyAgICA6IExheW91dCBvcHRpb25zXG4gICAqL1xuXG5cbiAgdmFyIHByb3BhZ2F0ZUZvcmNlcyA9IGZ1bmN0aW9uIHByb3BhZ2F0ZUZvcmNlcyhsYXlvdXRJbmZvLCBvcHRpb25zKSB7XG4gICAgLy8gSW5saW5lIGltcGxlbWVudGF0aW9uIG9mIGEgcXVldWUsIHVzZWQgZm9yIHRyYXZlcnNpbmcgdGhlIGdyYXBoIGluIEJGUyBvcmRlclxuICAgIHZhciBxdWV1ZSA9IFtdO1xuICAgIHZhciBzdGFydCA9IDA7IC8vIFBvaW50cyB0byB0aGUgc3RhcnQgdGhlIHF1ZXVlXG5cbiAgICB2YXIgZW5kID0gLTE7IC8vIFBvaW50cyB0byB0aGUgZW5kIG9mIHRoZSBxdWV1ZVxuICAgIC8vIGxvZ0RlYnVnKCdwcm9wYWdhdGVGb3JjZXMnKTtcbiAgICAvLyBTdGFydCBieSB2aXNpdGluZyB0aGUgbm9kZXMgaW4gdGhlIHJvb3QgZ3JhcGhcblxuICAgIHF1ZXVlLnB1c2guYXBwbHkocXVldWUsIGxheW91dEluZm8uZ3JhcGhTZXRbMF0pO1xuICAgIGVuZCArPSBsYXlvdXRJbmZvLmdyYXBoU2V0WzBdLmxlbmd0aDsgLy8gVHJhdmVyc2UgdGhlIGdyYXBoLCBsZXZlbCBieSBsZXZlbCxcblxuICAgIHdoaWxlIChzdGFydCA8PSBlbmQpIHtcbiAgICAgIC8vIEdldCB0aGUgbm9kZSB0byB2aXNpdCBhbmQgcmVtb3ZlIGl0IGZyb20gcXVldWVcbiAgICAgIHZhciBub2RlSWQgPSBxdWV1ZVtzdGFydCsrXTtcbiAgICAgIHZhciBub2RlSW5kZXggPSBsYXlvdXRJbmZvLmlkVG9JbmRleFtub2RlSWRdO1xuICAgICAgdmFyIG5vZGUgPSBsYXlvdXRJbmZvLmxheW91dE5vZGVzW25vZGVJbmRleF07XG4gICAgICB2YXIgY2hpbGRyZW4gPSBub2RlLmNoaWxkcmVuOyAvLyBXZSBvbmx5IG5lZWQgdG8gcHJvY2VzcyB0aGUgbm9kZSBpZiBpdCdzIGNvbXBvdW5kXG5cbiAgICAgIGlmICgwIDwgY2hpbGRyZW4ubGVuZ3RoICYmICFub2RlLmlzTG9ja2VkKSB7XG4gICAgICAgIHZhciBvZmZYID0gbm9kZS5vZmZzZXRYO1xuICAgICAgICB2YXIgb2ZmWSA9IG5vZGUub2Zmc2V0WTsgLy8gdmFyIHMgPSBcIlByb3BhZ2F0aW5nIG9mZnNldCBmcm9tIHBhcmVudCBub2RlIDogXCIgKyBub2RlLmlkICtcbiAgICAgICAgLy8gICBcIi4gT2Zmc2V0WDogXCIgKyBvZmZYICsgXCIuIE9mZnNldFk6IFwiICsgb2ZmWTtcbiAgICAgICAgLy8gcyArPSBcIlxcbiBDaGlsZHJlbjogXCIgKyBjaGlsZHJlbi50b1N0cmluZygpO1xuICAgICAgICAvLyBsb2dEZWJ1ZyhzKTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgdmFyIGNoaWxkTm9kZSA9IGxheW91dEluZm8ubGF5b3V0Tm9kZXNbbGF5b3V0SW5mby5pZFRvSW5kZXhbY2hpbGRyZW5baV1dXTsgLy8gUHJvcGFnYXRlIG9mZnNldFxuXG4gICAgICAgICAgY2hpbGROb2RlLm9mZnNldFggKz0gb2ZmWDtcbiAgICAgICAgICBjaGlsZE5vZGUub2Zmc2V0WSArPSBvZmZZOyAvLyBBZGQgY2hpbGRyZW4gdG8gcXVldWUgdG8gYmUgdmlzaXRlZFxuXG4gICAgICAgICAgcXVldWVbKytlbmRdID0gY2hpbGRyZW5baV07XG4gICAgICAgIH0gLy8gUmVzZXQgcGFyZW50IG9mZnNldHNcblxuXG4gICAgICAgIG5vZGUub2Zmc2V0WCA9IDA7XG4gICAgICAgIG5vZGUub2Zmc2V0WSA9IDA7XG4gICAgICB9XG4gICAgfVxuICB9O1xuICAvKipcbiAgICogQGJyaWVmIDogVXBkYXRlcyB0aGUgbGF5b3V0IG1vZGVsIHBvc2l0aW9ucywgYmFzZWQgb25cbiAgICogICAgICAgICAgdGhlIGFjY3VtdWxhdGVkIGZvcmNlc1xuICAgKi9cblxuXG4gIHZhciB1cGRhdGVQb3NpdGlvbnMgPSBmdW5jdGlvbiB1cGRhdGVQb3NpdGlvbnMobGF5b3V0SW5mbywgb3B0aW9ucykge1xuICAgIC8vIHZhciBzID0gJ1VwZGF0aW5nIHBvc2l0aW9ucyc7XG4gICAgLy8gbG9nRGVidWcocyk7XG4gICAgLy8gUmVzZXQgYm91bmRhcmllcyBmb3IgY29tcG91bmQgbm9kZXNcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxheW91dEluZm8ubm9kZVNpemU7IGkrKykge1xuICAgICAgdmFyIG4gPSBsYXlvdXRJbmZvLmxheW91dE5vZGVzW2ldO1xuXG4gICAgICBpZiAoMCA8IG4uY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgIC8vIGxvZ0RlYnVnKFwiUmVzZXR0aW5nIGJvdW5kYXJpZXMgb2YgY29tcG91bmQgbm9kZTogXCIgKyBuLmlkKTtcbiAgICAgICAgbi5tYXhYID0gdW5kZWZpbmVkO1xuICAgICAgICBuLm1pblggPSB1bmRlZmluZWQ7XG4gICAgICAgIG4ubWF4WSA9IHVuZGVmaW5lZDtcbiAgICAgICAgbi5taW5ZID0gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGF5b3V0SW5mby5ub2RlU2l6ZTsgaSsrKSB7XG4gICAgICB2YXIgbiA9IGxheW91dEluZm8ubGF5b3V0Tm9kZXNbaV07XG5cbiAgICAgIGlmICgwIDwgbi5jaGlsZHJlbi5sZW5ndGggfHwgbi5pc0xvY2tlZCkge1xuICAgICAgICAvLyBObyBuZWVkIHRvIHNldCBjb21wb3VuZCBvciBsb2NrZWQgbm9kZSBwb3NpdGlvblxuICAgICAgICAvLyBsb2dEZWJ1ZyhcIlNraXBwaW5nIHBvc2l0aW9uIHVwZGF0ZSBvZiBub2RlOiBcIiArIG4uaWQpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH0gLy8gcyA9IFwiTm9kZTogXCIgKyBuLmlkICsgXCIgUHJldmlvdXMgcG9zaXRpb246IChcIiArXG4gICAgICAvLyBuLnBvc2l0aW9uWCArIFwiLCBcIiArIG4ucG9zaXRpb25ZICsgXCIpLlwiO1xuICAgICAgLy8gTGltaXQgZGlzcGxhY2VtZW50IGluIG9yZGVyIHRvIGltcHJvdmUgc3RhYmlsaXR5XG5cblxuICAgICAgdmFyIHRlbXBGb3JjZSA9IGxpbWl0Rm9yY2Uobi5vZmZzZXRYLCBuLm9mZnNldFksIGxheW91dEluZm8udGVtcGVyYXR1cmUpO1xuICAgICAgbi5wb3NpdGlvblggKz0gdGVtcEZvcmNlLng7XG4gICAgICBuLnBvc2l0aW9uWSArPSB0ZW1wRm9yY2UueTtcbiAgICAgIG4ub2Zmc2V0WCA9IDA7XG4gICAgICBuLm9mZnNldFkgPSAwO1xuICAgICAgbi5taW5YID0gbi5wb3NpdGlvblggLSBuLndpZHRoO1xuICAgICAgbi5tYXhYID0gbi5wb3NpdGlvblggKyBuLndpZHRoO1xuICAgICAgbi5taW5ZID0gbi5wb3NpdGlvblkgLSBuLmhlaWdodDtcbiAgICAgIG4ubWF4WSA9IG4ucG9zaXRpb25ZICsgbi5oZWlnaHQ7IC8vIHMgKz0gXCIgTmV3IFBvc2l0aW9uOiAoXCIgKyBuLnBvc2l0aW9uWCArIFwiLCBcIiArIG4ucG9zaXRpb25ZICsgXCIpLlwiO1xuICAgICAgLy8gbG9nRGVidWcocyk7XG4gICAgICAvLyBVcGRhdGUgYW5jZXN0cnkgYm91ZGFyaWVzXG5cbiAgICAgIHVwZGF0ZUFuY2VzdHJ5Qm91bmRhcmllcyhuLCBsYXlvdXRJbmZvKTtcbiAgICB9IC8vIFVwZGF0ZSBzaXplLCBwb3NpdGlvbiBvZiBjb21wdW5kIG5vZGVzXG5cblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGF5b3V0SW5mby5ub2RlU2l6ZTsgaSsrKSB7XG4gICAgICB2YXIgbiA9IGxheW91dEluZm8ubGF5b3V0Tm9kZXNbaV07XG5cbiAgICAgIGlmICgwIDwgbi5jaGlsZHJlbi5sZW5ndGggJiYgIW4uaXNMb2NrZWQpIHtcbiAgICAgICAgbi5wb3NpdGlvblggPSAobi5tYXhYICsgbi5taW5YKSAvIDI7XG4gICAgICAgIG4ucG9zaXRpb25ZID0gKG4ubWF4WSArIG4ubWluWSkgLyAyO1xuICAgICAgICBuLndpZHRoID0gbi5tYXhYIC0gbi5taW5YO1xuICAgICAgICBuLmhlaWdodCA9IG4ubWF4WSAtIG4ubWluWTsgLy8gcyA9IFwiVXBkYXRpbmcgcG9zaXRpb24sIHNpemUgb2YgY29tcG91bmQgbm9kZSBcIiArIG4uaWQ7XG4gICAgICAgIC8vIHMgKz0gXCJcXG5Qb3NpdGlvblg6IFwiICsgbi5wb3NpdGlvblggKyBcIiwgUG9zaXRpb25ZOiBcIiArIG4ucG9zaXRpb25ZO1xuICAgICAgICAvLyBzICs9IFwiXFxuV2lkdGg6IFwiICsgbi53aWR0aCArIFwiLCBIZWlnaHQ6IFwiICsgbi5oZWlnaHQ7XG4gICAgICAgIC8vIGxvZ0RlYnVnKHMpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcbiAgLyoqXG4gICAqIEBicmllZiA6IExpbWl0cyBhIGZvcmNlIChmb3JjZVgsIGZvcmNlWSkgdG8gYmUgbm90XG4gICAqICAgICAgICAgIGdyZWF0ZXIgKGluIG1vZHVsbykgdGhhbiBtYXguXG4gICA4ICAgICAgICAgIFByZXNlcnZlcyBmb3JjZSBkaXJlY3Rpb24uXG4gICAgKi9cblxuXG4gIHZhciBsaW1pdEZvcmNlID0gZnVuY3Rpb24gbGltaXRGb3JjZShmb3JjZVgsIGZvcmNlWSwgbWF4KSB7XG4gICAgLy8gdmFyIHMgPSBcIkxpbWl0aW5nIGZvcmNlOiAoXCIgKyBmb3JjZVggKyBcIiwgXCIgKyBmb3JjZVkgKyBcIikuIE1heDogXCIgKyBtYXg7XG4gICAgdmFyIGZvcmNlID0gTWF0aC5zcXJ0KGZvcmNlWCAqIGZvcmNlWCArIGZvcmNlWSAqIGZvcmNlWSk7XG5cbiAgICBpZiAoZm9yY2UgPiBtYXgpIHtcbiAgICAgIHZhciByZXMgPSB7XG4gICAgICAgIHg6IG1heCAqIGZvcmNlWCAvIGZvcmNlLFxuICAgICAgICB5OiBtYXggKiBmb3JjZVkgLyBmb3JjZVxuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIHJlcyA9IHtcbiAgICAgICAgeDogZm9yY2VYLFxuICAgICAgICB5OiBmb3JjZVlcbiAgICAgIH07XG4gICAgfSAvLyBzICs9IFwiLlxcblJlc3VsdDogKFwiICsgcmVzLnggKyBcIiwgXCIgKyByZXMueSArIFwiKVwiO1xuICAgIC8vIGxvZ0RlYnVnKHMpO1xuXG5cbiAgICByZXR1cm4gcmVzO1xuICB9O1xuICAvKipcbiAgICogQGJyaWVmIDogRnVuY3Rpb24gdXNlZCBmb3Iga2VlcGluZyB0cmFjayBvZiBjb21wb3VuZCBub2RlXG4gICAqICAgICAgICAgIHNpemVzLCBzaW5jZSB0aGV5IHNob3VsZCBib3VuZCBhbGwgdGhlaXIgc3Vibm9kZXMuXG4gICAqL1xuXG5cbiAgdmFyIHVwZGF0ZUFuY2VzdHJ5Qm91bmRhcmllcyA9IGZ1bmN0aW9uIHVwZGF0ZUFuY2VzdHJ5Qm91bmRhcmllcyhub2RlLCBsYXlvdXRJbmZvKSB7XG4gICAgLy8gdmFyIHMgPSBcIlByb3BhZ2F0aW5nIG5ldyBwb3NpdGlvbi9zaXplIG9mIG5vZGUgXCIgKyBub2RlLmlkO1xuICAgIHZhciBwYXJlbnRJZCA9IG5vZGUucGFyZW50SWQ7XG5cbiAgICBpZiAobnVsbCA9PSBwYXJlbnRJZCkge1xuICAgICAgLy8gSWYgdGhlcmUncyBubyBwYXJlbnQsIHdlIGFyZSBkb25lXG4gICAgICAvLyBzICs9IFwiLiBObyBwYXJlbnQgbm9kZS5cIjtcbiAgICAgIC8vIGxvZ0RlYnVnKHMpO1xuICAgICAgcmV0dXJuO1xuICAgIH0gLy8gR2V0IFBhcmVudCBOb2RlXG5cblxuICAgIHZhciBwID0gbGF5b3V0SW5mby5sYXlvdXROb2Rlc1tsYXlvdXRJbmZvLmlkVG9JbmRleFtwYXJlbnRJZF1dO1xuICAgIHZhciBmbGFnID0gZmFsc2U7IC8vIE1heFhcblxuICAgIGlmIChudWxsID09IHAubWF4WCB8fCBub2RlLm1heFggKyBwLnBhZFJpZ2h0ID4gcC5tYXhYKSB7XG4gICAgICBwLm1heFggPSBub2RlLm1heFggKyBwLnBhZFJpZ2h0O1xuICAgICAgZmxhZyA9IHRydWU7IC8vIHMgKz0gXCJcXG5OZXcgbWF4WCBmb3IgcGFyZW50IG5vZGUgXCIgKyBwLmlkICsgXCI6IFwiICsgcC5tYXhYO1xuICAgIH0gLy8gTWluWFxuXG5cbiAgICBpZiAobnVsbCA9PSBwLm1pblggfHwgbm9kZS5taW5YIC0gcC5wYWRMZWZ0IDwgcC5taW5YKSB7XG4gICAgICBwLm1pblggPSBub2RlLm1pblggLSBwLnBhZExlZnQ7XG4gICAgICBmbGFnID0gdHJ1ZTsgLy8gcyArPSBcIlxcbk5ldyBtaW5YIGZvciBwYXJlbnQgbm9kZSBcIiArIHAuaWQgKyBcIjogXCIgKyBwLm1pblg7XG4gICAgfSAvLyBNYXhZXG5cblxuICAgIGlmIChudWxsID09IHAubWF4WSB8fCBub2RlLm1heFkgKyBwLnBhZEJvdHRvbSA+IHAubWF4WSkge1xuICAgICAgcC5tYXhZID0gbm9kZS5tYXhZICsgcC5wYWRCb3R0b207XG4gICAgICBmbGFnID0gdHJ1ZTsgLy8gcyArPSBcIlxcbk5ldyBtYXhZIGZvciBwYXJlbnQgbm9kZSBcIiArIHAuaWQgKyBcIjogXCIgKyBwLm1heFk7XG4gICAgfSAvLyBNaW5ZXG5cblxuICAgIGlmIChudWxsID09IHAubWluWSB8fCBub2RlLm1pblkgLSBwLnBhZFRvcCA8IHAubWluWSkge1xuICAgICAgcC5taW5ZID0gbm9kZS5taW5ZIC0gcC5wYWRUb3A7XG4gICAgICBmbGFnID0gdHJ1ZTsgLy8gcyArPSBcIlxcbk5ldyBtaW5ZIGZvciBwYXJlbnQgbm9kZSBcIiArIHAuaWQgKyBcIjogXCIgKyBwLm1pblk7XG4gICAgfSAvLyBJZiB1cGRhdGVkIGJvdW5kYXJpZXMsIHByb3BhZ2F0ZSBjaGFuZ2VzIHVwd2FyZFxuXG5cbiAgICBpZiAoZmxhZykge1xuICAgICAgLy8gbG9nRGVidWcocyk7XG4gICAgICByZXR1cm4gdXBkYXRlQW5jZXN0cnlCb3VuZGFyaWVzKHAsIGxheW91dEluZm8pO1xuICAgIH0gLy8gcyArPSBcIi4gTm8gY2hhbmdlcyBpbiBib3VuZGFyaWVzL3Bvc2l0aW9uIG9mIHBhcmVudCBub2RlIFwiICsgcC5pZDtcbiAgICAvLyBsb2dEZWJ1ZyhzKTtcblxuXG4gICAgcmV0dXJuO1xuICB9O1xuXG4gIHZhciBzZXBhcmF0ZUNvbXBvbmVudHMgPSBmdW5jdGlvbiBzZXBhcmF0ZUNvbXBvbmVudHMobGF5b3V0SW5mbywgb3B0aW9ucykge1xuICAgIHZhciBub2RlcyA9IGxheW91dEluZm8ubGF5b3V0Tm9kZXM7XG4gICAgdmFyIGNvbXBvbmVudHMgPSBbXTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBub2RlID0gbm9kZXNbaV07XG4gICAgICB2YXIgY2lkID0gbm9kZS5jbXB0SWQ7XG4gICAgICB2YXIgY29tcG9uZW50ID0gY29tcG9uZW50c1tjaWRdID0gY29tcG9uZW50c1tjaWRdIHx8IFtdO1xuICAgICAgY29tcG9uZW50LnB1c2gobm9kZSk7XG4gICAgfVxuXG4gICAgdmFyIHRvdGFsQSA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbXBvbmVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBjID0gY29tcG9uZW50c1tpXTtcblxuICAgICAgaWYgKCFjKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjLngxID0gSW5maW5pdHk7XG4gICAgICBjLngyID0gLUluZmluaXR5O1xuICAgICAgYy55MSA9IEluZmluaXR5O1xuICAgICAgYy55MiA9IC1JbmZpbml0eTtcblxuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBjLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHZhciBuID0gY1tqXTtcbiAgICAgICAgYy54MSA9IE1hdGgubWluKGMueDEsIG4ucG9zaXRpb25YIC0gbi53aWR0aCAvIDIpO1xuICAgICAgICBjLngyID0gTWF0aC5tYXgoYy54Miwgbi5wb3NpdGlvblggKyBuLndpZHRoIC8gMik7XG4gICAgICAgIGMueTEgPSBNYXRoLm1pbihjLnkxLCBuLnBvc2l0aW9uWSAtIG4uaGVpZ2h0IC8gMik7XG4gICAgICAgIGMueTIgPSBNYXRoLm1heChjLnkyLCBuLnBvc2l0aW9uWSArIG4uaGVpZ2h0IC8gMik7XG4gICAgICB9XG5cbiAgICAgIGMudyA9IGMueDIgLSBjLngxO1xuICAgICAgYy5oID0gYy55MiAtIGMueTE7XG4gICAgICB0b3RhbEEgKz0gYy53ICogYy5oO1xuICAgIH1cblxuICAgIGNvbXBvbmVudHMuc29ydChmdW5jdGlvbiAoYzEsIGMyKSB7XG4gICAgICByZXR1cm4gYzIudyAqIGMyLmggLSBjMS53ICogYzEuaDtcbiAgICB9KTtcbiAgICB2YXIgeCA9IDA7XG4gICAgdmFyIHkgPSAwO1xuICAgIHZhciB1c2VkVyA9IDA7XG4gICAgdmFyIHJvd0ggPSAwO1xuICAgIHZhciBtYXhSb3dXID0gTWF0aC5zcXJ0KHRvdGFsQSkgKiBsYXlvdXRJbmZvLmNsaWVudFdpZHRoIC8gbGF5b3V0SW5mby5jbGllbnRIZWlnaHQ7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbXBvbmVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBjID0gY29tcG9uZW50c1tpXTtcblxuICAgICAgaWYgKCFjKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdmFyIG4gPSBjW2pdO1xuXG4gICAgICAgIGlmICghbi5pc0xvY2tlZCkge1xuICAgICAgICAgIG4ucG9zaXRpb25YICs9IHggLSBjLngxO1xuICAgICAgICAgIG4ucG9zaXRpb25ZICs9IHkgLSBjLnkxO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHggKz0gYy53ICsgb3B0aW9ucy5jb21wb25lbnRTcGFjaW5nO1xuICAgICAgdXNlZFcgKz0gYy53ICsgb3B0aW9ucy5jb21wb25lbnRTcGFjaW5nO1xuICAgICAgcm93SCA9IE1hdGgubWF4KHJvd0gsIGMuaCk7XG5cbiAgICAgIGlmICh1c2VkVyA+IG1heFJvd1cpIHtcbiAgICAgICAgeSArPSByb3dIICsgb3B0aW9ucy5jb21wb25lbnRTcGFjaW5nO1xuICAgICAgICB4ID0gMDtcbiAgICAgICAgdXNlZFcgPSAwO1xuICAgICAgICByb3dIID0gMDtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgdmFyIGRlZmF1bHRzJDMgPSB7XG4gICAgZml0OiB0cnVlLFxuICAgIC8vIHdoZXRoZXIgdG8gZml0IHRoZSB2aWV3cG9ydCB0byB0aGUgZ3JhcGhcbiAgICBwYWRkaW5nOiAzMCxcbiAgICAvLyBwYWRkaW5nIHVzZWQgb24gZml0XG4gICAgYm91bmRpbmdCb3g6IHVuZGVmaW5lZCxcbiAgICAvLyBjb25zdHJhaW4gbGF5b3V0IGJvdW5kczsgeyB4MSwgeTEsIHgyLCB5MiB9IG9yIHsgeDEsIHkxLCB3LCBoIH1cbiAgICBhdm9pZE92ZXJsYXA6IHRydWUsXG4gICAgLy8gcHJldmVudHMgbm9kZSBvdmVybGFwLCBtYXkgb3ZlcmZsb3cgYm91bmRpbmdCb3ggaWYgbm90IGVub3VnaCBzcGFjZVxuICAgIGF2b2lkT3ZlcmxhcFBhZGRpbmc6IDEwLFxuICAgIC8vIGV4dHJhIHNwYWNpbmcgYXJvdW5kIG5vZGVzIHdoZW4gYXZvaWRPdmVybGFwOiB0cnVlXG4gICAgbm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzOiBmYWxzZSxcbiAgICAvLyBFeGNsdWRlcyB0aGUgbGFiZWwgd2hlbiBjYWxjdWxhdGluZyBub2RlIGJvdW5kaW5nIGJveGVzIGZvciB0aGUgbGF5b3V0IGFsZ29yaXRobVxuICAgIHNwYWNpbmdGYWN0b3I6IHVuZGVmaW5lZCxcbiAgICAvLyBBcHBsaWVzIGEgbXVsdGlwbGljYXRpdmUgZmFjdG9yICg+MCkgdG8gZXhwYW5kIG9yIGNvbXByZXNzIHRoZSBvdmVyYWxsIGFyZWEgdGhhdCB0aGUgbm9kZXMgdGFrZSB1cFxuICAgIGNvbmRlbnNlOiBmYWxzZSxcbiAgICAvLyB1c2VzIGFsbCBhdmFpbGFibGUgc3BhY2Ugb24gZmFsc2UsIHVzZXMgbWluaW1hbCBzcGFjZSBvbiB0cnVlXG4gICAgcm93czogdW5kZWZpbmVkLFxuICAgIC8vIGZvcmNlIG51bSBvZiByb3dzIGluIHRoZSBncmlkXG4gICAgY29sczogdW5kZWZpbmVkLFxuICAgIC8vIGZvcmNlIG51bSBvZiBjb2x1bW5zIGluIHRoZSBncmlkXG4gICAgcG9zaXRpb246IGZ1bmN0aW9uIHBvc2l0aW9uKG5vZGUpIHt9LFxuICAgIC8vIHJldHVybnMgeyByb3csIGNvbCB9IGZvciBlbGVtZW50XG4gICAgc29ydDogdW5kZWZpbmVkLFxuICAgIC8vIGEgc29ydGluZyBmdW5jdGlvbiB0byBvcmRlciB0aGUgbm9kZXM7IGUuZy4gZnVuY3Rpb24oYSwgYil7IHJldHVybiBhLmRhdGEoJ3dlaWdodCcpIC0gYi5kYXRhKCd3ZWlnaHQnKSB9XG4gICAgYW5pbWF0ZTogZmFsc2UsXG4gICAgLy8gd2hldGhlciB0byB0cmFuc2l0aW9uIHRoZSBub2RlIHBvc2l0aW9uc1xuICAgIGFuaW1hdGlvbkR1cmF0aW9uOiA1MDAsXG4gICAgLy8gZHVyYXRpb24gb2YgYW5pbWF0aW9uIGluIG1zIGlmIGVuYWJsZWRcbiAgICBhbmltYXRpb25FYXNpbmc6IHVuZGVmaW5lZCxcbiAgICAvLyBlYXNpbmcgb2YgYW5pbWF0aW9uIGlmIGVuYWJsZWRcbiAgICBhbmltYXRlRmlsdGVyOiBmdW5jdGlvbiBhbmltYXRlRmlsdGVyKG5vZGUsIGkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG4gICAgLy8gYSBmdW5jdGlvbiB0aGF0IGRldGVybWluZXMgd2hldGhlciB0aGUgbm9kZSBzaG91bGQgYmUgYW5pbWF0ZWQuICBBbGwgbm9kZXMgYW5pbWF0ZWQgYnkgZGVmYXVsdCBvbiBhbmltYXRlIGVuYWJsZWQuICBOb24tYW5pbWF0ZWQgbm9kZXMgYXJlIHBvc2l0aW9uZWQgaW1tZWRpYXRlbHkgd2hlbiB0aGUgbGF5b3V0IHN0YXJ0c1xuICAgIHJlYWR5OiB1bmRlZmluZWQsXG4gICAgLy8gY2FsbGJhY2sgb24gbGF5b3V0cmVhZHlcbiAgICBzdG9wOiB1bmRlZmluZWQsXG4gICAgLy8gY2FsbGJhY2sgb24gbGF5b3V0c3RvcFxuICAgIHRyYW5zZm9ybTogZnVuY3Rpb24gdHJhbnNmb3JtKG5vZGUsIHBvc2l0aW9uKSB7XG4gICAgICByZXR1cm4gcG9zaXRpb247XG4gICAgfSAvLyB0cmFuc2Zvcm0gYSBnaXZlbiBub2RlIHBvc2l0aW9uLiBVc2VmdWwgZm9yIGNoYW5naW5nIGZsb3cgZGlyZWN0aW9uIGluIGRpc2NyZXRlIGxheW91dHMgXG5cbiAgfTtcblxuICBmdW5jdGlvbiBHcmlkTGF5b3V0KG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSBleHRlbmQoe30sIGRlZmF1bHRzJDMsIG9wdGlvbnMpO1xuICB9XG5cbiAgR3JpZExheW91dC5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBwYXJhbXMgPSB0aGlzLm9wdGlvbnM7XG4gICAgdmFyIG9wdGlvbnMgPSBwYXJhbXM7XG4gICAgdmFyIGN5ID0gcGFyYW1zLmN5O1xuICAgIHZhciBlbGVzID0gb3B0aW9ucy5lbGVzO1xuICAgIHZhciBub2RlcyA9IGVsZXMubm9kZXMoKS5ub3QoJzpwYXJlbnQnKTtcblxuICAgIGlmIChvcHRpb25zLnNvcnQpIHtcbiAgICAgIG5vZGVzID0gbm9kZXMuc29ydChvcHRpb25zLnNvcnQpO1xuICAgIH1cblxuICAgIHZhciBiYiA9IG1ha2VCb3VuZGluZ0JveChvcHRpb25zLmJvdW5kaW5nQm94ID8gb3B0aW9ucy5ib3VuZGluZ0JveCA6IHtcbiAgICAgIHgxOiAwLFxuICAgICAgeTE6IDAsXG4gICAgICB3OiBjeS53aWR0aCgpLFxuICAgICAgaDogY3kuaGVpZ2h0KClcbiAgICB9KTtcblxuICAgIGlmIChiYi5oID09PSAwIHx8IGJiLncgPT09IDApIHtcbiAgICAgIGVsZXMubm9kZXMoKS5sYXlvdXRQb3NpdGlvbnModGhpcywgb3B0aW9ucywgZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHg6IGJiLngxLFxuICAgICAgICAgIHk6IGJiLnkxXG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gd2lkdGgvaGVpZ2h0ICogc3BsaXRzXjIgPSBjZWxscyB3aGVyZSBzcGxpdHMgaXMgbnVtYmVyIG9mIHRpbWVzIHRvIHNwbGl0IHdpZHRoXG4gICAgICB2YXIgY2VsbHMgPSBub2Rlcy5zaXplKCk7XG4gICAgICB2YXIgc3BsaXRzID0gTWF0aC5zcXJ0KGNlbGxzICogYmIuaCAvIGJiLncpO1xuICAgICAgdmFyIHJvd3MgPSBNYXRoLnJvdW5kKHNwbGl0cyk7XG4gICAgICB2YXIgY29scyA9IE1hdGgucm91bmQoYmIudyAvIGJiLmggKiBzcGxpdHMpO1xuXG4gICAgICB2YXIgc21hbGwgPSBmdW5jdGlvbiBzbWFsbCh2YWwpIHtcbiAgICAgICAgaWYgKHZhbCA9PSBudWxsKSB7XG4gICAgICAgICAgcmV0dXJuIE1hdGgubWluKHJvd3MsIGNvbHMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhciBtaW4gPSBNYXRoLm1pbihyb3dzLCBjb2xzKTtcblxuICAgICAgICAgIGlmIChtaW4gPT0gcm93cykge1xuICAgICAgICAgICAgcm93cyA9IHZhbDtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29scyA9IHZhbDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIHZhciBsYXJnZSA9IGZ1bmN0aW9uIGxhcmdlKHZhbCkge1xuICAgICAgICBpZiAodmFsID09IG51bGwpIHtcbiAgICAgICAgICByZXR1cm4gTWF0aC5tYXgocm93cywgY29scyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmFyIG1heCA9IE1hdGgubWF4KHJvd3MsIGNvbHMpO1xuXG4gICAgICAgICAgaWYgKG1heCA9PSByb3dzKSB7XG4gICAgICAgICAgICByb3dzID0gdmFsO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb2xzID0gdmFsO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgdmFyIG9Sb3dzID0gb3B0aW9ucy5yb3dzO1xuICAgICAgdmFyIG9Db2xzID0gb3B0aW9ucy5jb2xzICE9IG51bGwgPyBvcHRpb25zLmNvbHMgOiBvcHRpb25zLmNvbHVtbnM7IC8vIGlmIHJvd3Mgb3IgY29sdW1ucyB3ZXJlIHNldCBpbiBvcHRpb25zLCB1c2UgdGhvc2UgdmFsdWVzXG5cbiAgICAgIGlmIChvUm93cyAhPSBudWxsICYmIG9Db2xzICE9IG51bGwpIHtcbiAgICAgICAgcm93cyA9IG9Sb3dzO1xuICAgICAgICBjb2xzID0gb0NvbHM7XG4gICAgICB9IGVsc2UgaWYgKG9Sb3dzICE9IG51bGwgJiYgb0NvbHMgPT0gbnVsbCkge1xuICAgICAgICByb3dzID0gb1Jvd3M7XG4gICAgICAgIGNvbHMgPSBNYXRoLmNlaWwoY2VsbHMgLyByb3dzKTtcbiAgICAgIH0gZWxzZSBpZiAob1Jvd3MgPT0gbnVsbCAmJiBvQ29scyAhPSBudWxsKSB7XG4gICAgICAgIGNvbHMgPSBvQ29scztcbiAgICAgICAgcm93cyA9IE1hdGguY2VpbChjZWxscyAvIGNvbHMpO1xuICAgICAgfSAvLyBvdGhlcndpc2UgdXNlIHRoZSBhdXRvbWF0aWMgdmFsdWVzIGFuZCBhZGp1c3QgYWNjb3JkaW5nbHlcbiAgICAgIC8vIGlmIHJvdW5kaW5nIHdhcyB1cCwgc2VlIGlmIHdlIGNhbiByZWR1Y2Ugcm93cyBvciBjb2x1bW5zXG4gICAgICBlbHNlIGlmIChjb2xzICogcm93cyA+IGNlbGxzKSB7XG4gICAgICAgIHZhciBzbSA9IHNtYWxsKCk7XG4gICAgICAgIHZhciBsZyA9IGxhcmdlKCk7IC8vIHJlZHVjaW5nIHRoZSBzbWFsbCBzaWRlIHRha2VzIGF3YXkgdGhlIG1vc3QgY2VsbHMsIHNvIHRyeSBpdCBmaXJzdFxuXG4gICAgICAgIGlmICgoc20gLSAxKSAqIGxnID49IGNlbGxzKSB7XG4gICAgICAgICAgc21hbGwoc20gLSAxKTtcbiAgICAgICAgfSBlbHNlIGlmICgobGcgLSAxKSAqIHNtID49IGNlbGxzKSB7XG4gICAgICAgICAgbGFyZ2UobGcgLSAxKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gaWYgcm91bmRpbmcgd2FzIHRvbyBsb3csIGFkZCByb3dzIG9yIGNvbHVtbnNcbiAgICAgICAgd2hpbGUgKGNvbHMgKiByb3dzIDwgY2VsbHMpIHtcbiAgICAgICAgICB2YXIgX3NtID0gc21hbGwoKTtcblxuICAgICAgICAgIHZhciBfbGcgPSBsYXJnZSgpOyAvLyB0cnkgdG8gYWRkIHRvIGxhcmdlciBzaWRlIGZpcnN0IChhZGRzIGxlc3MgaW4gbXVsdGlwbGljYXRpb24pXG5cblxuICAgICAgICAgIGlmICgoX2xnICsgMSkgKiBfc20gPj0gY2VsbHMpIHtcbiAgICAgICAgICAgIGxhcmdlKF9sZyArIDEpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzbWFsbChfc20gKyAxKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdmFyIGNlbGxXaWR0aCA9IGJiLncgLyBjb2xzO1xuICAgICAgdmFyIGNlbGxIZWlnaHQgPSBiYi5oIC8gcm93cztcblxuICAgICAgaWYgKG9wdGlvbnMuY29uZGVuc2UpIHtcbiAgICAgICAgY2VsbFdpZHRoID0gMDtcbiAgICAgICAgY2VsbEhlaWdodCA9IDA7XG4gICAgICB9XG5cbiAgICAgIGlmIChvcHRpb25zLmF2b2lkT3ZlcmxhcCkge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgdmFyIG5vZGUgPSBub2Rlc1tpXTtcbiAgICAgICAgICB2YXIgcG9zID0gbm9kZS5fcHJpdmF0ZS5wb3NpdGlvbjtcblxuICAgICAgICAgIGlmIChwb3MueCA9PSBudWxsIHx8IHBvcy55ID09IG51bGwpIHtcbiAgICAgICAgICAgIC8vIGZvciBiYlxuICAgICAgICAgICAgcG9zLnggPSAwO1xuICAgICAgICAgICAgcG9zLnkgPSAwO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHZhciBuYmIgPSBub2RlLmxheW91dERpbWVuc2lvbnMob3B0aW9ucyk7XG4gICAgICAgICAgdmFyIHAgPSBvcHRpb25zLmF2b2lkT3ZlcmxhcFBhZGRpbmc7XG4gICAgICAgICAgdmFyIHcgPSBuYmIudyArIHA7XG4gICAgICAgICAgdmFyIGggPSBuYmIuaCArIHA7XG4gICAgICAgICAgY2VsbFdpZHRoID0gTWF0aC5tYXgoY2VsbFdpZHRoLCB3KTtcbiAgICAgICAgICBjZWxsSGVpZ2h0ID0gTWF0aC5tYXgoY2VsbEhlaWdodCwgaCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdmFyIGNlbGxVc2VkID0ge307IC8vIGUuZy4gJ2MtMC0yJyA9PiB0cnVlXG5cbiAgICAgIHZhciB1c2VkID0gZnVuY3Rpb24gdXNlZChyb3csIGNvbCkge1xuICAgICAgICByZXR1cm4gY2VsbFVzZWRbJ2MtJyArIHJvdyArICctJyArIGNvbF0gPyB0cnVlIDogZmFsc2U7XG4gICAgICB9O1xuXG4gICAgICB2YXIgdXNlID0gZnVuY3Rpb24gdXNlKHJvdywgY29sKSB7XG4gICAgICAgIGNlbGxVc2VkWydjLScgKyByb3cgKyAnLScgKyBjb2xdID0gdHJ1ZTtcbiAgICAgIH07IC8vIHRvIGtlZXAgdHJhY2sgb2YgY3VycmVudCBjZWxsIHBvc2l0aW9uXG5cblxuICAgICAgdmFyIHJvdyA9IDA7XG4gICAgICB2YXIgY29sID0gMDtcblxuICAgICAgdmFyIG1vdmVUb05leHRDZWxsID0gZnVuY3Rpb24gbW92ZVRvTmV4dENlbGwoKSB7XG4gICAgICAgIGNvbCsrO1xuXG4gICAgICAgIGlmIChjb2wgPj0gY29scykge1xuICAgICAgICAgIGNvbCA9IDA7XG4gICAgICAgICAgcm93Kys7XG4gICAgICAgIH1cbiAgICAgIH07IC8vIGdldCBhIGNhY2hlIG9mIGFsbCB0aGUgbWFudWFsIHBvc2l0aW9uc1xuXG5cbiAgICAgIHZhciBpZDJtYW5Qb3MgPSB7fTtcblxuICAgICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IG5vZGVzLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgX25vZGUgPSBub2Rlc1tfaV07XG4gICAgICAgIHZhciByY1BvcyA9IG9wdGlvbnMucG9zaXRpb24oX25vZGUpO1xuXG4gICAgICAgIGlmIChyY1BvcyAmJiAocmNQb3Mucm93ICE9PSB1bmRlZmluZWQgfHwgcmNQb3MuY29sICE9PSB1bmRlZmluZWQpKSB7XG4gICAgICAgICAgLy8gbXVzdCBoYXZlIGF0IGxlYXN0IHJvdyBvciBjb2wgZGVmJ2RcbiAgICAgICAgICB2YXIgX3BvcyA9IHtcbiAgICAgICAgICAgIHJvdzogcmNQb3Mucm93LFxuICAgICAgICAgICAgY29sOiByY1Bvcy5jb2xcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgaWYgKF9wb3MuY29sID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIGZpbmQgdW51c2VkIGNvbFxuICAgICAgICAgICAgX3Bvcy5jb2wgPSAwO1xuXG4gICAgICAgICAgICB3aGlsZSAodXNlZChfcG9zLnJvdywgX3Bvcy5jb2wpKSB7XG4gICAgICAgICAgICAgIF9wb3MuY29sKys7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChfcG9zLnJvdyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAvLyBmaW5kIHVudXNlZCByb3dcbiAgICAgICAgICAgIF9wb3Mucm93ID0gMDtcblxuICAgICAgICAgICAgd2hpbGUgKHVzZWQoX3Bvcy5yb3csIF9wb3MuY29sKSkge1xuICAgICAgICAgICAgICBfcG9zLnJvdysrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlkMm1hblBvc1tfbm9kZS5pZCgpXSA9IF9wb3M7XG4gICAgICAgICAgdXNlKF9wb3Mucm93LCBfcG9zLmNvbCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdmFyIGdldFBvcyA9IGZ1bmN0aW9uIGdldFBvcyhlbGVtZW50LCBpKSB7XG4gICAgICAgIHZhciB4LCB5O1xuXG4gICAgICAgIGlmIChlbGVtZW50LmxvY2tlZCgpIHx8IGVsZW1lbnQuaXNQYXJlbnQoKSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfSAvLyBzZWUgaWYgd2UgaGF2ZSBhIG1hbnVhbCBwb3NpdGlvbiBzZXRcblxuXG4gICAgICAgIHZhciByY1BvcyA9IGlkMm1hblBvc1tlbGVtZW50LmlkKCldO1xuXG4gICAgICAgIGlmIChyY1Bvcykge1xuICAgICAgICAgIHggPSByY1Bvcy5jb2wgKiBjZWxsV2lkdGggKyBjZWxsV2lkdGggLyAyICsgYmIueDE7XG4gICAgICAgICAgeSA9IHJjUG9zLnJvdyAqIGNlbGxIZWlnaHQgKyBjZWxsSGVpZ2h0IC8gMiArIGJiLnkxO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIG90aGVyd2lzZSBzZXQgYXV0b21hdGljYWxseVxuICAgICAgICAgIHdoaWxlICh1c2VkKHJvdywgY29sKSkge1xuICAgICAgICAgICAgbW92ZVRvTmV4dENlbGwoKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB4ID0gY29sICogY2VsbFdpZHRoICsgY2VsbFdpZHRoIC8gMiArIGJiLngxO1xuICAgICAgICAgIHkgPSByb3cgKiBjZWxsSGVpZ2h0ICsgY2VsbEhlaWdodCAvIDIgKyBiYi55MTtcbiAgICAgICAgICB1c2Uocm93LCBjb2wpO1xuICAgICAgICAgIG1vdmVUb05leHRDZWxsKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHg6IHgsXG4gICAgICAgICAgeTogeVxuICAgICAgICB9O1xuICAgICAgfTtcblxuICAgICAgbm9kZXMubGF5b3V0UG9zaXRpb25zKHRoaXMsIG9wdGlvbnMsIGdldFBvcyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gIH07XG5cbiAgdmFyIGRlZmF1bHRzJDIgPSB7XG4gICAgcmVhZHk6IGZ1bmN0aW9uIHJlYWR5KCkge30sXG4gICAgLy8gb24gbGF5b3V0cmVhZHlcbiAgICBzdG9wOiBmdW5jdGlvbiBzdG9wKCkge30gLy8gb24gbGF5b3V0c3RvcFxuXG4gIH07IC8vIGNvbnN0cnVjdG9yXG4gIC8vIG9wdGlvbnMgOiBvYmplY3QgY29udGFpbmluZyBsYXlvdXQgb3B0aW9uc1xuXG4gIGZ1bmN0aW9uIE51bGxMYXlvdXQob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IGV4dGVuZCh7fSwgZGVmYXVsdHMkMiwgb3B0aW9ucyk7XG4gIH0gLy8gcnVucyB0aGUgbGF5b3V0XG5cblxuICBOdWxsTGF5b3V0LnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG4gICAgdmFyIGVsZXMgPSBvcHRpb25zLmVsZXM7IC8vIGVsZW1lbnRzIHRvIGNvbnNpZGVyIGluIHRoZSBsYXlvdXRcblxuICAgIHZhciBsYXlvdXQgPSB0aGlzOyAvLyBjeSBpcyBhdXRvbWF0aWNhbGx5IHBvcHVsYXRlZCBmb3IgdXMgaW4gdGhlIGNvbnN0cnVjdG9yXG4gICAgLy8gKGRpc2FibGUgZXNsaW50IGZvciBuZXh0IGxpbmUgYXMgdGhpcyBzZXJ2ZXMgYXMgZXhhbXBsZSBsYXlvdXQgY29kZSB0byBleHRlcm5hbCBkZXZlbG9wZXJzKVxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bnVzZWQtdmFyc1xuXG4gICAgb3B0aW9ucy5jeTtcbiAgICBsYXlvdXQuZW1pdCgnbGF5b3V0c3RhcnQnKTsgLy8gcHV0cyBhbGwgbm9kZXMgYXQgKDAsIDApXG4gICAgLy8gbi5iLiBtb3N0IGxheW91dHMgd291bGQgdXNlIGxheW91dFBvc2l0aW9ucygpLCBpbnN0ZWFkIG9mIHBvc2l0aW9ucygpIGFuZCBtYW51YWwgZXZlbnRzXG5cbiAgICBlbGVzLm5vZGVzKCkucG9zaXRpb25zKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHg6IDAsXG4gICAgICAgIHk6IDBcbiAgICAgIH07XG4gICAgfSk7IC8vIHRyaWdnZXIgbGF5b3V0cmVhZHkgd2hlbiBlYWNoIG5vZGUgaGFzIGhhZCBpdHMgcG9zaXRpb24gc2V0IGF0IGxlYXN0IG9uY2VcblxuICAgIGxheW91dC5vbmUoJ2xheW91dHJlYWR5Jywgb3B0aW9ucy5yZWFkeSk7XG4gICAgbGF5b3V0LmVtaXQoJ2xheW91dHJlYWR5Jyk7IC8vIHRyaWdnZXIgbGF5b3V0c3RvcCB3aGVuIHRoZSBsYXlvdXQgc3RvcHMgKGUuZy4gZmluaXNoZXMpXG5cbiAgICBsYXlvdXQub25lKCdsYXlvdXRzdG9wJywgb3B0aW9ucy5zdG9wKTtcbiAgICBsYXlvdXQuZW1pdCgnbGF5b3V0c3RvcCcpO1xuICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICB9OyAvLyBjYWxsZWQgb24gY29udGludW91cyBsYXlvdXRzIHRvIHN0b3AgdGhlbSBiZWZvcmUgdGhleSBmaW5pc2hcblxuXG4gIE51bGxMYXlvdXQucHJvdG90eXBlLnN0b3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gIH07XG5cbiAgdmFyIGRlZmF1bHRzJDEgPSB7XG4gICAgcG9zaXRpb25zOiB1bmRlZmluZWQsXG4gICAgLy8gbWFwIG9mIChub2RlIGlkKSA9PiAocG9zaXRpb24gb2JqKTsgb3IgZnVuY3Rpb24obm9kZSl7IHJldHVybiBzb21Qb3M7IH1cbiAgICB6b29tOiB1bmRlZmluZWQsXG4gICAgLy8gdGhlIHpvb20gbGV2ZWwgdG8gc2V0IChwcm9iIHdhbnQgZml0ID0gZmFsc2UgaWYgc2V0KVxuICAgIHBhbjogdW5kZWZpbmVkLFxuICAgIC8vIHRoZSBwYW4gbGV2ZWwgdG8gc2V0IChwcm9iIHdhbnQgZml0ID0gZmFsc2UgaWYgc2V0KVxuICAgIGZpdDogdHJ1ZSxcbiAgICAvLyB3aGV0aGVyIHRvIGZpdCB0byB2aWV3cG9ydFxuICAgIHBhZGRpbmc6IDMwLFxuICAgIC8vIHBhZGRpbmcgb24gZml0XG4gICAgYW5pbWF0ZTogZmFsc2UsXG4gICAgLy8gd2hldGhlciB0byB0cmFuc2l0aW9uIHRoZSBub2RlIHBvc2l0aW9uc1xuICAgIGFuaW1hdGlvbkR1cmF0aW9uOiA1MDAsXG4gICAgLy8gZHVyYXRpb24gb2YgYW5pbWF0aW9uIGluIG1zIGlmIGVuYWJsZWRcbiAgICBhbmltYXRpb25FYXNpbmc6IHVuZGVmaW5lZCxcbiAgICAvLyBlYXNpbmcgb2YgYW5pbWF0aW9uIGlmIGVuYWJsZWRcbiAgICBhbmltYXRlRmlsdGVyOiBmdW5jdGlvbiBhbmltYXRlRmlsdGVyKG5vZGUsIGkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG4gICAgLy8gYSBmdW5jdGlvbiB0aGF0IGRldGVybWluZXMgd2hldGhlciB0aGUgbm9kZSBzaG91bGQgYmUgYW5pbWF0ZWQuICBBbGwgbm9kZXMgYW5pbWF0ZWQgYnkgZGVmYXVsdCBvbiBhbmltYXRlIGVuYWJsZWQuICBOb24tYW5pbWF0ZWQgbm9kZXMgYXJlIHBvc2l0aW9uZWQgaW1tZWRpYXRlbHkgd2hlbiB0aGUgbGF5b3V0IHN0YXJ0c1xuICAgIHJlYWR5OiB1bmRlZmluZWQsXG4gICAgLy8gY2FsbGJhY2sgb24gbGF5b3V0cmVhZHlcbiAgICBzdG9wOiB1bmRlZmluZWQsXG4gICAgLy8gY2FsbGJhY2sgb24gbGF5b3V0c3RvcFxuICAgIHRyYW5zZm9ybTogZnVuY3Rpb24gdHJhbnNmb3JtKG5vZGUsIHBvc2l0aW9uKSB7XG4gICAgICByZXR1cm4gcG9zaXRpb247XG4gICAgfSAvLyB0cmFuc2Zvcm0gYSBnaXZlbiBub2RlIHBvc2l0aW9uLiBVc2VmdWwgZm9yIGNoYW5naW5nIGZsb3cgZGlyZWN0aW9uIGluIGRpc2NyZXRlIGxheW91dHNcblxuICB9O1xuXG4gIGZ1bmN0aW9uIFByZXNldExheW91dChvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gZXh0ZW5kKHt9LCBkZWZhdWx0cyQxLCBvcHRpb25zKTtcbiAgfVxuXG4gIFByZXNldExheW91dC5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuICAgIHZhciBlbGVzID0gb3B0aW9ucy5lbGVzO1xuICAgIHZhciBub2RlcyA9IGVsZXMubm9kZXMoKTtcbiAgICB2YXIgcG9zSXNGbiA9IGZuJDYob3B0aW9ucy5wb3NpdGlvbnMpO1xuXG4gICAgZnVuY3Rpb24gZ2V0UG9zaXRpb24obm9kZSkge1xuICAgICAgaWYgKG9wdGlvbnMucG9zaXRpb25zID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIGNvcHlQb3NpdGlvbihub2RlLnBvc2l0aW9uKCkpO1xuICAgICAgfVxuXG4gICAgICBpZiAocG9zSXNGbikge1xuICAgICAgICByZXR1cm4gb3B0aW9ucy5wb3NpdGlvbnMobm9kZSk7XG4gICAgICB9XG5cbiAgICAgIHZhciBwb3MgPSBvcHRpb25zLnBvc2l0aW9uc1tub2RlLl9wcml2YXRlLmRhdGEuaWRdO1xuXG4gICAgICBpZiAocG9zID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBwb3M7XG4gICAgfVxuXG4gICAgbm9kZXMubGF5b3V0UG9zaXRpb25zKHRoaXMsIG9wdGlvbnMsIGZ1bmN0aW9uIChub2RlLCBpKSB7XG4gICAgICB2YXIgcG9zaXRpb24gPSBnZXRQb3NpdGlvbihub2RlKTtcblxuICAgICAgaWYgKG5vZGUubG9ja2VkKCkgfHwgcG9zaXRpb24gPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBwb3NpdGlvbjtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgfTtcblxuICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgZml0OiB0cnVlLFxuICAgIC8vIHdoZXRoZXIgdG8gZml0IHRvIHZpZXdwb3J0XG4gICAgcGFkZGluZzogMzAsXG4gICAgLy8gZml0IHBhZGRpbmdcbiAgICBib3VuZGluZ0JveDogdW5kZWZpbmVkLFxuICAgIC8vIGNvbnN0cmFpbiBsYXlvdXQgYm91bmRzOyB7IHgxLCB5MSwgeDIsIHkyIH0gb3IgeyB4MSwgeTEsIHcsIGggfVxuICAgIGFuaW1hdGU6IGZhbHNlLFxuICAgIC8vIHdoZXRoZXIgdG8gdHJhbnNpdGlvbiB0aGUgbm9kZSBwb3NpdGlvbnNcbiAgICBhbmltYXRpb25EdXJhdGlvbjogNTAwLFxuICAgIC8vIGR1cmF0aW9uIG9mIGFuaW1hdGlvbiBpbiBtcyBpZiBlbmFibGVkXG4gICAgYW5pbWF0aW9uRWFzaW5nOiB1bmRlZmluZWQsXG4gICAgLy8gZWFzaW5nIG9mIGFuaW1hdGlvbiBpZiBlbmFibGVkXG4gICAgYW5pbWF0ZUZpbHRlcjogZnVuY3Rpb24gYW5pbWF0ZUZpbHRlcihub2RlLCBpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuICAgIC8vIGEgZnVuY3Rpb24gdGhhdCBkZXRlcm1pbmVzIHdoZXRoZXIgdGhlIG5vZGUgc2hvdWxkIGJlIGFuaW1hdGVkLiAgQWxsIG5vZGVzIGFuaW1hdGVkIGJ5IGRlZmF1bHQgb24gYW5pbWF0ZSBlbmFibGVkLiAgTm9uLWFuaW1hdGVkIG5vZGVzIGFyZSBwb3NpdGlvbmVkIGltbWVkaWF0ZWx5IHdoZW4gdGhlIGxheW91dCBzdGFydHNcbiAgICByZWFkeTogdW5kZWZpbmVkLFxuICAgIC8vIGNhbGxiYWNrIG9uIGxheW91dHJlYWR5XG4gICAgc3RvcDogdW5kZWZpbmVkLFxuICAgIC8vIGNhbGxiYWNrIG9uIGxheW91dHN0b3BcbiAgICB0cmFuc2Zvcm06IGZ1bmN0aW9uIHRyYW5zZm9ybShub2RlLCBwb3NpdGlvbikge1xuICAgICAgcmV0dXJuIHBvc2l0aW9uO1xuICAgIH0gLy8gdHJhbnNmb3JtIGEgZ2l2ZW4gbm9kZSBwb3NpdGlvbi4gVXNlZnVsIGZvciBjaGFuZ2luZyBmbG93IGRpcmVjdGlvbiBpbiBkaXNjcmV0ZSBsYXlvdXRzIFxuXG4gIH07XG5cbiAgZnVuY3Rpb24gUmFuZG9tTGF5b3V0KG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSBleHRlbmQoe30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgfVxuXG4gIFJhbmRvbUxheW91dC5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuICAgIHZhciBjeSA9IG9wdGlvbnMuY3k7XG4gICAgdmFyIGVsZXMgPSBvcHRpb25zLmVsZXM7XG4gICAgdmFyIGJiID0gbWFrZUJvdW5kaW5nQm94KG9wdGlvbnMuYm91bmRpbmdCb3ggPyBvcHRpb25zLmJvdW5kaW5nQm94IDoge1xuICAgICAgeDE6IDAsXG4gICAgICB5MTogMCxcbiAgICAgIHc6IGN5LndpZHRoKCksXG4gICAgICBoOiBjeS5oZWlnaHQoKVxuICAgIH0pO1xuXG4gICAgdmFyIGdldFBvcyA9IGZ1bmN0aW9uIGdldFBvcyhub2RlLCBpKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB4OiBiYi54MSArIE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIGJiLncpLFxuICAgICAgICB5OiBiYi55MSArIE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIGJiLmgpXG4gICAgICB9O1xuICAgIH07XG5cbiAgICBlbGVzLm5vZGVzKCkubGF5b3V0UG9zaXRpb25zKHRoaXMsIG9wdGlvbnMsIGdldFBvcyk7XG4gICAgcmV0dXJuIHRoaXM7IC8vIGNoYWluaW5nXG4gIH07XG5cbiAgdmFyIGxheW91dCA9IFt7XG4gICAgbmFtZTogJ2JyZWFkdGhmaXJzdCcsXG4gICAgaW1wbDogQnJlYWR0aEZpcnN0TGF5b3V0XG4gIH0sIHtcbiAgICBuYW1lOiAnY2lyY2xlJyxcbiAgICBpbXBsOiBDaXJjbGVMYXlvdXRcbiAgfSwge1xuICAgIG5hbWU6ICdjb25jZW50cmljJyxcbiAgICBpbXBsOiBDb25jZW50cmljTGF5b3V0XG4gIH0sIHtcbiAgICBuYW1lOiAnY29zZScsXG4gICAgaW1wbDogQ29zZUxheW91dFxuICB9LCB7XG4gICAgbmFtZTogJ2dyaWQnLFxuICAgIGltcGw6IEdyaWRMYXlvdXRcbiAgfSwge1xuICAgIG5hbWU6ICdudWxsJyxcbiAgICBpbXBsOiBOdWxsTGF5b3V0XG4gIH0sIHtcbiAgICBuYW1lOiAncHJlc2V0JyxcbiAgICBpbXBsOiBQcmVzZXRMYXlvdXRcbiAgfSwge1xuICAgIG5hbWU6ICdyYW5kb20nLFxuICAgIGltcGw6IFJhbmRvbUxheW91dFxuICB9XTtcblxuICBmdW5jdGlvbiBOdWxsUmVuZGVyZXIob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5ub3RpZmljYXRpb25zID0gMDsgLy8gZm9yIHRlc3RpbmdcbiAgfVxuXG4gIHZhciBub29wID0gZnVuY3Rpb24gbm9vcCgpIHt9O1xuXG4gIHZhciB0aHJvd0ltZ0VyciA9IGZ1bmN0aW9uIHRocm93SW1nRXJyKCkge1xuICAgIHRocm93IG5ldyBFcnJvcignQSBoZWFkbGVzcyBpbnN0YW5jZSBjYW4gbm90IHJlbmRlciBpbWFnZXMnKTtcbiAgfTtcblxuICBOdWxsUmVuZGVyZXIucHJvdG90eXBlID0ge1xuICAgIHJlY2FsY3VsYXRlUmVuZGVyZWRTdHlsZTogbm9vcCxcbiAgICBub3RpZnk6IGZ1bmN0aW9uIG5vdGlmeSgpIHtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9ucysrO1xuICAgIH0sXG4gICAgaW5pdDogbm9vcCxcbiAgICBpc0hlYWRsZXNzOiBmdW5jdGlvbiBpc0hlYWRsZXNzKCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSxcbiAgICBwbmc6IHRocm93SW1nRXJyLFxuICAgIGpwZzogdGhyb3dJbWdFcnJcbiAgfTtcblxuICB2YXIgQlJwJGYgPSB7fTtcbiAgQlJwJGYuYXJyb3dTaGFwZVdpZHRoID0gMC4zO1xuXG4gIEJScCRmLnJlZ2lzdGVyQXJyb3dTaGFwZXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGFycm93U2hhcGVzID0gdGhpcy5hcnJvd1NoYXBlcyA9IHt9O1xuICAgIHZhciByZW5kZXJlciA9IHRoaXM7IC8vIENvbnRyYWN0IGZvciBhcnJvdyBzaGFwZXM6XG4gICAgLy8gMCwgMCBpcyBhcnJvdyB0aXBcbiAgICAvLyAoMCwgMSkgaXMgZGlyZWN0aW9uIHRvd2FyZHMgbm9kZVxuICAgIC8vICgxLCAwKSBpcyByaWdodFxuICAgIC8vXG4gICAgLy8gZnVuY3Rpb25hbCBhcGk6XG4gICAgLy8gY29sbGlkZTogY2hlY2sgeCwgeSBpbiBzaGFwZVxuICAgIC8vIHJvdWdoQ29sbGlkZTogY2FsbGVkIGJlZm9yZSBjb2xsaWRlLCBubyBmYWxzZSBuZWdhdGl2ZXNcbiAgICAvLyBkcmF3OiBkcmF3XG4gICAgLy8gc3BhY2luZzogZGlzdChhcnJvd1RpcCwgbm9kZUJvdW5kYXJ5KVxuICAgIC8vIGdhcDogZGlzdChlZGdlVGlwLCBub2RlQm91bmRhcnkpLCBlZGdlVGlwIG1heSAhPSBhcnJvd1RpcFxuXG4gICAgdmFyIGJiQ29sbGlkZSA9IGZ1bmN0aW9uIGJiQ29sbGlkZSh4LCB5LCBzaXplLCBhbmdsZSwgdHJhbnNsYXRpb24sIGVkZ2VXaWR0aCwgcGFkZGluZykge1xuICAgICAgdmFyIHgxID0gdHJhbnNsYXRpb24ueCAtIHNpemUgLyAyIC0gcGFkZGluZztcbiAgICAgIHZhciB4MiA9IHRyYW5zbGF0aW9uLnggKyBzaXplIC8gMiArIHBhZGRpbmc7XG4gICAgICB2YXIgeTEgPSB0cmFuc2xhdGlvbi55IC0gc2l6ZSAvIDIgLSBwYWRkaW5nO1xuICAgICAgdmFyIHkyID0gdHJhbnNsYXRpb24ueSArIHNpemUgLyAyICsgcGFkZGluZztcbiAgICAgIHZhciBpbnNpZGUgPSB4MSA8PSB4ICYmIHggPD0geDIgJiYgeTEgPD0geSAmJiB5IDw9IHkyO1xuICAgICAgcmV0dXJuIGluc2lkZTtcbiAgICB9O1xuXG4gICAgdmFyIHRyYW5zZm9ybSA9IGZ1bmN0aW9uIHRyYW5zZm9ybSh4LCB5LCBzaXplLCBhbmdsZSwgdHJhbnNsYXRpb24pIHtcbiAgICAgIHZhciB4Um90YXRlZCA9IHggKiBNYXRoLmNvcyhhbmdsZSkgLSB5ICogTWF0aC5zaW4oYW5nbGUpO1xuICAgICAgdmFyIHlSb3RhdGVkID0geCAqIE1hdGguc2luKGFuZ2xlKSArIHkgKiBNYXRoLmNvcyhhbmdsZSk7XG4gICAgICB2YXIgeFNjYWxlZCA9IHhSb3RhdGVkICogc2l6ZTtcbiAgICAgIHZhciB5U2NhbGVkID0geVJvdGF0ZWQgKiBzaXplO1xuICAgICAgdmFyIHhUcmFuc2xhdGVkID0geFNjYWxlZCArIHRyYW5zbGF0aW9uLng7XG4gICAgICB2YXIgeVRyYW5zbGF0ZWQgPSB5U2NhbGVkICsgdHJhbnNsYXRpb24ueTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHg6IHhUcmFuc2xhdGVkLFxuICAgICAgICB5OiB5VHJhbnNsYXRlZFxuICAgICAgfTtcbiAgICB9O1xuXG4gICAgdmFyIHRyYW5zZm9ybVBvaW50cyA9IGZ1bmN0aW9uIHRyYW5zZm9ybVBvaW50cyhwdHMsIHNpemUsIGFuZ2xlLCB0cmFuc2xhdGlvbikge1xuICAgICAgdmFyIHJldFB0cyA9IFtdO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHB0cy5sZW5ndGg7IGkgKz0gMikge1xuICAgICAgICB2YXIgeCA9IHB0c1tpXTtcbiAgICAgICAgdmFyIHkgPSBwdHNbaSArIDFdO1xuICAgICAgICByZXRQdHMucHVzaCh0cmFuc2Zvcm0oeCwgeSwgc2l6ZSwgYW5nbGUsIHRyYW5zbGF0aW9uKSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZXRQdHM7XG4gICAgfTtcblxuICAgIHZhciBwb2ludHNUb0FyciA9IGZ1bmN0aW9uIHBvaW50c1RvQXJyKHB0cykge1xuICAgICAgdmFyIHJldCA9IFtdO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHB0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgcCA9IHB0c1tpXTtcbiAgICAgICAgcmV0LnB1c2gocC54LCBwLnkpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gcmV0O1xuICAgIH07XG5cbiAgICB2YXIgc3RhbmRhcmRHYXAgPSBmdW5jdGlvbiBzdGFuZGFyZEdhcChlZGdlKSB7XG4gICAgICByZXR1cm4gZWRnZS5wc3R5bGUoJ3dpZHRoJykucGZWYWx1ZSAqIGVkZ2UucHN0eWxlKCdhcnJvdy1zY2FsZScpLnBmVmFsdWUgKiAyO1xuICAgIH07XG5cbiAgICB2YXIgZGVmaW5lQXJyb3dTaGFwZSA9IGZ1bmN0aW9uIGRlZmluZUFycm93U2hhcGUobmFtZSwgZGVmbikge1xuICAgICAgaWYgKHN0cmluZyhkZWZuKSkge1xuICAgICAgICBkZWZuID0gYXJyb3dTaGFwZXNbZGVmbl07XG4gICAgICB9XG5cbiAgICAgIGFycm93U2hhcGVzW25hbWVdID0gZXh0ZW5kKHtcbiAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgcG9pbnRzOiBbLTAuMTUsIC0wLjMsIDAuMTUsIC0wLjMsIDAuMTUsIDAuMywgLTAuMTUsIDAuM10sXG4gICAgICAgIGNvbGxpZGU6IGZ1bmN0aW9uIGNvbGxpZGUoeCwgeSwgc2l6ZSwgYW5nbGUsIHRyYW5zbGF0aW9uLCBwYWRkaW5nKSB7XG4gICAgICAgICAgdmFyIHBvaW50cyA9IHBvaW50c1RvQXJyKHRyYW5zZm9ybVBvaW50cyh0aGlzLnBvaW50cywgc2l6ZSArIDIgKiBwYWRkaW5nLCBhbmdsZSwgdHJhbnNsYXRpb24pKTtcbiAgICAgICAgICB2YXIgaW5zaWRlID0gcG9pbnRJbnNpZGVQb2x5Z29uUG9pbnRzKHgsIHksIHBvaW50cyk7XG4gICAgICAgICAgcmV0dXJuIGluc2lkZTtcbiAgICAgICAgfSxcbiAgICAgICAgcm91Z2hDb2xsaWRlOiBiYkNvbGxpZGUsXG4gICAgICAgIGRyYXc6IGZ1bmN0aW9uIGRyYXcoY29udGV4dCwgc2l6ZSwgYW5nbGUsIHRyYW5zbGF0aW9uKSB7XG4gICAgICAgICAgdmFyIHBvaW50cyA9IHRyYW5zZm9ybVBvaW50cyh0aGlzLnBvaW50cywgc2l6ZSwgYW5nbGUsIHRyYW5zbGF0aW9uKTtcbiAgICAgICAgICByZW5kZXJlci5hcnJvd1NoYXBlSW1wbCgncG9seWdvbicpKGNvbnRleHQsIHBvaW50cyk7XG4gICAgICAgIH0sXG4gICAgICAgIHNwYWNpbmc6IGZ1bmN0aW9uIHNwYWNpbmcoZWRnZSkge1xuICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9LFxuICAgICAgICBnYXA6IHN0YW5kYXJkR2FwXG4gICAgICB9LCBkZWZuKTtcbiAgICB9O1xuXG4gICAgZGVmaW5lQXJyb3dTaGFwZSgnbm9uZScsIHtcbiAgICAgIGNvbGxpZGU6IGZhbHNpZnksXG4gICAgICByb3VnaENvbGxpZGU6IGZhbHNpZnksXG4gICAgICBkcmF3OiBub29wJDEsXG4gICAgICBzcGFjaW5nOiB6ZXJvaWZ5LFxuICAgICAgZ2FwOiB6ZXJvaWZ5XG4gICAgfSk7XG4gICAgZGVmaW5lQXJyb3dTaGFwZSgndHJpYW5nbGUnLCB7XG4gICAgICBwb2ludHM6IFstMC4xNSwgLTAuMywgMCwgMCwgMC4xNSwgLTAuM11cbiAgICB9KTtcbiAgICBkZWZpbmVBcnJvd1NoYXBlKCdhcnJvdycsICd0cmlhbmdsZScpO1xuICAgIGRlZmluZUFycm93U2hhcGUoJ3RyaWFuZ2xlLWJhY2tjdXJ2ZScsIHtcbiAgICAgIHBvaW50czogYXJyb3dTaGFwZXNbJ3RyaWFuZ2xlJ10ucG9pbnRzLFxuICAgICAgY29udHJvbFBvaW50OiBbMCwgLTAuMTVdLFxuICAgICAgcm91Z2hDb2xsaWRlOiBiYkNvbGxpZGUsXG4gICAgICBkcmF3OiBmdW5jdGlvbiBkcmF3KGNvbnRleHQsIHNpemUsIGFuZ2xlLCB0cmFuc2xhdGlvbiwgZWRnZVdpZHRoKSB7XG4gICAgICAgIHZhciBwdHNUcmFucyA9IHRyYW5zZm9ybVBvaW50cyh0aGlzLnBvaW50cywgc2l6ZSwgYW5nbGUsIHRyYW5zbGF0aW9uKTtcbiAgICAgICAgdmFyIGN0cmxQdCA9IHRoaXMuY29udHJvbFBvaW50O1xuICAgICAgICB2YXIgY3RybFB0VHJhbnMgPSB0cmFuc2Zvcm0oY3RybFB0WzBdLCBjdHJsUHRbMV0sIHNpemUsIGFuZ2xlLCB0cmFuc2xhdGlvbik7XG4gICAgICAgIHJlbmRlcmVyLmFycm93U2hhcGVJbXBsKHRoaXMubmFtZSkoY29udGV4dCwgcHRzVHJhbnMsIGN0cmxQdFRyYW5zKTtcbiAgICAgIH0sXG4gICAgICBnYXA6IGZ1bmN0aW9uIGdhcChlZGdlKSB7XG4gICAgICAgIHJldHVybiBzdGFuZGFyZEdhcChlZGdlKSAqIDAuODtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBkZWZpbmVBcnJvd1NoYXBlKCd0cmlhbmdsZS10ZWUnLCB7XG4gICAgICBwb2ludHM6IFswLCAwLCAwLjE1LCAtMC4zLCAtMC4xNSwgLTAuMywgMCwgMF0sXG4gICAgICBwb2ludHNUZWU6IFstMC4xNSwgLTAuNCwgLTAuMTUsIC0wLjUsIDAuMTUsIC0wLjUsIDAuMTUsIC0wLjRdLFxuICAgICAgY29sbGlkZTogZnVuY3Rpb24gY29sbGlkZSh4LCB5LCBzaXplLCBhbmdsZSwgdHJhbnNsYXRpb24sIGVkZ2VXaWR0aCwgcGFkZGluZykge1xuICAgICAgICB2YXIgdHJpUHRzID0gcG9pbnRzVG9BcnIodHJhbnNmb3JtUG9pbnRzKHRoaXMucG9pbnRzLCBzaXplICsgMiAqIHBhZGRpbmcsIGFuZ2xlLCB0cmFuc2xhdGlvbikpO1xuICAgICAgICB2YXIgdGVlUHRzID0gcG9pbnRzVG9BcnIodHJhbnNmb3JtUG9pbnRzKHRoaXMucG9pbnRzVGVlLCBzaXplICsgMiAqIHBhZGRpbmcsIGFuZ2xlLCB0cmFuc2xhdGlvbikpO1xuICAgICAgICB2YXIgaW5zaWRlID0gcG9pbnRJbnNpZGVQb2x5Z29uUG9pbnRzKHgsIHksIHRyaVB0cykgfHwgcG9pbnRJbnNpZGVQb2x5Z29uUG9pbnRzKHgsIHksIHRlZVB0cyk7XG4gICAgICAgIHJldHVybiBpbnNpZGU7XG4gICAgICB9LFxuICAgICAgZHJhdzogZnVuY3Rpb24gZHJhdyhjb250ZXh0LCBzaXplLCBhbmdsZSwgdHJhbnNsYXRpb24sIGVkZ2VXaWR0aCkge1xuICAgICAgICB2YXIgdHJpUHRzID0gdHJhbnNmb3JtUG9pbnRzKHRoaXMucG9pbnRzLCBzaXplLCBhbmdsZSwgdHJhbnNsYXRpb24pO1xuICAgICAgICB2YXIgdGVlUHRzID0gdHJhbnNmb3JtUG9pbnRzKHRoaXMucG9pbnRzVGVlLCBzaXplLCBhbmdsZSwgdHJhbnNsYXRpb24pO1xuICAgICAgICByZW5kZXJlci5hcnJvd1NoYXBlSW1wbCh0aGlzLm5hbWUpKGNvbnRleHQsIHRyaVB0cywgdGVlUHRzKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBkZWZpbmVBcnJvd1NoYXBlKCdjaXJjbGUtdHJpYW5nbGUnLCB7XG4gICAgICByYWRpdXM6IDAuMTUsXG4gICAgICBwb2ludHNUcjogWzAsIC0wLjE1LCAwLjE1LCAtMC40NSwgLTAuMTUsIC0wLjQ1LCAwLCAtMC4xNV0sXG4gICAgICBjb2xsaWRlOiBmdW5jdGlvbiBjb2xsaWRlKHgsIHksIHNpemUsIGFuZ2xlLCB0cmFuc2xhdGlvbiwgZWRnZVdpZHRoLCBwYWRkaW5nKSB7XG4gICAgICAgIHZhciB0ID0gdHJhbnNsYXRpb247XG4gICAgICAgIHZhciBjaXJjbGVJbnNpZGUgPSBNYXRoLnBvdyh0LnggLSB4LCAyKSArIE1hdGgucG93KHQueSAtIHksIDIpIDw9IE1hdGgucG93KChzaXplICsgMiAqIHBhZGRpbmcpICogdGhpcy5yYWRpdXMsIDIpO1xuICAgICAgICB2YXIgdHJpUHRzID0gcG9pbnRzVG9BcnIodHJhbnNmb3JtUG9pbnRzKHRoaXMucG9pbnRzLCBzaXplICsgMiAqIHBhZGRpbmcsIGFuZ2xlLCB0cmFuc2xhdGlvbikpO1xuICAgICAgICByZXR1cm4gcG9pbnRJbnNpZGVQb2x5Z29uUG9pbnRzKHgsIHksIHRyaVB0cykgfHwgY2lyY2xlSW5zaWRlO1xuICAgICAgfSxcbiAgICAgIGRyYXc6IGZ1bmN0aW9uIGRyYXcoY29udGV4dCwgc2l6ZSwgYW5nbGUsIHRyYW5zbGF0aW9uLCBlZGdlV2lkdGgpIHtcbiAgICAgICAgdmFyIHRyaVB0cyA9IHRyYW5zZm9ybVBvaW50cyh0aGlzLnBvaW50c1RyLCBzaXplLCBhbmdsZSwgdHJhbnNsYXRpb24pO1xuICAgICAgICByZW5kZXJlci5hcnJvd1NoYXBlSW1wbCh0aGlzLm5hbWUpKGNvbnRleHQsIHRyaVB0cywgdHJhbnNsYXRpb24ueCwgdHJhbnNsYXRpb24ueSwgdGhpcy5yYWRpdXMgKiBzaXplKTtcbiAgICAgIH0sXG4gICAgICBzcGFjaW5nOiBmdW5jdGlvbiBzcGFjaW5nKGVkZ2UpIHtcbiAgICAgICAgcmV0dXJuIHJlbmRlcmVyLmdldEFycm93V2lkdGgoZWRnZS5wc3R5bGUoJ3dpZHRoJykucGZWYWx1ZSwgZWRnZS5wc3R5bGUoJ2Fycm93LXNjYWxlJykudmFsdWUpICogdGhpcy5yYWRpdXM7XG4gICAgICB9XG4gICAgfSk7XG4gICAgZGVmaW5lQXJyb3dTaGFwZSgndHJpYW5nbGUtY3Jvc3MnLCB7XG4gICAgICBwb2ludHM6IFswLCAwLCAwLjE1LCAtMC4zLCAtMC4xNSwgLTAuMywgMCwgMF0sXG4gICAgICBiYXNlQ3Jvc3NMaW5lUHRzOiBbLTAuMTUsIC0wLjQsIC8vIGZpcnN0IGhhbGYgb2YgdGhlIHJlY3RhbmdsZVxuICAgICAgLTAuMTUsIC0wLjQsIDAuMTUsIC0wLjQsIC8vIHNlY29uZCBoYWxmIG9mIHRoZSByZWN0YW5nbGVcbiAgICAgIDAuMTUsIC0wLjRdLFxuICAgICAgY3Jvc3NMaW5lUHRzOiBmdW5jdGlvbiBjcm9zc0xpbmVQdHMoc2l6ZSwgZWRnZVdpZHRoKSB7XG4gICAgICAgIC8vIHNoaWZ0IHBvaW50cyBzbyB0aGF0IHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHRoZSBjcm9zcyBwb2ludHMgbWF0Y2hlcyBlZGdlIHdpZHRoXG4gICAgICAgIHZhciBwID0gdGhpcy5iYXNlQ3Jvc3NMaW5lUHRzLnNsaWNlKCk7XG4gICAgICAgIHZhciBzaGlmdEZhY3RvciA9IGVkZ2VXaWR0aCAvIHNpemU7XG4gICAgICAgIHZhciB5MCA9IDM7XG4gICAgICAgIHZhciB5MSA9IDU7XG4gICAgICAgIHBbeTBdID0gcFt5MF0gLSBzaGlmdEZhY3RvcjtcbiAgICAgICAgcFt5MV0gPSBwW3kxXSAtIHNoaWZ0RmFjdG9yO1xuICAgICAgICByZXR1cm4gcDtcbiAgICAgIH0sXG4gICAgICBjb2xsaWRlOiBmdW5jdGlvbiBjb2xsaWRlKHgsIHksIHNpemUsIGFuZ2xlLCB0cmFuc2xhdGlvbiwgZWRnZVdpZHRoLCBwYWRkaW5nKSB7XG4gICAgICAgIHZhciB0cmlQdHMgPSBwb2ludHNUb0Fycih0cmFuc2Zvcm1Qb2ludHModGhpcy5wb2ludHMsIHNpemUgKyAyICogcGFkZGluZywgYW5nbGUsIHRyYW5zbGF0aW9uKSk7XG4gICAgICAgIHZhciB0ZWVQdHMgPSBwb2ludHNUb0Fycih0cmFuc2Zvcm1Qb2ludHModGhpcy5jcm9zc0xpbmVQdHMoc2l6ZSwgZWRnZVdpZHRoKSwgc2l6ZSArIDIgKiBwYWRkaW5nLCBhbmdsZSwgdHJhbnNsYXRpb24pKTtcbiAgICAgICAgdmFyIGluc2lkZSA9IHBvaW50SW5zaWRlUG9seWdvblBvaW50cyh4LCB5LCB0cmlQdHMpIHx8IHBvaW50SW5zaWRlUG9seWdvblBvaW50cyh4LCB5LCB0ZWVQdHMpO1xuICAgICAgICByZXR1cm4gaW5zaWRlO1xuICAgICAgfSxcbiAgICAgIGRyYXc6IGZ1bmN0aW9uIGRyYXcoY29udGV4dCwgc2l6ZSwgYW5nbGUsIHRyYW5zbGF0aW9uLCBlZGdlV2lkdGgpIHtcbiAgICAgICAgdmFyIHRyaVB0cyA9IHRyYW5zZm9ybVBvaW50cyh0aGlzLnBvaW50cywgc2l6ZSwgYW5nbGUsIHRyYW5zbGF0aW9uKTtcbiAgICAgICAgdmFyIGNyb3NzTGluZVB0cyA9IHRyYW5zZm9ybVBvaW50cyh0aGlzLmNyb3NzTGluZVB0cyhzaXplLCBlZGdlV2lkdGgpLCBzaXplLCBhbmdsZSwgdHJhbnNsYXRpb24pO1xuICAgICAgICByZW5kZXJlci5hcnJvd1NoYXBlSW1wbCh0aGlzLm5hbWUpKGNvbnRleHQsIHRyaVB0cywgY3Jvc3NMaW5lUHRzKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBkZWZpbmVBcnJvd1NoYXBlKCd2ZWUnLCB7XG4gICAgICBwb2ludHM6IFstMC4xNSwgLTAuMywgMCwgMCwgMC4xNSwgLTAuMywgMCwgLTAuMTVdLFxuICAgICAgZ2FwOiBmdW5jdGlvbiBnYXAoZWRnZSkge1xuICAgICAgICByZXR1cm4gc3RhbmRhcmRHYXAoZWRnZSkgKiAwLjUyNTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBkZWZpbmVBcnJvd1NoYXBlKCdjaXJjbGUnLCB7XG4gICAgICByYWRpdXM6IDAuMTUsXG4gICAgICBjb2xsaWRlOiBmdW5jdGlvbiBjb2xsaWRlKHgsIHksIHNpemUsIGFuZ2xlLCB0cmFuc2xhdGlvbiwgZWRnZVdpZHRoLCBwYWRkaW5nKSB7XG4gICAgICAgIHZhciB0ID0gdHJhbnNsYXRpb247XG4gICAgICAgIHZhciBpbnNpZGUgPSBNYXRoLnBvdyh0LnggLSB4LCAyKSArIE1hdGgucG93KHQueSAtIHksIDIpIDw9IE1hdGgucG93KChzaXplICsgMiAqIHBhZGRpbmcpICogdGhpcy5yYWRpdXMsIDIpO1xuICAgICAgICByZXR1cm4gaW5zaWRlO1xuICAgICAgfSxcbiAgICAgIGRyYXc6IGZ1bmN0aW9uIGRyYXcoY29udGV4dCwgc2l6ZSwgYW5nbGUsIHRyYW5zbGF0aW9uLCBlZGdlV2lkdGgpIHtcbiAgICAgICAgcmVuZGVyZXIuYXJyb3dTaGFwZUltcGwodGhpcy5uYW1lKShjb250ZXh0LCB0cmFuc2xhdGlvbi54LCB0cmFuc2xhdGlvbi55LCB0aGlzLnJhZGl1cyAqIHNpemUpO1xuICAgICAgfSxcbiAgICAgIHNwYWNpbmc6IGZ1bmN0aW9uIHNwYWNpbmcoZWRnZSkge1xuICAgICAgICByZXR1cm4gcmVuZGVyZXIuZ2V0QXJyb3dXaWR0aChlZGdlLnBzdHlsZSgnd2lkdGgnKS5wZlZhbHVlLCBlZGdlLnBzdHlsZSgnYXJyb3ctc2NhbGUnKS52YWx1ZSkgKiB0aGlzLnJhZGl1cztcbiAgICAgIH1cbiAgICB9KTtcbiAgICBkZWZpbmVBcnJvd1NoYXBlKCd0ZWUnLCB7XG4gICAgICBwb2ludHM6IFstMC4xNSwgMCwgLTAuMTUsIC0wLjEsIDAuMTUsIC0wLjEsIDAuMTUsIDBdLFxuICAgICAgc3BhY2luZzogZnVuY3Rpb24gc3BhY2luZyhlZGdlKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfSxcbiAgICAgIGdhcDogZnVuY3Rpb24gZ2FwKGVkZ2UpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICB9XG4gICAgfSk7XG4gICAgZGVmaW5lQXJyb3dTaGFwZSgnc3F1YXJlJywge1xuICAgICAgcG9pbnRzOiBbLTAuMTUsIDAuMDAsIDAuMTUsIDAuMDAsIDAuMTUsIC0wLjMsIC0wLjE1LCAtMC4zXVxuICAgIH0pO1xuICAgIGRlZmluZUFycm93U2hhcGUoJ2RpYW1vbmQnLCB7XG4gICAgICBwb2ludHM6IFstMC4xNSwgLTAuMTUsIDAsIC0wLjMsIDAuMTUsIC0wLjE1LCAwLCAwXSxcbiAgICAgIGdhcDogZnVuY3Rpb24gZ2FwKGVkZ2UpIHtcbiAgICAgICAgcmV0dXJuIGVkZ2UucHN0eWxlKCd3aWR0aCcpLnBmVmFsdWUgKiBlZGdlLnBzdHlsZSgnYXJyb3ctc2NhbGUnKS52YWx1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBkZWZpbmVBcnJvd1NoYXBlKCdjaGV2cm9uJywge1xuICAgICAgcG9pbnRzOiBbMCwgMCwgLTAuMTUsIC0wLjE1LCAtMC4xLCAtMC4yLCAwLCAtMC4xLCAwLjEsIC0wLjIsIDAuMTUsIC0wLjE1XSxcbiAgICAgIGdhcDogZnVuY3Rpb24gZ2FwKGVkZ2UpIHtcbiAgICAgICAgcmV0dXJuIDAuOTUgKiBlZGdlLnBzdHlsZSgnd2lkdGgnKS5wZlZhbHVlICogZWRnZS5wc3R5bGUoJ2Fycm93LXNjYWxlJykudmFsdWU7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgdmFyIEJScCRlID0ge307IC8vIFByb2plY3QgbW91c2VcblxuICBCUnAkZS5wcm9qZWN0SW50b1ZpZXdwb3J0ID0gZnVuY3Rpb24gKGNsaWVudFgsIGNsaWVudFkpIHtcbiAgICB2YXIgY3kgPSB0aGlzLmN5O1xuICAgIHZhciBvZmZzZXRzID0gdGhpcy5maW5kQ29udGFpbmVyQ2xpZW50Q29vcmRzKCk7XG4gICAgdmFyIG9mZnNldExlZnQgPSBvZmZzZXRzWzBdO1xuICAgIHZhciBvZmZzZXRUb3AgPSBvZmZzZXRzWzFdO1xuICAgIHZhciBzY2FsZSA9IG9mZnNldHNbNF07XG4gICAgdmFyIHBhbiA9IGN5LnBhbigpO1xuICAgIHZhciB6b29tID0gY3kuem9vbSgpO1xuICAgIHZhciB4ID0gKChjbGllbnRYIC0gb2Zmc2V0TGVmdCkgLyBzY2FsZSAtIHBhbi54KSAvIHpvb207XG4gICAgdmFyIHkgPSAoKGNsaWVudFkgLSBvZmZzZXRUb3ApIC8gc2NhbGUgLSBwYW4ueSkgLyB6b29tO1xuICAgIHJldHVybiBbeCwgeV07XG4gIH07XG5cbiAgQlJwJGUuZmluZENvbnRhaW5lckNsaWVudENvb3JkcyA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5jb250YWluZXJCQikge1xuICAgICAgcmV0dXJuIHRoaXMuY29udGFpbmVyQkI7XG4gICAgfVxuXG4gICAgdmFyIGNvbnRhaW5lciA9IHRoaXMuY29udGFpbmVyO1xuICAgIHZhciByZWN0ID0gY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIHZhciBzdHlsZSA9IHRoaXMuY3kud2luZG93KCkuZ2V0Q29tcHV0ZWRTdHlsZShjb250YWluZXIpO1xuXG4gICAgdmFyIHN0eWxlVmFsdWUgPSBmdW5jdGlvbiBzdHlsZVZhbHVlKG5hbWUpIHtcbiAgICAgIHJldHVybiBwYXJzZUZsb2F0KHN0eWxlLmdldFByb3BlcnR5VmFsdWUobmFtZSkpO1xuICAgIH07XG5cbiAgICB2YXIgcGFkZGluZyA9IHtcbiAgICAgIGxlZnQ6IHN0eWxlVmFsdWUoJ3BhZGRpbmctbGVmdCcpLFxuICAgICAgcmlnaHQ6IHN0eWxlVmFsdWUoJ3BhZGRpbmctcmlnaHQnKSxcbiAgICAgIHRvcDogc3R5bGVWYWx1ZSgncGFkZGluZy10b3AnKSxcbiAgICAgIGJvdHRvbTogc3R5bGVWYWx1ZSgncGFkZGluZy1ib3R0b20nKVxuICAgIH07XG4gICAgdmFyIGJvcmRlciA9IHtcbiAgICAgIGxlZnQ6IHN0eWxlVmFsdWUoJ2JvcmRlci1sZWZ0LXdpZHRoJyksXG4gICAgICByaWdodDogc3R5bGVWYWx1ZSgnYm9yZGVyLXJpZ2h0LXdpZHRoJyksXG4gICAgICB0b3A6IHN0eWxlVmFsdWUoJ2JvcmRlci10b3Atd2lkdGgnKSxcbiAgICAgIGJvdHRvbTogc3R5bGVWYWx1ZSgnYm9yZGVyLWJvdHRvbS13aWR0aCcpXG4gICAgfTtcbiAgICB2YXIgY2xpZW50V2lkdGggPSBjb250YWluZXIuY2xpZW50V2lkdGg7XG4gICAgdmFyIGNsaWVudEhlaWdodCA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQ7XG4gICAgdmFyIHBhZGRpbmdIb3IgPSBwYWRkaW5nLmxlZnQgKyBwYWRkaW5nLnJpZ2h0O1xuICAgIHZhciBwYWRkaW5nVmVyID0gcGFkZGluZy50b3AgKyBwYWRkaW5nLmJvdHRvbTtcbiAgICB2YXIgYm9yZGVySG9yID0gYm9yZGVyLmxlZnQgKyBib3JkZXIucmlnaHQ7XG4gICAgdmFyIHNjYWxlID0gcmVjdC53aWR0aCAvIChjbGllbnRXaWR0aCArIGJvcmRlckhvcik7XG4gICAgdmFyIHVuc2NhbGVkVyA9IGNsaWVudFdpZHRoIC0gcGFkZGluZ0hvcjtcbiAgICB2YXIgdW5zY2FsZWRIID0gY2xpZW50SGVpZ2h0IC0gcGFkZGluZ1ZlcjtcbiAgICB2YXIgbGVmdCA9IHJlY3QubGVmdCArIHBhZGRpbmcubGVmdCArIGJvcmRlci5sZWZ0O1xuICAgIHZhciB0b3AgPSByZWN0LnRvcCArIHBhZGRpbmcudG9wICsgYm9yZGVyLnRvcDtcbiAgICByZXR1cm4gdGhpcy5jb250YWluZXJCQiA9IFtsZWZ0LCB0b3AsIHVuc2NhbGVkVywgdW5zY2FsZWRILCBzY2FsZV07XG4gIH07XG5cbiAgQlJwJGUuaW52YWxpZGF0ZUNvbnRhaW5lckNsaWVudENvb3Jkc0NhY2hlID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuY29udGFpbmVyQkIgPSBudWxsO1xuICB9O1xuXG4gIEJScCRlLmZpbmROZWFyZXN0RWxlbWVudCA9IGZ1bmN0aW9uICh4LCB5LCBpbnRlcmFjdGl2ZUVsZW1lbnRzT25seSwgaXNUb3VjaCkge1xuICAgIHJldHVybiB0aGlzLmZpbmROZWFyZXN0RWxlbWVudHMoeCwgeSwgaW50ZXJhY3RpdmVFbGVtZW50c09ubHksIGlzVG91Y2gpWzBdO1xuICB9O1xuXG4gIEJScCRlLmZpbmROZWFyZXN0RWxlbWVudHMgPSBmdW5jdGlvbiAoeCwgeSwgaW50ZXJhY3RpdmVFbGVtZW50c09ubHksIGlzVG91Y2gpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBlbGVzID0gci5nZXRDYWNoZWRaU29ydGVkRWxlcygpO1xuICAgIHZhciBuZWFyID0gW107IC8vIDEgbm9kZSBtYXgsIDEgZWRnZSBtYXhcblxuICAgIHZhciB6b29tID0gci5jeS56b29tKCk7XG4gICAgdmFyIGhhc0NvbXBvdW5kcyA9IHIuY3kuaGFzQ29tcG91bmROb2RlcygpO1xuICAgIHZhciBlZGdlVGhyZXNob2xkID0gKGlzVG91Y2ggPyAyNCA6IDgpIC8gem9vbTtcbiAgICB2YXIgbm9kZVRocmVzaG9sZCA9IChpc1RvdWNoID8gOCA6IDIpIC8gem9vbTtcbiAgICB2YXIgbGFiZWxUaHJlc2hvbGQgPSAoaXNUb3VjaCA/IDggOiAyKSAvIHpvb207XG4gICAgdmFyIG1pblNxRGlzdCA9IEluZmluaXR5O1xuICAgIHZhciBuZWFyRWRnZTtcbiAgICB2YXIgbmVhck5vZGU7XG5cbiAgICBpZiAoaW50ZXJhY3RpdmVFbGVtZW50c09ubHkpIHtcbiAgICAgIGVsZXMgPSBlbGVzLmludGVyYWN0aXZlO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFkZEVsZShlbGUsIHNxRGlzdCkge1xuICAgICAgaWYgKGVsZS5pc05vZGUoKSkge1xuICAgICAgICBpZiAobmVhck5vZGUpIHtcbiAgICAgICAgICByZXR1cm47IC8vIGNhbid0IHJlcGxhY2Ugbm9kZVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG5lYXJOb2RlID0gZWxlO1xuICAgICAgICAgIG5lYXIucHVzaChlbGUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChlbGUuaXNFZGdlKCkgJiYgKHNxRGlzdCA9PSBudWxsIHx8IHNxRGlzdCA8IG1pblNxRGlzdCkpIHtcbiAgICAgICAgaWYgKG5lYXJFZGdlKSB7XG4gICAgICAgICAgLy8gdGhlbiByZXBsYWNlIGV4aXN0aW5nIGVkZ2VcbiAgICAgICAgICAvLyBjYW4gcmVwbGFjZSBvbmx5IGlmIHNhbWUgei1pbmRleFxuICAgICAgICAgIGlmIChuZWFyRWRnZS5wc3R5bGUoJ3otY29tcG91bmQtZGVwdGgnKS52YWx1ZSA9PT0gZWxlLnBzdHlsZSgnei1jb21wb3VuZC1kZXB0aCcpLnZhbHVlICYmIG5lYXJFZGdlLnBzdHlsZSgnei1jb21wb3VuZC1kZXB0aCcpLnZhbHVlID09PSBlbGUucHN0eWxlKCd6LWNvbXBvdW5kLWRlcHRoJykudmFsdWUpIHtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbmVhci5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICBpZiAobmVhcltpXS5pc0VkZ2UoKSkge1xuICAgICAgICAgICAgICAgIG5lYXJbaV0gPSBlbGU7XG4gICAgICAgICAgICAgICAgbmVhckVkZ2UgPSBlbGU7XG4gICAgICAgICAgICAgICAgbWluU3FEaXN0ID0gc3FEaXN0ICE9IG51bGwgPyBzcURpc3QgOiBtaW5TcURpc3Q7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbmVhci5wdXNoKGVsZSk7XG4gICAgICAgICAgbmVhckVkZ2UgPSBlbGU7XG4gICAgICAgICAgbWluU3FEaXN0ID0gc3FEaXN0ICE9IG51bGwgPyBzcURpc3QgOiBtaW5TcURpc3Q7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjaGVja05vZGUobm9kZSkge1xuICAgICAgdmFyIHdpZHRoID0gbm9kZS5vdXRlcldpZHRoKCkgKyAyICogbm9kZVRocmVzaG9sZDtcbiAgICAgIHZhciBoZWlnaHQgPSBub2RlLm91dGVySGVpZ2h0KCkgKyAyICogbm9kZVRocmVzaG9sZDtcbiAgICAgIHZhciBodyA9IHdpZHRoIC8gMjtcbiAgICAgIHZhciBoaCA9IGhlaWdodCAvIDI7XG4gICAgICB2YXIgcG9zID0gbm9kZS5wb3NpdGlvbigpO1xuXG4gICAgICBpZiAocG9zLnggLSBodyA8PSB4ICYmIHggPD0gcG9zLnggKyBodyAvLyBiYiBjaGVjayB4XG4gICAgICAmJiBwb3MueSAtIGhoIDw9IHkgJiYgeSA8PSBwb3MueSArIGhoIC8vIGJiIGNoZWNrIHlcbiAgICAgICkge1xuICAgICAgICB2YXIgc2hhcGUgPSByLm5vZGVTaGFwZXNbc2VsZi5nZXROb2RlU2hhcGUobm9kZSldO1xuXG4gICAgICAgIGlmIChzaGFwZS5jaGVja1BvaW50KHgsIHksIDAsIHdpZHRoLCBoZWlnaHQsIHBvcy54LCBwb3MueSkpIHtcbiAgICAgICAgICBhZGRFbGUobm9kZSwgMCk7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjaGVja0VkZ2UoZWRnZSkge1xuICAgICAgdmFyIF9wID0gZWRnZS5fcHJpdmF0ZTtcbiAgICAgIHZhciBycyA9IF9wLnJzY3JhdGNoO1xuICAgICAgdmFyIHN0eWxlV2lkdGggPSBlZGdlLnBzdHlsZSgnd2lkdGgnKS5wZlZhbHVlO1xuICAgICAgdmFyIHNjYWxlID0gZWRnZS5wc3R5bGUoJ2Fycm93LXNjYWxlJykudmFsdWU7XG4gICAgICB2YXIgd2lkdGggPSBzdHlsZVdpZHRoIC8gMiArIGVkZ2VUaHJlc2hvbGQ7IC8vIG1vcmUgbGlrZSBhIGRpc3RhbmNlIHJhZGl1cyBmcm9tIGNlbnRyZVxuXG4gICAgICB2YXIgd2lkdGhTcSA9IHdpZHRoICogd2lkdGg7XG4gICAgICB2YXIgd2lkdGgyID0gd2lkdGggKiAyO1xuICAgICAgdmFyIHNyYyA9IF9wLnNvdXJjZTtcbiAgICAgIHZhciB0Z3QgPSBfcC50YXJnZXQ7XG4gICAgICB2YXIgc3FEaXN0O1xuXG4gICAgICBpZiAocnMuZWRnZVR5cGUgPT09ICdzZWdtZW50cycgfHwgcnMuZWRnZVR5cGUgPT09ICdzdHJhaWdodCcgfHwgcnMuZWRnZVR5cGUgPT09ICdoYXlzdGFjaycpIHtcbiAgICAgICAgdmFyIHB0cyA9IHJzLmFsbHB0cztcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSArIDMgPCBwdHMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgICAgICBpZiAoaW5MaW5lVmljaW5pdHkoeCwgeSwgcHRzW2ldLCBwdHNbaSArIDFdLCBwdHNbaSArIDJdLCBwdHNbaSArIDNdLCB3aWR0aDIpICYmIHdpZHRoU3EgPiAoc3FEaXN0ID0gc3FkaXN0VG9GaW5pdGVMaW5lKHgsIHksIHB0c1tpXSwgcHRzW2kgKyAxXSwgcHRzW2kgKyAyXSwgcHRzW2kgKyAzXSkpKSB7XG4gICAgICAgICAgICBhZGRFbGUoZWRnZSwgc3FEaXN0KTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChycy5lZGdlVHlwZSA9PT0gJ2JlemllcicgfHwgcnMuZWRnZVR5cGUgPT09ICdtdWx0aWJlemllcicgfHwgcnMuZWRnZVR5cGUgPT09ICdzZWxmJyB8fCBycy5lZGdlVHlwZSA9PT0gJ2NvbXBvdW5kJykge1xuICAgICAgICB2YXIgcHRzID0gcnMuYWxscHRzO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpICsgNSA8IHJzLmFsbHB0cy5sZW5ndGg7IGkgKz0gNCkge1xuICAgICAgICAgIGlmIChpbkJlemllclZpY2luaXR5KHgsIHksIHB0c1tpXSwgcHRzW2kgKyAxXSwgcHRzW2kgKyAyXSwgcHRzW2kgKyAzXSwgcHRzW2kgKyA0XSwgcHRzW2kgKyA1XSwgd2lkdGgyKSAmJiB3aWR0aFNxID4gKHNxRGlzdCA9IHNxZGlzdFRvUXVhZHJhdGljQmV6aWVyKHgsIHksIHB0c1tpXSwgcHRzW2kgKyAxXSwgcHRzW2kgKyAyXSwgcHRzW2kgKyAzXSwgcHRzW2kgKyA0XSwgcHRzW2kgKyA1XSkpKSB7XG4gICAgICAgICAgICBhZGRFbGUoZWRnZSwgc3FEaXN0KTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSAvLyBpZiB3ZSdyZSBjbG9zZSB0byB0aGUgZWRnZSBidXQgZGlkbid0IGhpdCBpdCwgbWF5YmUgd2UgaGl0IGl0cyBhcnJvd3NcblxuXG4gICAgICB2YXIgc3JjID0gc3JjIHx8IF9wLnNvdXJjZTtcbiAgICAgIHZhciB0Z3QgPSB0Z3QgfHwgX3AudGFyZ2V0O1xuICAgICAgdmFyIGFyU2l6ZSA9IHNlbGYuZ2V0QXJyb3dXaWR0aChzdHlsZVdpZHRoLCBzY2FsZSk7XG4gICAgICB2YXIgYXJyb3dzID0gW3tcbiAgICAgICAgbmFtZTogJ3NvdXJjZScsXG4gICAgICAgIHg6IHJzLmFycm93U3RhcnRYLFxuICAgICAgICB5OiBycy5hcnJvd1N0YXJ0WSxcbiAgICAgICAgYW5nbGU6IHJzLnNyY0Fycm93QW5nbGVcbiAgICAgIH0sIHtcbiAgICAgICAgbmFtZTogJ3RhcmdldCcsXG4gICAgICAgIHg6IHJzLmFycm93RW5kWCxcbiAgICAgICAgeTogcnMuYXJyb3dFbmRZLFxuICAgICAgICBhbmdsZTogcnMudGd0QXJyb3dBbmdsZVxuICAgICAgfSwge1xuICAgICAgICBuYW1lOiAnbWlkLXNvdXJjZScsXG4gICAgICAgIHg6IHJzLm1pZFgsXG4gICAgICAgIHk6IHJzLm1pZFksXG4gICAgICAgIGFuZ2xlOiBycy5taWRzcmNBcnJvd0FuZ2xlXG4gICAgICB9LCB7XG4gICAgICAgIG5hbWU6ICdtaWQtdGFyZ2V0JyxcbiAgICAgICAgeDogcnMubWlkWCxcbiAgICAgICAgeTogcnMubWlkWSxcbiAgICAgICAgYW5nbGU6IHJzLm1pZHRndEFycm93QW5nbGVcbiAgICAgIH1dO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFycm93cy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgYXIgPSBhcnJvd3NbaV07XG4gICAgICAgIHZhciBzaGFwZSA9IHIuYXJyb3dTaGFwZXNbZWRnZS5wc3R5bGUoYXIubmFtZSArICctYXJyb3ctc2hhcGUnKS52YWx1ZV07XG4gICAgICAgIHZhciBlZGdlV2lkdGggPSBlZGdlLnBzdHlsZSgnd2lkdGgnKS5wZlZhbHVlO1xuXG4gICAgICAgIGlmIChzaGFwZS5yb3VnaENvbGxpZGUoeCwgeSwgYXJTaXplLCBhci5hbmdsZSwge1xuICAgICAgICAgIHg6IGFyLngsXG4gICAgICAgICAgeTogYXIueVxuICAgICAgICB9LCBlZGdlV2lkdGgsIGVkZ2VUaHJlc2hvbGQpICYmIHNoYXBlLmNvbGxpZGUoeCwgeSwgYXJTaXplLCBhci5hbmdsZSwge1xuICAgICAgICAgIHg6IGFyLngsXG4gICAgICAgICAgeTogYXIueVxuICAgICAgICB9LCBlZGdlV2lkdGgsIGVkZ2VUaHJlc2hvbGQpKSB7XG4gICAgICAgICAgYWRkRWxlKGVkZ2UpO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9IC8vIGZvciBjb21wb3VuZCBncmFwaHMsIGhpdHRpbmcgZWRnZSBtYXkgYWN0dWFsbHkgd2FudCBhIGNvbm5lY3RlZCBub2RlIGluc3RlYWQgKGIvYyBlZGdlIG1heSBoYXZlIGdyZWF0ZXIgei1pbmRleCBwcmVjZWRlbmNlKVxuXG5cbiAgICAgIGlmIChoYXNDb21wb3VuZHMgJiYgbmVhci5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNoZWNrTm9kZShzcmMpO1xuICAgICAgICBjaGVja05vZGUodGd0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwcmVwcm9wKG9iaiwgbmFtZSwgcHJlKSB7XG4gICAgICByZXR1cm4gZ2V0UHJlZml4ZWRQcm9wZXJ0eShvYmosIG5hbWUsIHByZSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY2hlY2tMYWJlbChlbGUsIHByZWZpeCkge1xuICAgICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgICAgdmFyIHRoID0gbGFiZWxUaHJlc2hvbGQ7XG4gICAgICB2YXIgcHJlZml4RGFzaDtcblxuICAgICAgaWYgKHByZWZpeCkge1xuICAgICAgICBwcmVmaXhEYXNoID0gcHJlZml4ICsgJy0nO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcHJlZml4RGFzaCA9ICcnO1xuICAgICAgfVxuXG4gICAgICBlbGUuYm91bmRpbmdCb3goKTtcbiAgICAgIHZhciBiYiA9IF9wLmxhYmVsQm91bmRzW3ByZWZpeCB8fCAnbWFpbiddO1xuICAgICAgdmFyIHRleHQgPSBlbGUucHN0eWxlKHByZWZpeERhc2ggKyAnbGFiZWwnKS52YWx1ZTtcbiAgICAgIHZhciBldmVudHNFbmFibGVkID0gZWxlLnBzdHlsZSgndGV4dC1ldmVudHMnKS5zdHJWYWx1ZSA9PT0gJ3llcyc7XG5cbiAgICAgIGlmICghZXZlbnRzRW5hYmxlZCB8fCAhdGV4dCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciBseCA9IHByZXByb3AoX3AucnNjcmF0Y2gsICdsYWJlbFgnLCBwcmVmaXgpO1xuICAgICAgdmFyIGx5ID0gcHJlcHJvcChfcC5yc2NyYXRjaCwgJ2xhYmVsWScsIHByZWZpeCk7XG4gICAgICB2YXIgdGhldGEgPSBwcmVwcm9wKF9wLnJzY3JhdGNoLCAnbGFiZWxBbmdsZScsIHByZWZpeCk7XG4gICAgICB2YXIgb3ggPSBlbGUucHN0eWxlKHByZWZpeERhc2ggKyAndGV4dC1tYXJnaW4teCcpLnBmVmFsdWU7XG4gICAgICB2YXIgb3kgPSBlbGUucHN0eWxlKHByZWZpeERhc2ggKyAndGV4dC1tYXJnaW4teScpLnBmVmFsdWU7XG4gICAgICB2YXIgbHgxID0gYmIueDEgLSB0aCAtIG94OyAvLyAoLW94LCAtb3kpIGFzIGJiIGFscmVhZHkgaW5jbHVkZXMgbWFyZ2luXG5cbiAgICAgIHZhciBseDIgPSBiYi54MiArIHRoIC0gb3g7IC8vIGFuZCByb3RhdGlvbiBpcyBhYm91dCAobHgsIGx5KVxuXG4gICAgICB2YXIgbHkxID0gYmIueTEgLSB0aCAtIG95O1xuICAgICAgdmFyIGx5MiA9IGJiLnkyICsgdGggLSBveTtcblxuICAgICAgaWYgKHRoZXRhKSB7XG4gICAgICAgIHZhciBjb3MgPSBNYXRoLmNvcyh0aGV0YSk7XG4gICAgICAgIHZhciBzaW4gPSBNYXRoLnNpbih0aGV0YSk7XG5cbiAgICAgICAgdmFyIHJvdGF0ZSA9IGZ1bmN0aW9uIHJvdGF0ZSh4LCB5KSB7XG4gICAgICAgICAgeCA9IHggLSBseDtcbiAgICAgICAgICB5ID0geSAtIGx5O1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB4OiB4ICogY29zIC0geSAqIHNpbiArIGx4LFxuICAgICAgICAgICAgeTogeCAqIHNpbiArIHkgKiBjb3MgKyBseVxuICAgICAgICAgIH07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHB4MXkxID0gcm90YXRlKGx4MSwgbHkxKTtcbiAgICAgICAgdmFyIHB4MXkyID0gcm90YXRlKGx4MSwgbHkyKTtcbiAgICAgICAgdmFyIHB4MnkxID0gcm90YXRlKGx4MiwgbHkxKTtcbiAgICAgICAgdmFyIHB4MnkyID0gcm90YXRlKGx4MiwgbHkyKTtcbiAgICAgICAgdmFyIHBvaW50cyA9IFsvLyB3aXRoIHRoZSBtYXJnaW4gYWRkZWQgYWZ0ZXIgdGhlIHJvdGF0aW9uIGlzIGFwcGxpZWRcbiAgICAgICAgcHgxeTEueCArIG94LCBweDF5MS55ICsgb3ksIHB4MnkxLnggKyBveCwgcHgyeTEueSArIG95LCBweDJ5Mi54ICsgb3gsIHB4MnkyLnkgKyBveSwgcHgxeTIueCArIG94LCBweDF5Mi55ICsgb3ldO1xuXG4gICAgICAgIGlmIChwb2ludEluc2lkZVBvbHlnb25Qb2ludHMoeCwgeSwgcG9pbnRzKSkge1xuICAgICAgICAgIGFkZEVsZShlbGUpO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBkbyBhIGNoZWFwZXIgYmIgY2hlY2tcbiAgICAgICAgaWYgKGluQm91bmRpbmdCb3goYmIsIHgsIHkpKSB7XG4gICAgICAgICAgYWRkRWxlKGVsZSk7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKHZhciBpID0gZWxlcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgLy8gcmV2ZXJzZSBvcmRlciBmb3IgcHJlY2VkZW5jZVxuICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG5cbiAgICAgIGlmIChlbGUuaXNOb2RlKCkpIHtcbiAgICAgICAgY2hlY2tOb2RlKGVsZSkgfHwgY2hlY2tMYWJlbChlbGUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gdGhlbiBlZGdlXG4gICAgICAgIGNoZWNrRWRnZShlbGUpIHx8IGNoZWNrTGFiZWwoZWxlKSB8fCBjaGVja0xhYmVsKGVsZSwgJ3NvdXJjZScpIHx8IGNoZWNrTGFiZWwoZWxlLCAndGFyZ2V0Jyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG5lYXI7XG4gIH07IC8vICdHaXZlIG1lIGV2ZXJ5dGhpbmcgZnJvbSB0aGlzIGJveCdcblxuXG4gIEJScCRlLmdldEFsbEluQm94ID0gZnVuY3Rpb24gKHgxLCB5MSwgeDIsIHkyKSB7XG4gICAgdmFyIGVsZXMgPSB0aGlzLmdldENhY2hlZFpTb3J0ZWRFbGVzKCkuaW50ZXJhY3RpdmU7XG4gICAgdmFyIGJveCA9IFtdO1xuICAgIHZhciB4MWMgPSBNYXRoLm1pbih4MSwgeDIpO1xuICAgIHZhciB4MmMgPSBNYXRoLm1heCh4MSwgeDIpO1xuICAgIHZhciB5MWMgPSBNYXRoLm1pbih5MSwgeTIpO1xuICAgIHZhciB5MmMgPSBNYXRoLm1heCh5MSwgeTIpO1xuICAgIHgxID0geDFjO1xuICAgIHgyID0geDJjO1xuICAgIHkxID0geTFjO1xuICAgIHkyID0geTJjO1xuICAgIHZhciBib3hCYiA9IG1ha2VCb3VuZGluZ0JveCh7XG4gICAgICB4MTogeDEsXG4gICAgICB5MTogeTEsXG4gICAgICB4MjogeDIsXG4gICAgICB5MjogeTJcbiAgICB9KTtcblxuICAgIGZvciAodmFyIGUgPSAwOyBlIDwgZWxlcy5sZW5ndGg7IGUrKykge1xuICAgICAgdmFyIGVsZSA9IGVsZXNbZV07XG5cbiAgICAgIGlmIChlbGUuaXNOb2RlKCkpIHtcbiAgICAgICAgdmFyIG5vZGUgPSBlbGU7XG4gICAgICAgIHZhciBub2RlQmIgPSBub2RlLmJvdW5kaW5nQm94KHtcbiAgICAgICAgICBpbmNsdWRlTm9kZXM6IHRydWUsXG4gICAgICAgICAgaW5jbHVkZUVkZ2VzOiBmYWxzZSxcbiAgICAgICAgICBpbmNsdWRlTGFiZWxzOiBmYWxzZVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoYm91bmRpbmdCb3hlc0ludGVyc2VjdChib3hCYiwgbm9kZUJiKSAmJiAhYm91bmRpbmdCb3hJbkJvdW5kaW5nQm94KG5vZGVCYiwgYm94QmIpKSB7XG4gICAgICAgICAgYm94LnB1c2gobm9kZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBlZGdlID0gZWxlO1xuICAgICAgICB2YXIgX3AgPSBlZGdlLl9wcml2YXRlO1xuICAgICAgICB2YXIgcnMgPSBfcC5yc2NyYXRjaDtcblxuICAgICAgICBpZiAocnMuc3RhcnRYICE9IG51bGwgJiYgcnMuc3RhcnRZICE9IG51bGwgJiYgIWluQm91bmRpbmdCb3goYm94QmIsIHJzLnN0YXJ0WCwgcnMuc3RhcnRZKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJzLmVuZFggIT0gbnVsbCAmJiBycy5lbmRZICE9IG51bGwgJiYgIWluQm91bmRpbmdCb3goYm94QmIsIHJzLmVuZFgsIHJzLmVuZFkpKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocnMuZWRnZVR5cGUgPT09ICdiZXppZXInIHx8IHJzLmVkZ2VUeXBlID09PSAnbXVsdGliZXppZXInIHx8IHJzLmVkZ2VUeXBlID09PSAnc2VsZicgfHwgcnMuZWRnZVR5cGUgPT09ICdjb21wb3VuZCcgfHwgcnMuZWRnZVR5cGUgPT09ICdzZWdtZW50cycgfHwgcnMuZWRnZVR5cGUgPT09ICdoYXlzdGFjaycpIHtcbiAgICAgICAgICB2YXIgcHRzID0gX3AucnN0eWxlLmJlemllclB0cyB8fCBfcC5yc3R5bGUubGluZVB0cyB8fCBfcC5yc3R5bGUuaGF5c3RhY2tQdHM7XG4gICAgICAgICAgdmFyIGFsbEluc2lkZSA9IHRydWU7XG5cbiAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHB0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKCFwb2ludEluQm91bmRpbmdCb3goYm94QmIsIHB0c1tpXSkpIHtcbiAgICAgICAgICAgICAgYWxsSW5zaWRlID0gZmFsc2U7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChhbGxJbnNpZGUpIHtcbiAgICAgICAgICAgIGJveC5wdXNoKGVkZ2UpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChycy5lZGdlVHlwZSA9PT0gJ2hheXN0YWNrJyB8fCBycy5lZGdlVHlwZSA9PT0gJ3N0cmFpZ2h0Jykge1xuICAgICAgICAgIGJveC5wdXNoKGVkZ2UpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGJveDtcbiAgfTtcblxuICB2YXIgQlJwJGQgPSB7fTtcblxuICBCUnAkZC5jYWxjdWxhdGVBcnJvd0FuZ2xlcyA9IGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgdmFyIHJzID0gZWRnZS5fcHJpdmF0ZS5yc2NyYXRjaDtcbiAgICB2YXIgaXNIYXlzdGFjayA9IHJzLmVkZ2VUeXBlID09PSAnaGF5c3RhY2snO1xuICAgIHZhciBpc0JlemllciA9IHJzLmVkZ2VUeXBlID09PSAnYmV6aWVyJztcbiAgICB2YXIgaXNNdWx0aWJlemllciA9IHJzLmVkZ2VUeXBlID09PSAnbXVsdGliZXppZXInO1xuICAgIHZhciBpc1NlZ21lbnRzID0gcnMuZWRnZVR5cGUgPT09ICdzZWdtZW50cyc7XG4gICAgdmFyIGlzQ29tcG91bmQgPSBycy5lZGdlVHlwZSA9PT0gJ2NvbXBvdW5kJztcbiAgICB2YXIgaXNTZWxmID0gcnMuZWRnZVR5cGUgPT09ICdzZWxmJzsgLy8gRGlzcGxhY2VtZW50IGdpdmVzIGRpcmVjdGlvbiBmb3IgYXJyb3doZWFkIG9yaWVudGF0aW9uXG5cbiAgICB2YXIgZGlzcFgsIGRpc3BZO1xuICAgIHZhciBzdGFydFgsIHN0YXJ0WSwgZW5kWCwgZW5kWSwgbWlkWCwgbWlkWTtcblxuICAgIGlmIChpc0hheXN0YWNrKSB7XG4gICAgICBzdGFydFggPSBycy5oYXlzdGFja1B0c1swXTtcbiAgICAgIHN0YXJ0WSA9IHJzLmhheXN0YWNrUHRzWzFdO1xuICAgICAgZW5kWCA9IHJzLmhheXN0YWNrUHRzWzJdO1xuICAgICAgZW5kWSA9IHJzLmhheXN0YWNrUHRzWzNdO1xuICAgIH0gZWxzZSB7XG4gICAgICBzdGFydFggPSBycy5hcnJvd1N0YXJ0WDtcbiAgICAgIHN0YXJ0WSA9IHJzLmFycm93U3RhcnRZO1xuICAgICAgZW5kWCA9IHJzLmFycm93RW5kWDtcbiAgICAgIGVuZFkgPSBycy5hcnJvd0VuZFk7XG4gICAgfVxuXG4gICAgbWlkWCA9IHJzLm1pZFg7XG4gICAgbWlkWSA9IHJzLm1pZFk7IC8vIHNvdXJjZVxuICAgIC8vXG5cbiAgICBpZiAoaXNTZWdtZW50cykge1xuICAgICAgZGlzcFggPSBzdGFydFggLSBycy5zZWdwdHNbMF07XG4gICAgICBkaXNwWSA9IHN0YXJ0WSAtIHJzLnNlZ3B0c1sxXTtcbiAgICB9IGVsc2UgaWYgKGlzTXVsdGliZXppZXIgfHwgaXNDb21wb3VuZCB8fCBpc1NlbGYgfHwgaXNCZXppZXIpIHtcbiAgICAgIHZhciBwdHMgPSBycy5hbGxwdHM7XG4gICAgICB2YXIgYlggPSBxYmV6aWVyQXQocHRzWzBdLCBwdHNbMl0sIHB0c1s0XSwgMC4xKTtcbiAgICAgIHZhciBiWSA9IHFiZXppZXJBdChwdHNbMV0sIHB0c1szXSwgcHRzWzVdLCAwLjEpO1xuICAgICAgZGlzcFggPSBzdGFydFggLSBiWDtcbiAgICAgIGRpc3BZID0gc3RhcnRZIC0gYlk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRpc3BYID0gc3RhcnRYIC0gbWlkWDtcbiAgICAgIGRpc3BZID0gc3RhcnRZIC0gbWlkWTtcbiAgICB9XG5cbiAgICBycy5zcmNBcnJvd0FuZ2xlID0gZ2V0QW5nbGVGcm9tRGlzcChkaXNwWCwgZGlzcFkpOyAvLyBtaWQgdGFyZ2V0XG4gICAgLy9cblxuICAgIHZhciBtaWRYID0gcnMubWlkWDtcbiAgICB2YXIgbWlkWSA9IHJzLm1pZFk7XG5cbiAgICBpZiAoaXNIYXlzdGFjaykge1xuICAgICAgbWlkWCA9IChzdGFydFggKyBlbmRYKSAvIDI7XG4gICAgICBtaWRZID0gKHN0YXJ0WSArIGVuZFkpIC8gMjtcbiAgICB9XG5cbiAgICBkaXNwWCA9IGVuZFggLSBzdGFydFg7XG4gICAgZGlzcFkgPSBlbmRZIC0gc3RhcnRZO1xuXG4gICAgaWYgKGlzU2VnbWVudHMpIHtcbiAgICAgIHZhciBwdHMgPSBycy5hbGxwdHM7XG5cbiAgICAgIGlmIChwdHMubGVuZ3RoIC8gMiAlIDIgPT09IDApIHtcbiAgICAgICAgdmFyIGkyID0gcHRzLmxlbmd0aCAvIDI7XG4gICAgICAgIHZhciBpMSA9IGkyIC0gMjtcbiAgICAgICAgZGlzcFggPSBwdHNbaTJdIC0gcHRzW2kxXTtcbiAgICAgICAgZGlzcFkgPSBwdHNbaTIgKyAxXSAtIHB0c1tpMSArIDFdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIGkyID0gcHRzLmxlbmd0aCAvIDIgLSAxO1xuICAgICAgICB2YXIgaTEgPSBpMiAtIDI7XG4gICAgICAgIHZhciBpMyA9IGkyICsgMjtcbiAgICAgICAgZGlzcFggPSBwdHNbaTJdIC0gcHRzW2kxXTtcbiAgICAgICAgZGlzcFkgPSBwdHNbaTIgKyAxXSAtIHB0c1tpMSArIDFdO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoaXNNdWx0aWJlemllciB8fCBpc0NvbXBvdW5kIHx8IGlzU2VsZikge1xuICAgICAgdmFyIHB0cyA9IHJzLmFsbHB0cztcbiAgICAgIHZhciBjcHRzID0gcnMuY3RybHB0cztcbiAgICAgIHZhciBicDB4LCBicDB5O1xuICAgICAgdmFyIGJwMXgsIGJwMXk7XG5cbiAgICAgIGlmIChjcHRzLmxlbmd0aCAvIDIgJSAyID09PSAwKSB7XG4gICAgICAgIHZhciBwMCA9IHB0cy5sZW5ndGggLyAyIC0gMTsgLy8gc3RhcnRwdFxuXG4gICAgICAgIHZhciBpYyA9IHAwICsgMjtcbiAgICAgICAgdmFyIHAxID0gaWMgKyAyO1xuICAgICAgICBicDB4ID0gcWJlemllckF0KHB0c1twMF0sIHB0c1tpY10sIHB0c1twMV0sIDAuMCk7XG4gICAgICAgIGJwMHkgPSBxYmV6aWVyQXQocHRzW3AwICsgMV0sIHB0c1tpYyArIDFdLCBwdHNbcDEgKyAxXSwgMC4wKTtcbiAgICAgICAgYnAxeCA9IHFiZXppZXJBdChwdHNbcDBdLCBwdHNbaWNdLCBwdHNbcDFdLCAwLjAwMDEpO1xuICAgICAgICBicDF5ID0gcWJlemllckF0KHB0c1twMCArIDFdLCBwdHNbaWMgKyAxXSwgcHRzW3AxICsgMV0sIDAuMDAwMSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgaWMgPSBwdHMubGVuZ3RoIC8gMiAtIDE7IC8vIGN0cnB0XG5cbiAgICAgICAgdmFyIHAwID0gaWMgLSAyOyAvLyBzdGFydHB0XG5cbiAgICAgICAgdmFyIHAxID0gaWMgKyAyOyAvLyBlbmRwdFxuXG4gICAgICAgIGJwMHggPSBxYmV6aWVyQXQocHRzW3AwXSwgcHRzW2ljXSwgcHRzW3AxXSwgMC40OTk5KTtcbiAgICAgICAgYnAweSA9IHFiZXppZXJBdChwdHNbcDAgKyAxXSwgcHRzW2ljICsgMV0sIHB0c1twMSArIDFdLCAwLjQ5OTkpO1xuICAgICAgICBicDF4ID0gcWJlemllckF0KHB0c1twMF0sIHB0c1tpY10sIHB0c1twMV0sIDAuNSk7XG4gICAgICAgIGJwMXkgPSBxYmV6aWVyQXQocHRzW3AwICsgMV0sIHB0c1tpYyArIDFdLCBwdHNbcDEgKyAxXSwgMC41KTtcbiAgICAgIH1cblxuICAgICAgZGlzcFggPSBicDF4IC0gYnAweDtcbiAgICAgIGRpc3BZID0gYnAxeSAtIGJwMHk7XG4gICAgfVxuXG4gICAgcnMubWlkdGd0QXJyb3dBbmdsZSA9IGdldEFuZ2xlRnJvbURpc3AoZGlzcFgsIGRpc3BZKTtcbiAgICBycy5taWREaXNwWCA9IGRpc3BYO1xuICAgIHJzLm1pZERpc3BZID0gZGlzcFk7IC8vIG1pZCBzb3VyY2VcbiAgICAvL1xuXG4gICAgZGlzcFggKj0gLTE7XG4gICAgZGlzcFkgKj0gLTE7XG5cbiAgICBpZiAoaXNTZWdtZW50cykge1xuICAgICAgdmFyIHB0cyA9IHJzLmFsbHB0cztcblxuICAgICAgaWYgKHB0cy5sZW5ndGggLyAyICUgMiA9PT0gMCkgOyBlbHNlIHtcbiAgICAgICAgdmFyIGkyID0gcHRzLmxlbmd0aCAvIDIgLSAxO1xuICAgICAgICB2YXIgaTMgPSBpMiArIDI7XG4gICAgICAgIGRpc3BYID0gLShwdHNbaTNdIC0gcHRzW2kyXSk7XG4gICAgICAgIGRpc3BZID0gLShwdHNbaTMgKyAxXSAtIHB0c1tpMiArIDFdKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBycy5taWRzcmNBcnJvd0FuZ2xlID0gZ2V0QW5nbGVGcm9tRGlzcChkaXNwWCwgZGlzcFkpOyAvLyB0YXJnZXRcbiAgICAvL1xuXG4gICAgaWYgKGlzU2VnbWVudHMpIHtcbiAgICAgIGRpc3BYID0gZW5kWCAtIHJzLnNlZ3B0c1tycy5zZWdwdHMubGVuZ3RoIC0gMl07XG4gICAgICBkaXNwWSA9IGVuZFkgLSBycy5zZWdwdHNbcnMuc2VncHRzLmxlbmd0aCAtIDFdO1xuICAgIH0gZWxzZSBpZiAoaXNNdWx0aWJlemllciB8fCBpc0NvbXBvdW5kIHx8IGlzU2VsZiB8fCBpc0Jlemllcikge1xuICAgICAgdmFyIHB0cyA9IHJzLmFsbHB0cztcbiAgICAgIHZhciBsID0gcHRzLmxlbmd0aDtcbiAgICAgIHZhciBiWCA9IHFiZXppZXJBdChwdHNbbCAtIDZdLCBwdHNbbCAtIDRdLCBwdHNbbCAtIDJdLCAwLjkpO1xuICAgICAgdmFyIGJZID0gcWJlemllckF0KHB0c1tsIC0gNV0sIHB0c1tsIC0gM10sIHB0c1tsIC0gMV0sIDAuOSk7XG4gICAgICBkaXNwWCA9IGVuZFggLSBiWDtcbiAgICAgIGRpc3BZID0gZW5kWSAtIGJZO1xuICAgIH0gZWxzZSB7XG4gICAgICBkaXNwWCA9IGVuZFggLSBtaWRYO1xuICAgICAgZGlzcFkgPSBlbmRZIC0gbWlkWTtcbiAgICB9XG5cbiAgICBycy50Z3RBcnJvd0FuZ2xlID0gZ2V0QW5nbGVGcm9tRGlzcChkaXNwWCwgZGlzcFkpO1xuICB9O1xuXG4gIEJScCRkLmdldEFycm93V2lkdGggPSBCUnAkZC5nZXRBcnJvd0hlaWdodCA9IGZ1bmN0aW9uIChlZGdlV2lkdGgsIHNjYWxlKSB7XG4gICAgdmFyIGNhY2hlID0gdGhpcy5hcnJvd1dpZHRoQ2FjaGUgPSB0aGlzLmFycm93V2lkdGhDYWNoZSB8fCB7fTtcbiAgICB2YXIgY2FjaGVkVmFsID0gY2FjaGVbZWRnZVdpZHRoICsgJywgJyArIHNjYWxlXTtcblxuICAgIGlmIChjYWNoZWRWYWwpIHtcbiAgICAgIHJldHVybiBjYWNoZWRWYWw7XG4gICAgfVxuXG4gICAgY2FjaGVkVmFsID0gTWF0aC5tYXgoTWF0aC5wb3coZWRnZVdpZHRoICogMTMuMzcsIDAuOSksIDI5KSAqIHNjYWxlO1xuICAgIGNhY2hlW2VkZ2VXaWR0aCArICcsICcgKyBzY2FsZV0gPSBjYWNoZWRWYWw7XG4gICAgcmV0dXJuIGNhY2hlZFZhbDtcbiAgfTtcblxuICB2YXIgQlJwJGMgPSB7fTtcblxuICBCUnAkYy5maW5kSGF5c3RhY2tQb2ludHMgPSBmdW5jdGlvbiAoZWRnZXMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVkZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZWRnZSA9IGVkZ2VzW2ldO1xuICAgICAgdmFyIF9wID0gZWRnZS5fcHJpdmF0ZTtcbiAgICAgIHZhciBycyA9IF9wLnJzY3JhdGNoO1xuXG4gICAgICBpZiAoIXJzLmhheXN0YWNrKSB7XG4gICAgICAgIHZhciBhbmdsZSA9IE1hdGgucmFuZG9tKCkgKiAyICogTWF0aC5QSTtcbiAgICAgICAgcnMuc291cmNlID0ge1xuICAgICAgICAgIHg6IE1hdGguY29zKGFuZ2xlKSxcbiAgICAgICAgICB5OiBNYXRoLnNpbihhbmdsZSlcbiAgICAgICAgfTtcbiAgICAgICAgYW5nbGUgPSBNYXRoLnJhbmRvbSgpICogMiAqIE1hdGguUEk7XG4gICAgICAgIHJzLnRhcmdldCA9IHtcbiAgICAgICAgICB4OiBNYXRoLmNvcyhhbmdsZSksXG4gICAgICAgICAgeTogTWF0aC5zaW4oYW5nbGUpXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIHZhciBzcmMgPSBfcC5zb3VyY2U7XG4gICAgICB2YXIgdGd0ID0gX3AudGFyZ2V0O1xuICAgICAgdmFyIHNyY1BvcyA9IHNyYy5wb3NpdGlvbigpO1xuICAgICAgdmFyIHRndFBvcyA9IHRndC5wb3NpdGlvbigpO1xuICAgICAgdmFyIHNyY1cgPSBzcmMud2lkdGgoKTtcbiAgICAgIHZhciB0Z3RXID0gdGd0LndpZHRoKCk7XG4gICAgICB2YXIgc3JjSCA9IHNyYy5oZWlnaHQoKTtcbiAgICAgIHZhciB0Z3RIID0gdGd0LmhlaWdodCgpO1xuICAgICAgdmFyIHJhZGl1cyA9IGVkZ2UucHN0eWxlKCdoYXlzdGFjay1yYWRpdXMnKS52YWx1ZTtcbiAgICAgIHZhciBoYWxmUmFkaXVzID0gcmFkaXVzIC8gMjsgLy8gYi9jIGhhdmUgdG8gaGFsZiB3aWR0aC9oZWlnaHRcblxuICAgICAgcnMuaGF5c3RhY2tQdHMgPSBycy5hbGxwdHMgPSBbcnMuc291cmNlLnggKiBzcmNXICogaGFsZlJhZGl1cyArIHNyY1Bvcy54LCBycy5zb3VyY2UueSAqIHNyY0ggKiBoYWxmUmFkaXVzICsgc3JjUG9zLnksIHJzLnRhcmdldC54ICogdGd0VyAqIGhhbGZSYWRpdXMgKyB0Z3RQb3MueCwgcnMudGFyZ2V0LnkgKiB0Z3RIICogaGFsZlJhZGl1cyArIHRndFBvcy55XTtcbiAgICAgIHJzLm1pZFggPSAocnMuYWxscHRzWzBdICsgcnMuYWxscHRzWzJdKSAvIDI7XG4gICAgICBycy5taWRZID0gKHJzLmFsbHB0c1sxXSArIHJzLmFsbHB0c1szXSkgLyAyOyAvLyBhbHdheXMgb3ZlcnJpZGUgYXMgaGF5c3RhY2sgaW4gY2FzZSBzZXQgdG8gZGlmZmVyZW50IHR5cGUgcHJldmlvdXNseVxuXG4gICAgICBycy5lZGdlVHlwZSA9ICdoYXlzdGFjayc7XG4gICAgICBycy5oYXlzdGFjayA9IHRydWU7XG4gICAgICB0aGlzLnN0b3JlRWRnZVByb2plY3Rpb25zKGVkZ2UpO1xuICAgICAgdGhpcy5jYWxjdWxhdGVBcnJvd0FuZ2xlcyhlZGdlKTtcbiAgICAgIHRoaXMucmVjYWxjdWxhdGVFZGdlTGFiZWxQcm9qZWN0aW9ucyhlZGdlKTtcbiAgICAgIHRoaXMuY2FsY3VsYXRlTGFiZWxBbmdsZXMoZWRnZSk7XG4gICAgfVxuICB9O1xuXG4gIEJScCRjLmZpbmRTZWdtZW50c1BvaW50cyA9IGZ1bmN0aW9uIChlZGdlLCBwYWlySW5mbykge1xuICAgIC8vIFNlZ21lbnRzIChtdWx0aXBsZSBzdHJhaWdodCBsaW5lcylcbiAgICB2YXIgcnMgPSBlZGdlLl9wcml2YXRlLnJzY3JhdGNoO1xuICAgIHZhciBwb3NQdHMgPSBwYWlySW5mby5wb3NQdHMsXG4gICAgICAgIGludGVyc2VjdGlvblB0cyA9IHBhaXJJbmZvLmludGVyc2VjdGlvblB0cyxcbiAgICAgICAgdmVjdG9yTm9ybUludmVyc2UgPSBwYWlySW5mby52ZWN0b3JOb3JtSW52ZXJzZTtcbiAgICB2YXIgZWRnZURpc3RhbmNlcyA9IGVkZ2UucHN0eWxlKCdlZGdlLWRpc3RhbmNlcycpLnZhbHVlO1xuICAgIHZhciBzZWdtZW50V3MgPSBlZGdlLnBzdHlsZSgnc2VnbWVudC13ZWlnaHRzJyk7XG4gICAgdmFyIHNlZ21lbnREcyA9IGVkZ2UucHN0eWxlKCdzZWdtZW50LWRpc3RhbmNlcycpO1xuICAgIHZhciBzZWdtZW50c04gPSBNYXRoLm1pbihzZWdtZW50V3MucGZWYWx1ZS5sZW5ndGgsIHNlZ21lbnREcy5wZlZhbHVlLmxlbmd0aCk7XG4gICAgcnMuZWRnZVR5cGUgPSAnc2VnbWVudHMnO1xuICAgIHJzLnNlZ3B0cyA9IFtdO1xuXG4gICAgZm9yICh2YXIgcyA9IDA7IHMgPCBzZWdtZW50c047IHMrKykge1xuICAgICAgdmFyIHcgPSBzZWdtZW50V3MucGZWYWx1ZVtzXTtcbiAgICAgIHZhciBkID0gc2VnbWVudERzLnBmVmFsdWVbc107XG4gICAgICB2YXIgdzEgPSAxIC0gdztcbiAgICAgIHZhciB3MiA9IHc7XG4gICAgICB2YXIgbWlkcHRQdHMgPSBlZGdlRGlzdGFuY2VzID09PSAnbm9kZS1wb3NpdGlvbicgPyBwb3NQdHMgOiBpbnRlcnNlY3Rpb25QdHM7XG4gICAgICB2YXIgYWRqdXN0ZWRNaWRwdCA9IHtcbiAgICAgICAgeDogbWlkcHRQdHMueDEgKiB3MSArIG1pZHB0UHRzLngyICogdzIsXG4gICAgICAgIHk6IG1pZHB0UHRzLnkxICogdzEgKyBtaWRwdFB0cy55MiAqIHcyXG4gICAgICB9O1xuICAgICAgcnMuc2VncHRzLnB1c2goYWRqdXN0ZWRNaWRwdC54ICsgdmVjdG9yTm9ybUludmVyc2UueCAqIGQsIGFkanVzdGVkTWlkcHQueSArIHZlY3Rvck5vcm1JbnZlcnNlLnkgKiBkKTtcbiAgICB9XG4gIH07XG5cbiAgQlJwJGMuZmluZExvb3BQb2ludHMgPSBmdW5jdGlvbiAoZWRnZSwgcGFpckluZm8sIGksIGVkZ2VJc1VuYnVuZGxlZCkge1xuICAgIC8vIFNlbGYtZWRnZVxuICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgdmFyIGRpckNvdW50cyA9IHBhaXJJbmZvLmRpckNvdW50cyxcbiAgICAgICAgc3JjUG9zID0gcGFpckluZm8uc3JjUG9zO1xuICAgIHZhciBjdHJscHREaXN0cyA9IGVkZ2UucHN0eWxlKCdjb250cm9sLXBvaW50LWRpc3RhbmNlcycpO1xuICAgIHZhciBjdHJscHREaXN0ID0gY3RybHB0RGlzdHMgPyBjdHJscHREaXN0cy5wZlZhbHVlWzBdIDogdW5kZWZpbmVkO1xuICAgIHZhciBsb29wRGlyID0gZWRnZS5wc3R5bGUoJ2xvb3AtZGlyZWN0aW9uJykucGZWYWx1ZTtcbiAgICB2YXIgbG9vcFN3cCA9IGVkZ2UucHN0eWxlKCdsb29wLXN3ZWVwJykucGZWYWx1ZTtcbiAgICB2YXIgc3RlcFNpemUgPSBlZGdlLnBzdHlsZSgnY29udHJvbC1wb2ludC1zdGVwLXNpemUnKS5wZlZhbHVlO1xuICAgIHJzLmVkZ2VUeXBlID0gJ3NlbGYnO1xuICAgIHZhciBqID0gaTtcbiAgICB2YXIgbG9vcERpc3QgPSBzdGVwU2l6ZTtcblxuICAgIGlmIChlZGdlSXNVbmJ1bmRsZWQpIHtcbiAgICAgIGogPSAwO1xuICAgICAgbG9vcERpc3QgPSBjdHJscHREaXN0O1xuICAgIH1cblxuICAgIHZhciBsb29wQW5nbGUgPSBsb29wRGlyIC0gTWF0aC5QSSAvIDI7XG4gICAgdmFyIG91dEFuZ2xlID0gbG9vcEFuZ2xlIC0gbG9vcFN3cCAvIDI7XG4gICAgdmFyIGluQW5nbGUgPSBsb29wQW5nbGUgKyBsb29wU3dwIC8gMjsgLy8gaW5jcmVhc2UgYnkgc3RlcCBzaXplIGZvciBvdmVybGFwcGluZyBsb29wcywga2V5ZWQgb24gZGlyZWN0aW9uIGFuZCBzd2VlcCB2YWx1ZXNcblxuICAgIHZhciBkYyA9IFN0cmluZyhsb29wRGlyICsgJ18nICsgbG9vcFN3cCk7XG4gICAgaiA9IGRpckNvdW50c1tkY10gPT09IHVuZGVmaW5lZCA/IGRpckNvdW50c1tkY10gPSAwIDogKytkaXJDb3VudHNbZGNdO1xuICAgIHJzLmN0cmxwdHMgPSBbc3JjUG9zLnggKyBNYXRoLmNvcyhvdXRBbmdsZSkgKiAxLjQgKiBsb29wRGlzdCAqIChqIC8gMyArIDEpLCBzcmNQb3MueSArIE1hdGguc2luKG91dEFuZ2xlKSAqIDEuNCAqIGxvb3BEaXN0ICogKGogLyAzICsgMSksIHNyY1Bvcy54ICsgTWF0aC5jb3MoaW5BbmdsZSkgKiAxLjQgKiBsb29wRGlzdCAqIChqIC8gMyArIDEpLCBzcmNQb3MueSArIE1hdGguc2luKGluQW5nbGUpICogMS40ICogbG9vcERpc3QgKiAoaiAvIDMgKyAxKV07XG4gIH07XG5cbiAgQlJwJGMuZmluZENvbXBvdW5kTG9vcFBvaW50cyA9IGZ1bmN0aW9uIChlZGdlLCBwYWlySW5mbywgaSwgZWRnZUlzVW5idW5kbGVkKSB7XG4gICAgLy8gQ29tcG91bmQgZWRnZVxuICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgcnMuZWRnZVR5cGUgPSAnY29tcG91bmQnO1xuICAgIHZhciBzcmNQb3MgPSBwYWlySW5mby5zcmNQb3MsXG4gICAgICAgIHRndFBvcyA9IHBhaXJJbmZvLnRndFBvcyxcbiAgICAgICAgc3JjVyA9IHBhaXJJbmZvLnNyY1csXG4gICAgICAgIHNyY0ggPSBwYWlySW5mby5zcmNILFxuICAgICAgICB0Z3RXID0gcGFpckluZm8udGd0VyxcbiAgICAgICAgdGd0SCA9IHBhaXJJbmZvLnRndEg7XG4gICAgdmFyIHN0ZXBTaXplID0gZWRnZS5wc3R5bGUoJ2NvbnRyb2wtcG9pbnQtc3RlcC1zaXplJykucGZWYWx1ZTtcbiAgICB2YXIgY3RybHB0RGlzdHMgPSBlZGdlLnBzdHlsZSgnY29udHJvbC1wb2ludC1kaXN0YW5jZXMnKTtcbiAgICB2YXIgY3RybHB0RGlzdCA9IGN0cmxwdERpc3RzID8gY3RybHB0RGlzdHMucGZWYWx1ZVswXSA6IHVuZGVmaW5lZDtcbiAgICB2YXIgaiA9IGk7XG4gICAgdmFyIGxvb3BEaXN0ID0gc3RlcFNpemU7XG5cbiAgICBpZiAoZWRnZUlzVW5idW5kbGVkKSB7XG4gICAgICBqID0gMDtcbiAgICAgIGxvb3BEaXN0ID0gY3RybHB0RGlzdDtcbiAgICB9XG5cbiAgICB2YXIgbG9vcFcgPSA1MDtcbiAgICB2YXIgbG9vcGFQb3MgPSB7XG4gICAgICB4OiBzcmNQb3MueCAtIHNyY1cgLyAyLFxuICAgICAgeTogc3JjUG9zLnkgLSBzcmNIIC8gMlxuICAgIH07XG4gICAgdmFyIGxvb3BiUG9zID0ge1xuICAgICAgeDogdGd0UG9zLnggLSB0Z3RXIC8gMixcbiAgICAgIHk6IHRndFBvcy55IC0gdGd0SCAvIDJcbiAgICB9O1xuICAgIHZhciBsb29wUG9zID0ge1xuICAgICAgeDogTWF0aC5taW4obG9vcGFQb3MueCwgbG9vcGJQb3MueCksXG4gICAgICB5OiBNYXRoLm1pbihsb29wYVBvcy55LCBsb29wYlBvcy55KVxuICAgIH07IC8vIGF2b2lkcyBjYXNlcyB3aXRoIGltcG9zc2libGUgYmV6aWVyc1xuXG4gICAgdmFyIG1pbkNvbXBvdW5kU3RyZXRjaCA9IDAuNTtcbiAgICB2YXIgY29tcG91bmRTdHJldGNoQSA9IE1hdGgubWF4KG1pbkNvbXBvdW5kU3RyZXRjaCwgTWF0aC5sb2coc3JjVyAqIDAuMDEpKTtcbiAgICB2YXIgY29tcG91bmRTdHJldGNoQiA9IE1hdGgubWF4KG1pbkNvbXBvdW5kU3RyZXRjaCwgTWF0aC5sb2codGd0VyAqIDAuMDEpKTtcbiAgICBycy5jdHJscHRzID0gW2xvb3BQb3MueCwgbG9vcFBvcy55IC0gKDEgKyBNYXRoLnBvdyhsb29wVywgMS4xMikgLyAxMDApICogbG9vcERpc3QgKiAoaiAvIDMgKyAxKSAqIGNvbXBvdW5kU3RyZXRjaEEsIGxvb3BQb3MueCAtICgxICsgTWF0aC5wb3cobG9vcFcsIDEuMTIpIC8gMTAwKSAqIGxvb3BEaXN0ICogKGogLyAzICsgMSkgKiBjb21wb3VuZFN0cmV0Y2hCLCBsb29wUG9zLnldO1xuICB9O1xuXG4gIEJScCRjLmZpbmRTdHJhaWdodEVkZ2VQb2ludHMgPSBmdW5jdGlvbiAoZWRnZSkge1xuICAgIC8vIFN0cmFpZ2h0IGVkZ2Ugd2l0aGluIGJ1bmRsZVxuICAgIGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2guZWRnZVR5cGUgPSAnc3RyYWlnaHQnO1xuICB9O1xuXG4gIEJScCRjLmZpbmRCZXppZXJQb2ludHMgPSBmdW5jdGlvbiAoZWRnZSwgcGFpckluZm8sIGksIGVkZ2VJc1VuYnVuZGxlZCwgZWRnZUlzU3dhcHBlZCkge1xuICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgdmFyIHZlY3Rvck5vcm1JbnZlcnNlID0gcGFpckluZm8udmVjdG9yTm9ybUludmVyc2UsXG4gICAgICAgIHBvc1B0cyA9IHBhaXJJbmZvLnBvc1B0cyxcbiAgICAgICAgaW50ZXJzZWN0aW9uUHRzID0gcGFpckluZm8uaW50ZXJzZWN0aW9uUHRzO1xuICAgIHZhciBlZGdlRGlzdGFuY2VzID0gZWRnZS5wc3R5bGUoJ2VkZ2UtZGlzdGFuY2VzJykudmFsdWU7XG4gICAgdmFyIHN0ZXBTaXplID0gZWRnZS5wc3R5bGUoJ2NvbnRyb2wtcG9pbnQtc3RlcC1zaXplJykucGZWYWx1ZTtcbiAgICB2YXIgY3RybHB0RGlzdHMgPSBlZGdlLnBzdHlsZSgnY29udHJvbC1wb2ludC1kaXN0YW5jZXMnKTtcbiAgICB2YXIgY3RybHB0V3MgPSBlZGdlLnBzdHlsZSgnY29udHJvbC1wb2ludC13ZWlnaHRzJyk7XG4gICAgdmFyIGJlemllck4gPSBjdHJscHREaXN0cyAmJiBjdHJscHRXcyA/IE1hdGgubWluKGN0cmxwdERpc3RzLnZhbHVlLmxlbmd0aCwgY3RybHB0V3MudmFsdWUubGVuZ3RoKSA6IDE7XG4gICAgdmFyIGN0cmxwdERpc3QgPSBjdHJscHREaXN0cyA/IGN0cmxwdERpc3RzLnBmVmFsdWVbMF0gOiB1bmRlZmluZWQ7XG4gICAgdmFyIGN0cmxwdFdlaWdodCA9IGN0cmxwdFdzLnZhbHVlWzBdOyAvLyAoTXVsdGkpYmV6aWVyXG5cbiAgICB2YXIgbXVsdGkgPSBlZGdlSXNVbmJ1bmRsZWQ7XG4gICAgcnMuZWRnZVR5cGUgPSBtdWx0aSA/ICdtdWx0aWJlemllcicgOiAnYmV6aWVyJztcbiAgICBycy5jdHJscHRzID0gW107XG5cbiAgICBmb3IgKHZhciBiID0gMDsgYiA8IGJlemllck47IGIrKykge1xuICAgICAgdmFyIG5vcm1jdHJscHREaXN0ID0gKDAuNSAtIHBhaXJJbmZvLmVsZXMubGVuZ3RoIC8gMiArIGkpICogc3RlcFNpemUgKiAoZWRnZUlzU3dhcHBlZCA/IC0xIDogMSk7XG4gICAgICB2YXIgbWFuY3RybHB0RGlzdCA9IHZvaWQgMDtcbiAgICAgIHZhciBzaWduID0gc2lnbnVtKG5vcm1jdHJscHREaXN0KTtcblxuICAgICAgaWYgKG11bHRpKSB7XG4gICAgICAgIGN0cmxwdERpc3QgPSBjdHJscHREaXN0cyA/IGN0cmxwdERpc3RzLnBmVmFsdWVbYl0gOiBzdGVwU2l6ZTsgLy8gZmFsbCBiYWNrIG9uIHN0ZXAgc2l6ZVxuXG4gICAgICAgIGN0cmxwdFdlaWdodCA9IGN0cmxwdFdzLnZhbHVlW2JdO1xuICAgICAgfVxuXG4gICAgICBpZiAoZWRnZUlzVW5idW5kbGVkKSB7XG4gICAgICAgIC8vIG11bHRpIG9yIHNpbmdsZSB1bmJ1bmRsZWRcbiAgICAgICAgbWFuY3RybHB0RGlzdCA9IGN0cmxwdERpc3Q7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBtYW5jdHJscHREaXN0ID0gY3RybHB0RGlzdCAhPT0gdW5kZWZpbmVkID8gc2lnbiAqIGN0cmxwdERpc3QgOiB1bmRlZmluZWQ7XG4gICAgICB9XG5cbiAgICAgIHZhciBkaXN0YW5jZUZyb21NaWRwb2ludCA9IG1hbmN0cmxwdERpc3QgIT09IHVuZGVmaW5lZCA/IG1hbmN0cmxwdERpc3QgOiBub3JtY3RybHB0RGlzdDtcbiAgICAgIHZhciB3MSA9IDEgLSBjdHJscHRXZWlnaHQ7XG4gICAgICB2YXIgdzIgPSBjdHJscHRXZWlnaHQ7XG4gICAgICB2YXIgbWlkcHRQdHMgPSBlZGdlRGlzdGFuY2VzID09PSAnbm9kZS1wb3NpdGlvbicgPyBwb3NQdHMgOiBpbnRlcnNlY3Rpb25QdHM7XG4gICAgICB2YXIgYWRqdXN0ZWRNaWRwdCA9IHtcbiAgICAgICAgeDogbWlkcHRQdHMueDEgKiB3MSArIG1pZHB0UHRzLngyICogdzIsXG4gICAgICAgIHk6IG1pZHB0UHRzLnkxICogdzEgKyBtaWRwdFB0cy55MiAqIHcyXG4gICAgICB9O1xuICAgICAgcnMuY3RybHB0cy5wdXNoKGFkanVzdGVkTWlkcHQueCArIHZlY3Rvck5vcm1JbnZlcnNlLnggKiBkaXN0YW5jZUZyb21NaWRwb2ludCwgYWRqdXN0ZWRNaWRwdC55ICsgdmVjdG9yTm9ybUludmVyc2UueSAqIGRpc3RhbmNlRnJvbU1pZHBvaW50KTtcbiAgICB9XG4gIH07XG5cbiAgQlJwJGMuZmluZFRheGlQb2ludHMgPSBmdW5jdGlvbiAoZWRnZSwgcGFpckluZm8pIHtcbiAgICAvLyBUYXhpY2FiIGdlb21ldHJ5IHdpdGggdHdvIHR1cm5zIG1heGltdW1cbiAgICB2YXIgcnMgPSBlZGdlLl9wcml2YXRlLnJzY3JhdGNoO1xuICAgIHJzLmVkZ2VUeXBlID0gJ3NlZ21lbnRzJztcbiAgICB2YXIgVkVSVElDQUwgPSAndmVydGljYWwnO1xuICAgIHZhciBIT1JJWk9OVEFMID0gJ2hvcml6b250YWwnO1xuICAgIHZhciBMRUZUV0FSRCA9ICdsZWZ0d2FyZCc7XG4gICAgdmFyIFJJR0hUV0FSRCA9ICdyaWdodHdhcmQnO1xuICAgIHZhciBET1dOV0FSRCA9ICdkb3dud2FyZCc7XG4gICAgdmFyIFVQV0FSRCA9ICd1cHdhcmQnO1xuICAgIHZhciBBVVRPID0gJ2F1dG8nO1xuICAgIHZhciBwb3NQdHMgPSBwYWlySW5mby5wb3NQdHMsXG4gICAgICAgIHNyY1cgPSBwYWlySW5mby5zcmNXLFxuICAgICAgICBzcmNIID0gcGFpckluZm8uc3JjSCxcbiAgICAgICAgdGd0VyA9IHBhaXJJbmZvLnRndFcsXG4gICAgICAgIHRndEggPSBwYWlySW5mby50Z3RIO1xuICAgIHZhciBlZGdlRGlzdGFuY2VzID0gZWRnZS5wc3R5bGUoJ2VkZ2UtZGlzdGFuY2VzJykudmFsdWU7XG4gICAgdmFyIGRJbmNsdWRlc05vZGVCb2R5ID0gZWRnZURpc3RhbmNlcyAhPT0gJ25vZGUtcG9zaXRpb24nO1xuICAgIHZhciB0YXhpRGlyID0gZWRnZS5wc3R5bGUoJ3RheGktZGlyZWN0aW9uJykudmFsdWU7XG4gICAgdmFyIHJhd1RheGlEaXIgPSB0YXhpRGlyOyAvLyB1bnByb2Nlc3NlZCB2YWx1ZVxuXG4gICAgdmFyIHRheGlUdXJuID0gZWRnZS5wc3R5bGUoJ3RheGktdHVybicpO1xuICAgIHZhciB0dXJuSXNQZXJjZW50ID0gdGF4aVR1cm4udW5pdHMgPT09ICclJztcbiAgICB2YXIgdGF4aVR1cm5QZlZhbCA9IHRheGlUdXJuLnBmVmFsdWU7XG4gICAgdmFyIHR1cm5Jc05lZ2F0aXZlID0gdGF4aVR1cm5QZlZhbCA8IDA7IC8vIGkuZS4gZnJvbSB0YXJnZXQgc2lkZVxuXG4gICAgdmFyIG1pbkQgPSBlZGdlLnBzdHlsZSgndGF4aS10dXJuLW1pbi1kaXN0YW5jZScpLnBmVmFsdWU7XG4gICAgdmFyIGR3ID0gZEluY2x1ZGVzTm9kZUJvZHkgPyAoc3JjVyArIHRndFcpIC8gMiA6IDA7XG4gICAgdmFyIGRoID0gZEluY2x1ZGVzTm9kZUJvZHkgPyAoc3JjSCArIHRndEgpIC8gMiA6IDA7XG4gICAgdmFyIHBkeCA9IHBvc1B0cy54MiAtIHBvc1B0cy54MTtcbiAgICB2YXIgcGR5ID0gcG9zUHRzLnkyIC0gcG9zUHRzLnkxOyAvLyB0YWtlIGF3YXkgdGhlIGVmZmVjdGl2ZSB3L2ggZnJvbSB0aGUgbWFnbml0dWRlIG9mIHRoZSBkZWx0YSB2YWx1ZVxuXG4gICAgdmFyIHN1YkRXSCA9IGZ1bmN0aW9uIHN1YkRXSChkeHksIGR3aCkge1xuICAgICAgaWYgKGR4eSA+IDApIHtcbiAgICAgICAgcmV0dXJuIE1hdGgubWF4KGR4eSAtIGR3aCwgMCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gTWF0aC5taW4oZHh5ICsgZHdoLCAwKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGR4ID0gc3ViRFdIKHBkeCwgZHcpO1xuICAgIHZhciBkeSA9IHN1YkRXSChwZHksIGRoKTtcbiAgICB2YXIgaXNFeHBsaWNpdERpciA9IGZhbHNlO1xuXG4gICAgaWYgKHJhd1RheGlEaXIgPT09IEFVVE8pIHtcbiAgICAgIHRheGlEaXIgPSBNYXRoLmFicyhkeCkgPiBNYXRoLmFicyhkeSkgPyBIT1JJWk9OVEFMIDogVkVSVElDQUw7XG4gICAgfSBlbHNlIGlmIChyYXdUYXhpRGlyID09PSBVUFdBUkQgfHwgcmF3VGF4aURpciA9PT0gRE9XTldBUkQpIHtcbiAgICAgIHRheGlEaXIgPSBWRVJUSUNBTDtcbiAgICAgIGlzRXhwbGljaXREaXIgPSB0cnVlO1xuICAgIH0gZWxzZSBpZiAocmF3VGF4aURpciA9PT0gTEVGVFdBUkQgfHwgcmF3VGF4aURpciA9PT0gUklHSFRXQVJEKSB7XG4gICAgICB0YXhpRGlyID0gSE9SSVpPTlRBTDtcbiAgICAgIGlzRXhwbGljaXREaXIgPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciBpc1ZlcnQgPSB0YXhpRGlyID09PSBWRVJUSUNBTDtcbiAgICB2YXIgbCA9IGlzVmVydCA/IGR5IDogZHg7XG4gICAgdmFyIHBsID0gaXNWZXJ0ID8gcGR5IDogcGR4O1xuICAgIHZhciBzZ25MID0gc2lnbnVtKHBsKTtcbiAgICB2YXIgZm9yY2VkRGlyID0gZmFsc2U7XG5cbiAgICBpZiAoIShpc0V4cGxpY2l0RGlyICYmICh0dXJuSXNQZXJjZW50IHx8IHR1cm5Jc05lZ2F0aXZlKSkgLy8gZm9yY2luZyBpbiB0aGlzIGNhc2Ugd291bGQgY2F1c2Ugd2VpcmQgZ3Jvd2luZyBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uXG4gICAgJiYgKHJhd1RheGlEaXIgPT09IERPV05XQVJEICYmIHBsIDwgMCB8fCByYXdUYXhpRGlyID09PSBVUFdBUkQgJiYgcGwgPiAwIHx8IHJhd1RheGlEaXIgPT09IExFRlRXQVJEICYmIHBsID4gMCB8fCByYXdUYXhpRGlyID09PSBSSUdIVFdBUkQgJiYgcGwgPCAwKSkge1xuICAgICAgc2duTCAqPSAtMTtcbiAgICAgIGwgPSBzZ25MICogTWF0aC5hYnMobCk7XG4gICAgICBmb3JjZWREaXIgPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciBkO1xuXG4gICAgaWYgKHR1cm5Jc1BlcmNlbnQpIHtcbiAgICAgIHZhciBwID0gdGF4aVR1cm5QZlZhbCA8IDAgPyAxICsgdGF4aVR1cm5QZlZhbCA6IHRheGlUdXJuUGZWYWw7XG4gICAgICBkID0gcCAqIGw7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBrID0gdGF4aVR1cm5QZlZhbCA8IDAgPyBsIDogMDtcbiAgICAgIGQgPSBrICsgdGF4aVR1cm5QZlZhbCAqIHNnbkw7XG4gICAgfVxuXG4gICAgdmFyIGdldElzVG9vQ2xvc2UgPSBmdW5jdGlvbiBnZXRJc1Rvb0Nsb3NlKGQpIHtcbiAgICAgIHJldHVybiBNYXRoLmFicyhkKSA8IG1pbkQgfHwgTWF0aC5hYnMoZCkgPj0gTWF0aC5hYnMobCk7XG4gICAgfTtcblxuICAgIHZhciBpc1Rvb0Nsb3NlU3JjID0gZ2V0SXNUb29DbG9zZShkKTtcbiAgICB2YXIgaXNUb29DbG9zZVRndCA9IGdldElzVG9vQ2xvc2UoTWF0aC5hYnMobCkgLSBNYXRoLmFicyhkKSk7XG4gICAgdmFyIGlzVG9vQ2xvc2UgPSBpc1Rvb0Nsb3NlU3JjIHx8IGlzVG9vQ2xvc2VUZ3Q7XG5cbiAgICBpZiAoaXNUb29DbG9zZSAmJiAhZm9yY2VkRGlyKSB7XG4gICAgICAvLyBub24taWRlYWwgcm91dGluZ1xuICAgICAgaWYgKGlzVmVydCkge1xuICAgICAgICAvLyB2ZXJ0aWNhbCBmYWxsYmFja3NcbiAgICAgICAgdmFyIGxTaGFwZUluc2lkZVNyYyA9IE1hdGguYWJzKHBsKSA8PSBzcmNIIC8gMjtcbiAgICAgICAgdmFyIGxTaGFwZUluc2lkZVRndCA9IE1hdGguYWJzKHBkeCkgPD0gdGd0VyAvIDI7XG5cbiAgICAgICAgaWYgKGxTaGFwZUluc2lkZVNyYykge1xuICAgICAgICAgIC8vIGhvcml6b250YWwgWi1zaGFwZSAoZGlyZWN0aW9uIG5vdCByZXNwZWN0ZWQpXG4gICAgICAgICAgdmFyIHggPSAocG9zUHRzLngxICsgcG9zUHRzLngyKSAvIDI7XG4gICAgICAgICAgdmFyIHkxID0gcG9zUHRzLnkxLFxuICAgICAgICAgICAgICB5MiA9IHBvc1B0cy55MjtcbiAgICAgICAgICBycy5zZWdwdHMgPSBbeCwgeTEsIHgsIHkyXTtcbiAgICAgICAgfSBlbHNlIGlmIChsU2hhcGVJbnNpZGVUZ3QpIHtcbiAgICAgICAgICAvLyB2ZXJ0aWNhbCBaLXNoYXBlIChkaXN0YW5jZSBub3QgcmVzcGVjdGVkKVxuICAgICAgICAgIHZhciB5ID0gKHBvc1B0cy55MSArIHBvc1B0cy55MikgLyAyO1xuICAgICAgICAgIHZhciB4MSA9IHBvc1B0cy54MSxcbiAgICAgICAgICAgICAgeDIgPSBwb3NQdHMueDI7XG4gICAgICAgICAgcnMuc2VncHRzID0gW3gxLCB5LCB4MiwgeV07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gTC1zaGFwZSBmYWxsYmFjayAodHVybiBkaXN0YW5jZSBub3QgcmVzcGVjdGVkLCBidXQgd29ya3Mgd2VsbCB3aXRoIHRyZWUgc2libGluZ3MpXG4gICAgICAgICAgcnMuc2VncHRzID0gW3Bvc1B0cy54MSwgcG9zUHRzLnkyXTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gaG9yaXpvbnRhbCBmYWxsYmFja3NcbiAgICAgICAgdmFyIF9sU2hhcGVJbnNpZGVTcmMgPSBNYXRoLmFicyhwbCkgPD0gc3JjVyAvIDI7XG5cbiAgICAgICAgdmFyIF9sU2hhcGVJbnNpZGVUZ3QgPSBNYXRoLmFicyhwZHkpIDw9IHRndEggLyAyO1xuXG4gICAgICAgIGlmIChfbFNoYXBlSW5zaWRlU3JjKSB7XG4gICAgICAgICAgLy8gdmVydGljYWwgWi1zaGFwZSAoZGlyZWN0aW9uIG5vdCByZXNwZWN0ZWQpXG4gICAgICAgICAgdmFyIF95ID0gKHBvc1B0cy55MSArIHBvc1B0cy55MikgLyAyO1xuXG4gICAgICAgICAgdmFyIF94ID0gcG9zUHRzLngxLFxuICAgICAgICAgICAgICBfeDIgPSBwb3NQdHMueDI7XG4gICAgICAgICAgcnMuc2VncHRzID0gW194LCBfeSwgX3gyLCBfeV07XG4gICAgICAgIH0gZWxzZSBpZiAoX2xTaGFwZUluc2lkZVRndCkge1xuICAgICAgICAgIC8vIGhvcml6b250YWwgWi1zaGFwZSAodHVybiBkaXN0YW5jZSBub3QgcmVzcGVjdGVkKVxuICAgICAgICAgIHZhciBfeDMgPSAocG9zUHRzLngxICsgcG9zUHRzLngyKSAvIDI7XG5cbiAgICAgICAgICB2YXIgX3kyID0gcG9zUHRzLnkxLFxuICAgICAgICAgICAgICBfeTMgPSBwb3NQdHMueTI7XG4gICAgICAgICAgcnMuc2VncHRzID0gW194MywgX3kyLCBfeDMsIF95M107XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gTC1zaGFwZSAodHVybiBkaXN0YW5jZSBub3QgcmVzcGVjdGVkLCBidXQgd29ya3Mgd2VsbCBmb3IgdHJlZSBzaWJsaW5ncylcbiAgICAgICAgICBycy5zZWdwdHMgPSBbcG9zUHRzLngyLCBwb3NQdHMueTFdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGlkZWFsIHJvdXRpbmdcbiAgICAgIGlmIChpc1ZlcnQpIHtcbiAgICAgICAgdmFyIF95NCA9IHBvc1B0cy55MSArIGQgKyAoZEluY2x1ZGVzTm9kZUJvZHkgPyBzcmNIIC8gMiAqIHNnbkwgOiAwKTtcblxuICAgICAgICB2YXIgX3g0ID0gcG9zUHRzLngxLFxuICAgICAgICAgICAgX3g1ID0gcG9zUHRzLngyO1xuICAgICAgICBycy5zZWdwdHMgPSBbX3g0LCBfeTQsIF94NSwgX3k0XTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGhvcml6b250YWxcbiAgICAgICAgdmFyIF94NiA9IHBvc1B0cy54MSArIGQgKyAoZEluY2x1ZGVzTm9kZUJvZHkgPyBzcmNXIC8gMiAqIHNnbkwgOiAwKTtcblxuICAgICAgICB2YXIgX3k1ID0gcG9zUHRzLnkxLFxuICAgICAgICAgICAgX3k2ID0gcG9zUHRzLnkyO1xuICAgICAgICBycy5zZWdwdHMgPSBbX3g2LCBfeTUsIF94NiwgX3k2XTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgQlJwJGMudHJ5VG9Db3JyZWN0SW52YWxpZFBvaW50cyA9IGZ1bmN0aW9uIChlZGdlLCBwYWlySW5mbykge1xuICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7IC8vIGNhbiBvbmx5IGNvcnJlY3QgYmV6aWVycyBmb3Igbm93Li4uXG5cbiAgICBpZiAocnMuZWRnZVR5cGUgPT09ICdiZXppZXInKSB7XG4gICAgICB2YXIgc3JjUG9zID0gcGFpckluZm8uc3JjUG9zLFxuICAgICAgICAgIHRndFBvcyA9IHBhaXJJbmZvLnRndFBvcyxcbiAgICAgICAgICBzcmNXID0gcGFpckluZm8uc3JjVyxcbiAgICAgICAgICBzcmNIID0gcGFpckluZm8uc3JjSCxcbiAgICAgICAgICB0Z3RXID0gcGFpckluZm8udGd0VyxcbiAgICAgICAgICB0Z3RIID0gcGFpckluZm8udGd0SCxcbiAgICAgICAgICBzcmNTaGFwZSA9IHBhaXJJbmZvLnNyY1NoYXBlLFxuICAgICAgICAgIHRndFNoYXBlID0gcGFpckluZm8udGd0U2hhcGU7XG4gICAgICB2YXIgYmFkU3RhcnQgPSAhbnVtYmVyJDEocnMuc3RhcnRYKSB8fCAhbnVtYmVyJDEocnMuc3RhcnRZKTtcbiAgICAgIHZhciBiYWRBU3RhcnQgPSAhbnVtYmVyJDEocnMuYXJyb3dTdGFydFgpIHx8ICFudW1iZXIkMShycy5hcnJvd1N0YXJ0WSk7XG4gICAgICB2YXIgYmFkRW5kID0gIW51bWJlciQxKHJzLmVuZFgpIHx8ICFudW1iZXIkMShycy5lbmRZKTtcbiAgICAgIHZhciBiYWRBRW5kID0gIW51bWJlciQxKHJzLmFycm93RW5kWCkgfHwgIW51bWJlciQxKHJzLmFycm93RW5kWSk7XG4gICAgICB2YXIgbWluQ3BBRGlzdEZhY3RvciA9IDM7XG4gICAgICB2YXIgYXJyb3dXID0gdGhpcy5nZXRBcnJvd1dpZHRoKGVkZ2UucHN0eWxlKCd3aWR0aCcpLnBmVmFsdWUsIGVkZ2UucHN0eWxlKCdhcnJvdy1zY2FsZScpLnZhbHVlKSAqIHRoaXMuYXJyb3dTaGFwZVdpZHRoO1xuICAgICAgdmFyIG1pbkNwQURpc3QgPSBtaW5DcEFEaXN0RmFjdG9yICogYXJyb3dXO1xuICAgICAgdmFyIHN0YXJ0QUNwRGlzdCA9IGRpc3Qoe1xuICAgICAgICB4OiBycy5jdHJscHRzWzBdLFxuICAgICAgICB5OiBycy5jdHJscHRzWzFdXG4gICAgICB9LCB7XG4gICAgICAgIHg6IHJzLnN0YXJ0WCxcbiAgICAgICAgeTogcnMuc3RhcnRZXG4gICAgICB9KTtcbiAgICAgIHZhciBjbG9zZVN0YXJ0QUNwID0gc3RhcnRBQ3BEaXN0IDwgbWluQ3BBRGlzdDtcbiAgICAgIHZhciBlbmRBQ3BEaXN0ID0gZGlzdCh7XG4gICAgICAgIHg6IHJzLmN0cmxwdHNbMF0sXG4gICAgICAgIHk6IHJzLmN0cmxwdHNbMV1cbiAgICAgIH0sIHtcbiAgICAgICAgeDogcnMuZW5kWCxcbiAgICAgICAgeTogcnMuZW5kWVxuICAgICAgfSk7XG4gICAgICB2YXIgY2xvc2VFbmRBQ3AgPSBlbmRBQ3BEaXN0IDwgbWluQ3BBRGlzdDtcbiAgICAgIHZhciBvdmVybGFwcGluZyA9IGZhbHNlO1xuXG4gICAgICBpZiAoYmFkU3RhcnQgfHwgYmFkQVN0YXJ0IHx8IGNsb3NlU3RhcnRBQ3ApIHtcbiAgICAgICAgb3ZlcmxhcHBpbmcgPSB0cnVlOyAvLyBwcm9qZWN0IGNvbnRyb2wgcG9pbnQgYWxvbmcgbGluZSBmcm9tIHNyYyBjZW50cmUgdG8gb3V0c2lkZSB0aGUgc3JjIHNoYXBlXG4gICAgICAgIC8vIChvdGhlcndpc2UgaW50ZXJzZWN0aW9uIHdpbGwgeWllbGQgbm90aGluZylcblxuICAgICAgICB2YXIgY3BEID0ge1xuICAgICAgICAgIC8vIGRlbHRhXG4gICAgICAgICAgeDogcnMuY3RybHB0c1swXSAtIHNyY1Bvcy54LFxuICAgICAgICAgIHk6IHJzLmN0cmxwdHNbMV0gLSBzcmNQb3MueVxuICAgICAgICB9O1xuICAgICAgICB2YXIgY3BMID0gTWF0aC5zcXJ0KGNwRC54ICogY3BELnggKyBjcEQueSAqIGNwRC55KTsgLy8gbGVuZ3RoIG9mIGxpbmVcblxuICAgICAgICB2YXIgY3BNID0ge1xuICAgICAgICAgIC8vIG5vcm1hbGlzZWQgZGVsdGFcbiAgICAgICAgICB4OiBjcEQueCAvIGNwTCxcbiAgICAgICAgICB5OiBjcEQueSAvIGNwTFxuICAgICAgICB9O1xuICAgICAgICB2YXIgcmFkaXVzID0gTWF0aC5tYXgoc3JjVywgc3JjSCk7XG4gICAgICAgIHZhciBjcFByb2ogPSB7XG4gICAgICAgICAgLy8gKjIgcmFkaXVzIGd1YXJhbnRlZXMgb3V0c2lkZSBzaGFwZVxuICAgICAgICAgIHg6IHJzLmN0cmxwdHNbMF0gKyBjcE0ueCAqIDIgKiByYWRpdXMsXG4gICAgICAgICAgeTogcnMuY3RybHB0c1sxXSArIGNwTS55ICogMiAqIHJhZGl1c1xuICAgICAgICB9O1xuICAgICAgICB2YXIgc3JjQ3RybFB0SW50biA9IHNyY1NoYXBlLmludGVyc2VjdExpbmUoc3JjUG9zLngsIHNyY1Bvcy55LCBzcmNXLCBzcmNILCBjcFByb2oueCwgY3BQcm9qLnksIDApO1xuXG4gICAgICAgIGlmIChjbG9zZVN0YXJ0QUNwKSB7XG4gICAgICAgICAgcnMuY3RybHB0c1swXSA9IHJzLmN0cmxwdHNbMF0gKyBjcE0ueCAqIChtaW5DcEFEaXN0IC0gc3RhcnRBQ3BEaXN0KTtcbiAgICAgICAgICBycy5jdHJscHRzWzFdID0gcnMuY3RybHB0c1sxXSArIGNwTS55ICogKG1pbkNwQURpc3QgLSBzdGFydEFDcERpc3QpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJzLmN0cmxwdHNbMF0gPSBzcmNDdHJsUHRJbnRuWzBdICsgY3BNLnggKiBtaW5DcEFEaXN0O1xuICAgICAgICAgIHJzLmN0cmxwdHNbMV0gPSBzcmNDdHJsUHRJbnRuWzFdICsgY3BNLnkgKiBtaW5DcEFEaXN0O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChiYWRFbmQgfHwgYmFkQUVuZCB8fCBjbG9zZUVuZEFDcCkge1xuICAgICAgICBvdmVybGFwcGluZyA9IHRydWU7IC8vIHByb2plY3QgY29udHJvbCBwb2ludCBhbG9uZyBsaW5lIGZyb20gdGd0IGNlbnRyZSB0byBvdXRzaWRlIHRoZSB0Z3Qgc2hhcGVcbiAgICAgICAgLy8gKG90aGVyd2lzZSBpbnRlcnNlY3Rpb24gd2lsbCB5aWVsZCBub3RoaW5nKVxuXG4gICAgICAgIHZhciBfY3BEID0ge1xuICAgICAgICAgIC8vIGRlbHRhXG4gICAgICAgICAgeDogcnMuY3RybHB0c1swXSAtIHRndFBvcy54LFxuICAgICAgICAgIHk6IHJzLmN0cmxwdHNbMV0gLSB0Z3RQb3MueVxuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBfY3BMID0gTWF0aC5zcXJ0KF9jcEQueCAqIF9jcEQueCArIF9jcEQueSAqIF9jcEQueSk7IC8vIGxlbmd0aCBvZiBsaW5lXG5cblxuICAgICAgICB2YXIgX2NwTSA9IHtcbiAgICAgICAgICAvLyBub3JtYWxpc2VkIGRlbHRhXG4gICAgICAgICAgeDogX2NwRC54IC8gX2NwTCxcbiAgICAgICAgICB5OiBfY3BELnkgLyBfY3BMXG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIF9yYWRpdXMgPSBNYXRoLm1heChzcmNXLCBzcmNIKTtcblxuICAgICAgICB2YXIgX2NwUHJvaiA9IHtcbiAgICAgICAgICAvLyAqMiByYWRpdXMgZ3VhcmFudGVlcyBvdXRzaWRlIHNoYXBlXG4gICAgICAgICAgeDogcnMuY3RybHB0c1swXSArIF9jcE0ueCAqIDIgKiBfcmFkaXVzLFxuICAgICAgICAgIHk6IHJzLmN0cmxwdHNbMV0gKyBfY3BNLnkgKiAyICogX3JhZGl1c1xuICAgICAgICB9O1xuICAgICAgICB2YXIgdGd0Q3RybFB0SW50biA9IHRndFNoYXBlLmludGVyc2VjdExpbmUodGd0UG9zLngsIHRndFBvcy55LCB0Z3RXLCB0Z3RILCBfY3BQcm9qLngsIF9jcFByb2oueSwgMCk7XG5cbiAgICAgICAgaWYgKGNsb3NlRW5kQUNwKSB7XG4gICAgICAgICAgcnMuY3RybHB0c1swXSA9IHJzLmN0cmxwdHNbMF0gKyBfY3BNLnggKiAobWluQ3BBRGlzdCAtIGVuZEFDcERpc3QpO1xuICAgICAgICAgIHJzLmN0cmxwdHNbMV0gPSBycy5jdHJscHRzWzFdICsgX2NwTS55ICogKG1pbkNwQURpc3QgLSBlbmRBQ3BEaXN0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBycy5jdHJscHRzWzBdID0gdGd0Q3RybFB0SW50blswXSArIF9jcE0ueCAqIG1pbkNwQURpc3Q7XG4gICAgICAgICAgcnMuY3RybHB0c1sxXSA9IHRndEN0cmxQdEludG5bMV0gKyBfY3BNLnkgKiBtaW5DcEFEaXN0O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChvdmVybGFwcGluZykge1xuICAgICAgICAvLyByZWNhbGMgZW5kcHRzXG4gICAgICAgIHRoaXMuZmluZEVuZHBvaW50cyhlZGdlKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgQlJwJGMuc3RvcmVBbGxwdHMgPSBmdW5jdGlvbiAoZWRnZSkge1xuICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7XG5cbiAgICBpZiAocnMuZWRnZVR5cGUgPT09ICdtdWx0aWJlemllcicgfHwgcnMuZWRnZVR5cGUgPT09ICdiZXppZXInIHx8IHJzLmVkZ2VUeXBlID09PSAnc2VsZicgfHwgcnMuZWRnZVR5cGUgPT09ICdjb21wb3VuZCcpIHtcbiAgICAgIHJzLmFsbHB0cyA9IFtdO1xuICAgICAgcnMuYWxscHRzLnB1c2gocnMuc3RhcnRYLCBycy5zdGFydFkpO1xuXG4gICAgICBmb3IgKHZhciBiID0gMDsgYiArIDEgPCBycy5jdHJscHRzLmxlbmd0aDsgYiArPSAyKSB7XG4gICAgICAgIC8vIGN0cmwgcHQgaXRzZWxmXG4gICAgICAgIHJzLmFsbHB0cy5wdXNoKHJzLmN0cmxwdHNbYl0sIHJzLmN0cmxwdHNbYiArIDFdKTsgLy8gdGhlIG1pZHB0IGJldHdlZW4gY3RybHB0cyBhcyBpbnRlcm1lZGlhdGUgZGVzdGluYXRpb24gcHRzXG5cbiAgICAgICAgaWYgKGIgKyAzIDwgcnMuY3RybHB0cy5sZW5ndGgpIHtcbiAgICAgICAgICBycy5hbGxwdHMucHVzaCgocnMuY3RybHB0c1tiXSArIHJzLmN0cmxwdHNbYiArIDJdKSAvIDIsIChycy5jdHJscHRzW2IgKyAxXSArIHJzLmN0cmxwdHNbYiArIDNdKSAvIDIpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJzLmFsbHB0cy5wdXNoKHJzLmVuZFgsIHJzLmVuZFkpO1xuICAgICAgdmFyIG0sIG10O1xuXG4gICAgICBpZiAocnMuY3RybHB0cy5sZW5ndGggLyAyICUgMiA9PT0gMCkge1xuICAgICAgICBtID0gcnMuYWxscHRzLmxlbmd0aCAvIDIgLSAxO1xuICAgICAgICBycy5taWRYID0gcnMuYWxscHRzW21dO1xuICAgICAgICBycy5taWRZID0gcnMuYWxscHRzW20gKyAxXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG0gPSBycy5hbGxwdHMubGVuZ3RoIC8gMiAtIDM7XG4gICAgICAgIG10ID0gMC41O1xuICAgICAgICBycy5taWRYID0gcWJlemllckF0KHJzLmFsbHB0c1ttXSwgcnMuYWxscHRzW20gKyAyXSwgcnMuYWxscHRzW20gKyA0XSwgbXQpO1xuICAgICAgICBycy5taWRZID0gcWJlemllckF0KHJzLmFsbHB0c1ttICsgMV0sIHJzLmFsbHB0c1ttICsgM10sIHJzLmFsbHB0c1ttICsgNV0sIG10KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHJzLmVkZ2VUeXBlID09PSAnc3RyYWlnaHQnKSB7XG4gICAgICAvLyBuZWVkIHRvIGNhbGMgdGhlc2UgYWZ0ZXIgZW5kcHRzXG4gICAgICBycy5hbGxwdHMgPSBbcnMuc3RhcnRYLCBycy5zdGFydFksIHJzLmVuZFgsIHJzLmVuZFldOyAvLyBkZWZhdWx0IG1pZHB0IGZvciBsYWJlbHMgZXRjXG5cbiAgICAgIHJzLm1pZFggPSAocnMuc3RhcnRYICsgcnMuZW5kWCArIHJzLmFycm93U3RhcnRYICsgcnMuYXJyb3dFbmRYKSAvIDQ7XG4gICAgICBycy5taWRZID0gKHJzLnN0YXJ0WSArIHJzLmVuZFkgKyBycy5hcnJvd1N0YXJ0WSArIHJzLmFycm93RW5kWSkgLyA0O1xuICAgIH0gZWxzZSBpZiAocnMuZWRnZVR5cGUgPT09ICdzZWdtZW50cycpIHtcbiAgICAgIHJzLmFsbHB0cyA9IFtdO1xuICAgICAgcnMuYWxscHRzLnB1c2gocnMuc3RhcnRYLCBycy5zdGFydFkpO1xuICAgICAgcnMuYWxscHRzLnB1c2guYXBwbHkocnMuYWxscHRzLCBycy5zZWdwdHMpO1xuICAgICAgcnMuYWxscHRzLnB1c2gocnMuZW5kWCwgcnMuZW5kWSk7XG5cbiAgICAgIGlmIChycy5zZWdwdHMubGVuZ3RoICUgNCA9PT0gMCkge1xuICAgICAgICB2YXIgaTIgPSBycy5zZWdwdHMubGVuZ3RoIC8gMjtcbiAgICAgICAgdmFyIGkxID0gaTIgLSAyO1xuICAgICAgICBycy5taWRYID0gKHJzLnNlZ3B0c1tpMV0gKyBycy5zZWdwdHNbaTJdKSAvIDI7XG4gICAgICAgIHJzLm1pZFkgPSAocnMuc2VncHRzW2kxICsgMV0gKyBycy5zZWdwdHNbaTIgKyAxXSkgLyAyO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIF9pID0gcnMuc2VncHRzLmxlbmd0aCAvIDIgLSAxO1xuXG4gICAgICAgIHJzLm1pZFggPSBycy5zZWdwdHNbX2ldO1xuICAgICAgICBycy5taWRZID0gcnMuc2VncHRzW19pICsgMV07XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIEJScCRjLmNoZWNrRm9ySW52YWxpZEVkZ2VXYXJuaW5nID0gZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICB2YXIgcnMgPSBlZGdlWzBdLl9wcml2YXRlLnJzY3JhdGNoO1xuXG4gICAgaWYgKHJzLm5vZGVzT3ZlcmxhcCB8fCBudW1iZXIkMShycy5zdGFydFgpICYmIG51bWJlciQxKHJzLnN0YXJ0WSkgJiYgbnVtYmVyJDEocnMuZW5kWCkgJiYgbnVtYmVyJDEocnMuZW5kWSkpIHtcbiAgICAgIHJzLmxvZ2dlZEVyciA9IGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoIXJzLmxvZ2dlZEVycikge1xuICAgICAgICBycy5sb2dnZWRFcnIgPSB0cnVlO1xuICAgICAgICB3YXJuKCdFZGdlIGAnICsgZWRnZS5pZCgpICsgJ2AgaGFzIGludmFsaWQgZW5kcG9pbnRzIGFuZCBzbyBpdCBpcyBpbXBvc3NpYmxlIHRvIGRyYXcuICBBZGp1c3QgeW91ciBlZGdlIHN0eWxlIChlLmcuIGNvbnRyb2wgcG9pbnRzKSBhY2NvcmRpbmdseSBvciB1c2UgYW4gYWx0ZXJuYXRpdmUgZWRnZSB0eXBlLiAgVGhpcyBpcyBleHBlY3RlZCBiZWhhdmlvdXIgd2hlbiB0aGUgc291cmNlIG5vZGUgYW5kIHRoZSB0YXJnZXQgbm9kZSBvdmVybGFwLicpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBCUnAkYy5maW5kRWRnZUNvbnRyb2xQb2ludHMgPSBmdW5jdGlvbiAoZWRnZXMpIHtcbiAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgaWYgKCFlZGdlcyB8fCBlZGdlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgciA9IHRoaXM7XG4gICAgdmFyIGN5ID0gci5jeTtcbiAgICB2YXIgaGFzQ29tcG91bmRzID0gY3kuaGFzQ29tcG91bmROb2RlcygpO1xuICAgIHZhciBoYXNoVGFibGUgPSB7XG4gICAgICBtYXA6IG5ldyBNYXAkMigpLFxuICAgICAgZ2V0OiBmdW5jdGlvbiBnZXQocGFpcklkKSB7XG4gICAgICAgIHZhciBtYXAyID0gdGhpcy5tYXAuZ2V0KHBhaXJJZFswXSk7XG5cbiAgICAgICAgaWYgKG1hcDIgIT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybiBtYXAyLmdldChwYWlySWRbMV0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgc2V0OiBmdW5jdGlvbiBzZXQocGFpcklkLCB2YWwpIHtcbiAgICAgICAgdmFyIG1hcDIgPSB0aGlzLm1hcC5nZXQocGFpcklkWzBdKTtcblxuICAgICAgICBpZiAobWFwMiA9PSBudWxsKSB7XG4gICAgICAgICAgbWFwMiA9IG5ldyBNYXAkMigpO1xuICAgICAgICAgIHRoaXMubWFwLnNldChwYWlySWRbMF0sIG1hcDIpO1xuICAgICAgICB9XG5cbiAgICAgICAgbWFwMi5zZXQocGFpcklkWzFdLCB2YWwpO1xuICAgICAgfVxuICAgIH07XG4gICAgdmFyIHBhaXJJZHMgPSBbXTtcbiAgICB2YXIgaGF5c3RhY2tFZGdlcyA9IFtdOyAvLyBjcmVhdGUgYSB0YWJsZSBvZiBlZGdlIChzcmMsIHRndCkgPT4gbGlzdCBvZiBlZGdlcyBiZXR3ZWVuIHRoZW1cblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWRnZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBlZGdlID0gZWRnZXNbaV07XG4gICAgICB2YXIgX3AgPSBlZGdlLl9wcml2YXRlO1xuICAgICAgdmFyIGN1cnZlU3R5bGUgPSBlZGdlLnBzdHlsZSgnY3VydmUtc3R5bGUnKS52YWx1ZTsgLy8gaWdub3JlIGVkZ2VzIHdobyBhcmUgbm90IHRvIGJlIGRpc3BsYXllZFxuICAgICAgLy8gdGhleSBzaG91bGRuJ3QgdGFrZSB1cCBzcGFjZVxuXG4gICAgICBpZiAoZWRnZS5yZW1vdmVkKCkgfHwgIWVkZ2UudGFrZXNVcFNwYWNlKCkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGlmIChjdXJ2ZVN0eWxlID09PSAnaGF5c3RhY2snKSB7XG4gICAgICAgIGhheXN0YWNrRWRnZXMucHVzaChlZGdlKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIHZhciBlZGdlSXNVbmJ1bmRsZWQgPSBjdXJ2ZVN0eWxlID09PSAndW5idW5kbGVkLWJlemllcicgfHwgY3VydmVTdHlsZSA9PT0gJ3NlZ21lbnRzJyB8fCBjdXJ2ZVN0eWxlID09PSAnc3RyYWlnaHQnIHx8IGN1cnZlU3R5bGUgPT09ICdzdHJhaWdodC10cmlhbmdsZScgfHwgY3VydmVTdHlsZSA9PT0gJ3RheGknO1xuICAgICAgdmFyIGVkZ2VJc0JlemllciA9IGN1cnZlU3R5bGUgPT09ICd1bmJ1bmRsZWQtYmV6aWVyJyB8fCBjdXJ2ZVN0eWxlID09PSAnYmV6aWVyJztcbiAgICAgIHZhciBzcmMgPSBfcC5zb3VyY2U7XG4gICAgICB2YXIgdGd0ID0gX3AudGFyZ2V0O1xuICAgICAgdmFyIHNyY0luZGV4ID0gc3JjLnBvb2xJbmRleCgpO1xuICAgICAgdmFyIHRndEluZGV4ID0gdGd0LnBvb2xJbmRleCgpO1xuICAgICAgdmFyIHBhaXJJZCA9IFtzcmNJbmRleCwgdGd0SW5kZXhdLnNvcnQoKTtcbiAgICAgIHZhciB0YWJsZUVudHJ5ID0gaGFzaFRhYmxlLmdldChwYWlySWQpO1xuXG4gICAgICBpZiAodGFibGVFbnRyeSA9PSBudWxsKSB7XG4gICAgICAgIHRhYmxlRW50cnkgPSB7XG4gICAgICAgICAgZWxlczogW11cbiAgICAgICAgfTtcbiAgICAgICAgaGFzaFRhYmxlLnNldChwYWlySWQsIHRhYmxlRW50cnkpO1xuICAgICAgICBwYWlySWRzLnB1c2gocGFpcklkKTtcbiAgICAgIH1cblxuICAgICAgdGFibGVFbnRyeS5lbGVzLnB1c2goZWRnZSk7XG5cbiAgICAgIGlmIChlZGdlSXNVbmJ1bmRsZWQpIHtcbiAgICAgICAgdGFibGVFbnRyeS5oYXNVbmJ1bmRsZWQgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoZWRnZUlzQmV6aWVyKSB7XG4gICAgICAgIHRhYmxlRW50cnkuaGFzQmV6aWVyID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9IC8vIGZvciBlYWNoIHBhaXIgKHNyYywgdGd0KSwgY3JlYXRlIHRoZSBjdHJsIHB0c1xuICAgIC8vIE5lc3RlZCBmb3IgbG9vcCBpcyBPSzsgdG90YWwgbnVtYmVyIG9mIGl0ZXJhdGlvbnMgZm9yIGJvdGggbG9vcHMgPSBlZGdlQ291bnRcblxuXG4gICAgdmFyIF9sb29wID0gZnVuY3Rpb24gX2xvb3AocCkge1xuICAgICAgdmFyIHBhaXJJZCA9IHBhaXJJZHNbcF07XG4gICAgICB2YXIgcGFpckluZm8gPSBoYXNoVGFibGUuZ2V0KHBhaXJJZCk7XG4gICAgICB2YXIgc3dhcHBlZHBhaXJJbmZvID0gdm9pZCAwO1xuXG4gICAgICBpZiAoIXBhaXJJbmZvLmhhc1VuYnVuZGxlZCkge1xuICAgICAgICB2YXIgcGxsRWRnZXMgPSBwYWlySW5mby5lbGVzWzBdLnBhcmFsbGVsRWRnZXMoKS5maWx0ZXIoZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICByZXR1cm4gZS5pc0J1bmRsZWRCZXppZXIoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGNsZWFyQXJyYXkocGFpckluZm8uZWxlcyk7XG4gICAgICAgIHBsbEVkZ2VzLmZvckVhY2goZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICAgICAgICByZXR1cm4gcGFpckluZm8uZWxlcy5wdXNoKGVkZ2UpO1xuICAgICAgICB9KTsgLy8gZm9yIGVhY2ggcGFpciBpZCwgdGhlIGVkZ2VzIHNob3VsZCBiZSBzb3J0ZWQgYnkgaW5kZXhcblxuICAgICAgICBwYWlySW5mby5lbGVzLnNvcnQoZnVuY3Rpb24gKGVkZ2UxLCBlZGdlMikge1xuICAgICAgICAgIHJldHVybiBlZGdlMS5wb29sSW5kZXgoKSAtIGVkZ2UyLnBvb2xJbmRleCgpO1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdmFyIGZpcnN0RWRnZSA9IHBhaXJJbmZvLmVsZXNbMF07XG4gICAgICB2YXIgc3JjID0gZmlyc3RFZGdlLnNvdXJjZSgpO1xuICAgICAgdmFyIHRndCA9IGZpcnN0RWRnZS50YXJnZXQoKTsgLy8gbWFrZSBzdXJlIHNyYy90Z3QgZGlzdGluY3Rpb24gaXMgY29uc2lzdGVudCB3LnIudC4gcGFpcklkXG5cbiAgICAgIGlmIChzcmMucG9vbEluZGV4KCkgPiB0Z3QucG9vbEluZGV4KCkpIHtcbiAgICAgICAgdmFyIHRlbXAgPSBzcmM7XG4gICAgICAgIHNyYyA9IHRndDtcbiAgICAgICAgdGd0ID0gdGVtcDtcbiAgICAgIH1cblxuICAgICAgdmFyIHNyY1BvcyA9IHBhaXJJbmZvLnNyY1BvcyA9IHNyYy5wb3NpdGlvbigpO1xuICAgICAgdmFyIHRndFBvcyA9IHBhaXJJbmZvLnRndFBvcyA9IHRndC5wb3NpdGlvbigpO1xuICAgICAgdmFyIHNyY1cgPSBwYWlySW5mby5zcmNXID0gc3JjLm91dGVyV2lkdGgoKTtcbiAgICAgIHZhciBzcmNIID0gcGFpckluZm8uc3JjSCA9IHNyYy5vdXRlckhlaWdodCgpO1xuICAgICAgdmFyIHRndFcgPSBwYWlySW5mby50Z3RXID0gdGd0Lm91dGVyV2lkdGgoKTtcbiAgICAgIHZhciB0Z3RIID0gcGFpckluZm8udGd0SCA9IHRndC5vdXRlckhlaWdodCgpO1xuXG4gICAgICB2YXIgc3JjU2hhcGUgPSBwYWlySW5mby5zcmNTaGFwZSA9IHIubm9kZVNoYXBlc1tfdGhpcy5nZXROb2RlU2hhcGUoc3JjKV07XG5cbiAgICAgIHZhciB0Z3RTaGFwZSA9IHBhaXJJbmZvLnRndFNoYXBlID0gci5ub2RlU2hhcGVzW190aGlzLmdldE5vZGVTaGFwZSh0Z3QpXTtcblxuICAgICAgcGFpckluZm8uZGlyQ291bnRzID0ge1xuICAgICAgICAnbm9ydGgnOiAwLFxuICAgICAgICAnd2VzdCc6IDAsXG4gICAgICAgICdzb3V0aCc6IDAsXG4gICAgICAgICdlYXN0JzogMCxcbiAgICAgICAgJ25vcnRod2VzdCc6IDAsXG4gICAgICAgICdzb3V0aHdlc3QnOiAwLFxuICAgICAgICAnbm9ydGhlYXN0JzogMCxcbiAgICAgICAgJ3NvdXRoZWFzdCc6IDBcbiAgICAgIH07XG5cbiAgICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IHBhaXJJbmZvLmVsZXMubGVuZ3RoOyBfaTIrKykge1xuICAgICAgICB2YXIgX2VkZ2UgPSBwYWlySW5mby5lbGVzW19pMl07XG4gICAgICAgIHZhciBycyA9IF9lZGdlWzBdLl9wcml2YXRlLnJzY3JhdGNoO1xuXG4gICAgICAgIHZhciBfY3VydmVTdHlsZSA9IF9lZGdlLnBzdHlsZSgnY3VydmUtc3R5bGUnKS52YWx1ZTtcblxuICAgICAgICB2YXIgX2VkZ2VJc1VuYnVuZGxlZCA9IF9jdXJ2ZVN0eWxlID09PSAndW5idW5kbGVkLWJlemllcicgfHwgX2N1cnZlU3R5bGUgPT09ICdzZWdtZW50cycgfHwgX2N1cnZlU3R5bGUgPT09ICd0YXhpJzsgLy8gd2hldGhlciB0aGUgbm9ybWFsaXNlZCBwYWlyIG9yZGVyIGlzIHRoZSByZXZlcnNlIG9mIHRoZSBlZGdlJ3Mgc3JjLXRndCBvcmRlclxuXG5cbiAgICAgICAgdmFyIGVkZ2VJc1N3YXBwZWQgPSAhc3JjLnNhbWUoX2VkZ2Uuc291cmNlKCkpO1xuXG4gICAgICAgIGlmICghcGFpckluZm8uY2FsY3VsYXRlZEludGVyc2VjdGlvbiAmJiBzcmMgIT09IHRndCAmJiAocGFpckluZm8uaGFzQmV6aWVyIHx8IHBhaXJJbmZvLmhhc1VuYnVuZGxlZCkpIHtcbiAgICAgICAgICBwYWlySW5mby5jYWxjdWxhdGVkSW50ZXJzZWN0aW9uID0gdHJ1ZTsgLy8gcHQgb3V0c2lkZSBzcmMgc2hhcGUgdG8gY2FsYyBkaXN0YW5jZS9kaXNwbGFjZW1lbnQgZnJvbSBzcmMgdG8gdGd0XG5cbiAgICAgICAgICB2YXIgc3JjT3V0c2lkZSA9IHNyY1NoYXBlLmludGVyc2VjdExpbmUoc3JjUG9zLngsIHNyY1Bvcy55LCBzcmNXLCBzcmNILCB0Z3RQb3MueCwgdGd0UG9zLnksIDApO1xuICAgICAgICAgIHZhciBzcmNJbnRuID0gcGFpckluZm8uc3JjSW50biA9IHNyY091dHNpZGU7IC8vIHB0IG91dHNpZGUgdGd0IHNoYXBlIHRvIGNhbGMgZGlzdGFuY2UvZGlzcGxhY2VtZW50IGZyb20gc3JjIHRvIHRndFxuXG4gICAgICAgICAgdmFyIHRndE91dHNpZGUgPSB0Z3RTaGFwZS5pbnRlcnNlY3RMaW5lKHRndFBvcy54LCB0Z3RQb3MueSwgdGd0VywgdGd0SCwgc3JjUG9zLngsIHNyY1Bvcy55LCAwKTtcbiAgICAgICAgICB2YXIgdGd0SW50biA9IHBhaXJJbmZvLnRndEludG4gPSB0Z3RPdXRzaWRlO1xuICAgICAgICAgIHZhciBpbnRlcnNlY3Rpb25QdHMgPSBwYWlySW5mby5pbnRlcnNlY3Rpb25QdHMgPSB7XG4gICAgICAgICAgICB4MTogc3JjT3V0c2lkZVswXSxcbiAgICAgICAgICAgIHgyOiB0Z3RPdXRzaWRlWzBdLFxuICAgICAgICAgICAgeTE6IHNyY091dHNpZGVbMV0sXG4gICAgICAgICAgICB5MjogdGd0T3V0c2lkZVsxXVxuICAgICAgICAgIH07XG4gICAgICAgICAgdmFyIHBvc1B0cyA9IHBhaXJJbmZvLnBvc1B0cyA9IHtcbiAgICAgICAgICAgIHgxOiBzcmNQb3MueCxcbiAgICAgICAgICAgIHgyOiB0Z3RQb3MueCxcbiAgICAgICAgICAgIHkxOiBzcmNQb3MueSxcbiAgICAgICAgICAgIHkyOiB0Z3RQb3MueVxuICAgICAgICAgIH07XG4gICAgICAgICAgdmFyIGR5ID0gdGd0T3V0c2lkZVsxXSAtIHNyY091dHNpZGVbMV07XG4gICAgICAgICAgdmFyIGR4ID0gdGd0T3V0c2lkZVswXSAtIHNyY091dHNpZGVbMF07XG4gICAgICAgICAgdmFyIGwgPSBNYXRoLnNxcnQoZHggKiBkeCArIGR5ICogZHkpO1xuICAgICAgICAgIHZhciB2ZWN0b3IgPSBwYWlySW5mby52ZWN0b3IgPSB7XG4gICAgICAgICAgICB4OiBkeCxcbiAgICAgICAgICAgIHk6IGR5XG4gICAgICAgICAgfTtcbiAgICAgICAgICB2YXIgdmVjdG9yTm9ybSA9IHBhaXJJbmZvLnZlY3Rvck5vcm0gPSB7XG4gICAgICAgICAgICB4OiB2ZWN0b3IueCAvIGwsXG4gICAgICAgICAgICB5OiB2ZWN0b3IueSAvIGxcbiAgICAgICAgICB9O1xuICAgICAgICAgIHZhciB2ZWN0b3JOb3JtSW52ZXJzZSA9IHtcbiAgICAgICAgICAgIHg6IC12ZWN0b3JOb3JtLnksXG4gICAgICAgICAgICB5OiB2ZWN0b3JOb3JtLnhcbiAgICAgICAgICB9OyAvLyBpZiBub2RlIHNoYXBlcyBvdmVybGFwLCB0aGVuIG5vIGN0cmwgcHRzIHRvIGRyYXdcblxuICAgICAgICAgIHBhaXJJbmZvLm5vZGVzT3ZlcmxhcCA9ICFudW1iZXIkMShsKSB8fCB0Z3RTaGFwZS5jaGVja1BvaW50KHNyY091dHNpZGVbMF0sIHNyY091dHNpZGVbMV0sIDAsIHRndFcsIHRndEgsIHRndFBvcy54LCB0Z3RQb3MueSkgfHwgc3JjU2hhcGUuY2hlY2tQb2ludCh0Z3RPdXRzaWRlWzBdLCB0Z3RPdXRzaWRlWzFdLCAwLCBzcmNXLCBzcmNILCBzcmNQb3MueCwgc3JjUG9zLnkpO1xuICAgICAgICAgIHBhaXJJbmZvLnZlY3Rvck5vcm1JbnZlcnNlID0gdmVjdG9yTm9ybUludmVyc2U7XG4gICAgICAgICAgc3dhcHBlZHBhaXJJbmZvID0ge1xuICAgICAgICAgICAgbm9kZXNPdmVybGFwOiBwYWlySW5mby5ub2Rlc092ZXJsYXAsXG4gICAgICAgICAgICBkaXJDb3VudHM6IHBhaXJJbmZvLmRpckNvdW50cyxcbiAgICAgICAgICAgIGNhbGN1bGF0ZWRJbnRlcnNlY3Rpb246IHRydWUsXG4gICAgICAgICAgICBoYXNCZXppZXI6IHBhaXJJbmZvLmhhc0JlemllcixcbiAgICAgICAgICAgIGhhc1VuYnVuZGxlZDogcGFpckluZm8uaGFzVW5idW5kbGVkLFxuICAgICAgICAgICAgZWxlczogcGFpckluZm8uZWxlcyxcbiAgICAgICAgICAgIHNyY1BvczogdGd0UG9zLFxuICAgICAgICAgICAgdGd0UG9zOiBzcmNQb3MsXG4gICAgICAgICAgICBzcmNXOiB0Z3RXLFxuICAgICAgICAgICAgc3JjSDogdGd0SCxcbiAgICAgICAgICAgIHRndFc6IHNyY1csXG4gICAgICAgICAgICB0Z3RIOiBzcmNILFxuICAgICAgICAgICAgc3JjSW50bjogdGd0SW50bixcbiAgICAgICAgICAgIHRndEludG46IHNyY0ludG4sXG4gICAgICAgICAgICBzcmNTaGFwZTogdGd0U2hhcGUsXG4gICAgICAgICAgICB0Z3RTaGFwZTogc3JjU2hhcGUsXG4gICAgICAgICAgICBwb3NQdHM6IHtcbiAgICAgICAgICAgICAgeDE6IHBvc1B0cy54MixcbiAgICAgICAgICAgICAgeTE6IHBvc1B0cy55MixcbiAgICAgICAgICAgICAgeDI6IHBvc1B0cy54MSxcbiAgICAgICAgICAgICAgeTI6IHBvc1B0cy55MVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGludGVyc2VjdGlvblB0czoge1xuICAgICAgICAgICAgICB4MTogaW50ZXJzZWN0aW9uUHRzLngyLFxuICAgICAgICAgICAgICB5MTogaW50ZXJzZWN0aW9uUHRzLnkyLFxuICAgICAgICAgICAgICB4MjogaW50ZXJzZWN0aW9uUHRzLngxLFxuICAgICAgICAgICAgICB5MjogaW50ZXJzZWN0aW9uUHRzLnkxXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdmVjdG9yOiB7XG4gICAgICAgICAgICAgIHg6IC12ZWN0b3IueCxcbiAgICAgICAgICAgICAgeTogLXZlY3Rvci55XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdmVjdG9yTm9ybToge1xuICAgICAgICAgICAgICB4OiAtdmVjdG9yTm9ybS54LFxuICAgICAgICAgICAgICB5OiAtdmVjdG9yTm9ybS55XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdmVjdG9yTm9ybUludmVyc2U6IHtcbiAgICAgICAgICAgICAgeDogLXZlY3Rvck5vcm1JbnZlcnNlLngsXG4gICAgICAgICAgICAgIHk6IC12ZWN0b3JOb3JtSW52ZXJzZS55XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBwYXNzZWRQYWlySW5mbyA9IGVkZ2VJc1N3YXBwZWQgPyBzd2FwcGVkcGFpckluZm8gOiBwYWlySW5mbztcbiAgICAgICAgcnMubm9kZXNPdmVybGFwID0gcGFzc2VkUGFpckluZm8ubm9kZXNPdmVybGFwO1xuICAgICAgICBycy5zcmNJbnRuID0gcGFzc2VkUGFpckluZm8uc3JjSW50bjtcbiAgICAgICAgcnMudGd0SW50biA9IHBhc3NlZFBhaXJJbmZvLnRndEludG47XG5cbiAgICAgICAgaWYgKGhhc0NvbXBvdW5kcyAmJiAoc3JjLmlzUGFyZW50KCkgfHwgc3JjLmlzQ2hpbGQoKSB8fCB0Z3QuaXNQYXJlbnQoKSB8fCB0Z3QuaXNDaGlsZCgpKSAmJiAoc3JjLnBhcmVudHMoKS5hbnlTYW1lKHRndCkgfHwgdGd0LnBhcmVudHMoKS5hbnlTYW1lKHNyYykgfHwgc3JjLnNhbWUodGd0KSAmJiBzcmMuaXNQYXJlbnQoKSkpIHtcbiAgICAgICAgICBfdGhpcy5maW5kQ29tcG91bmRMb29wUG9pbnRzKF9lZGdlLCBwYXNzZWRQYWlySW5mbywgX2kyLCBfZWRnZUlzVW5idW5kbGVkKTtcbiAgICAgICAgfSBlbHNlIGlmIChzcmMgPT09IHRndCkge1xuICAgICAgICAgIF90aGlzLmZpbmRMb29wUG9pbnRzKF9lZGdlLCBwYXNzZWRQYWlySW5mbywgX2kyLCBfZWRnZUlzVW5idW5kbGVkKTtcbiAgICAgICAgfSBlbHNlIGlmIChfY3VydmVTdHlsZSA9PT0gJ3NlZ21lbnRzJykge1xuICAgICAgICAgIF90aGlzLmZpbmRTZWdtZW50c1BvaW50cyhfZWRnZSwgcGFzc2VkUGFpckluZm8pO1xuICAgICAgICB9IGVsc2UgaWYgKF9jdXJ2ZVN0eWxlID09PSAndGF4aScpIHtcbiAgICAgICAgICBfdGhpcy5maW5kVGF4aVBvaW50cyhfZWRnZSwgcGFzc2VkUGFpckluZm8pO1xuICAgICAgICB9IGVsc2UgaWYgKF9jdXJ2ZVN0eWxlID09PSAnc3RyYWlnaHQnIHx8ICFfZWRnZUlzVW5idW5kbGVkICYmIHBhaXJJbmZvLmVsZXMubGVuZ3RoICUgMiA9PT0gMSAmJiBfaTIgPT09IE1hdGguZmxvb3IocGFpckluZm8uZWxlcy5sZW5ndGggLyAyKSkge1xuICAgICAgICAgIF90aGlzLmZpbmRTdHJhaWdodEVkZ2VQb2ludHMoX2VkZ2UpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIF90aGlzLmZpbmRCZXppZXJQb2ludHMoX2VkZ2UsIHBhc3NlZFBhaXJJbmZvLCBfaTIsIF9lZGdlSXNVbmJ1bmRsZWQsIGVkZ2VJc1N3YXBwZWQpO1xuICAgICAgICB9XG5cbiAgICAgICAgX3RoaXMuZmluZEVuZHBvaW50cyhfZWRnZSk7XG5cbiAgICAgICAgX3RoaXMudHJ5VG9Db3JyZWN0SW52YWxpZFBvaW50cyhfZWRnZSwgcGFzc2VkUGFpckluZm8pO1xuXG4gICAgICAgIF90aGlzLmNoZWNrRm9ySW52YWxpZEVkZ2VXYXJuaW5nKF9lZGdlKTtcblxuICAgICAgICBfdGhpcy5zdG9yZUFsbHB0cyhfZWRnZSk7XG5cbiAgICAgICAgX3RoaXMuc3RvcmVFZGdlUHJvamVjdGlvbnMoX2VkZ2UpO1xuXG4gICAgICAgIF90aGlzLmNhbGN1bGF0ZUFycm93QW5nbGVzKF9lZGdlKTtcblxuICAgICAgICBfdGhpcy5yZWNhbGN1bGF0ZUVkZ2VMYWJlbFByb2plY3Rpb25zKF9lZGdlKTtcblxuICAgICAgICBfdGhpcy5jYWxjdWxhdGVMYWJlbEFuZ2xlcyhfZWRnZSk7XG4gICAgICB9IC8vIGZvciBwYWlyIGVkZ2VzXG5cbiAgICB9O1xuXG4gICAgZm9yICh2YXIgcCA9IDA7IHAgPCBwYWlySWRzLmxlbmd0aDsgcCsrKSB7XG4gICAgICBfbG9vcChwKTtcbiAgICB9IC8vIGZvciBwYWlyIGlkc1xuICAgIC8vIGhheXN0YWNrcyBhdm9pZCB0aGUgZXhwZW5zZSBvZiBwYWlySW5mbyBzdHVmZiAoaW50ZXJzZWN0aW9ucyBldGMuKVxuXG5cbiAgICB0aGlzLmZpbmRIYXlzdGFja1BvaW50cyhoYXlzdGFja0VkZ2VzKTtcbiAgfTtcblxuICBmdW5jdGlvbiBnZXRQdHMocHRzKSB7XG4gICAgdmFyIHJldFB0cyA9IFtdO1xuXG4gICAgaWYgKHB0cyA9PSBudWxsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwdHMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgIHZhciB4ID0gcHRzW2ldO1xuICAgICAgdmFyIHkgPSBwdHNbaSArIDFdO1xuICAgICAgcmV0UHRzLnB1c2goe1xuICAgICAgICB4OiB4LFxuICAgICAgICB5OiB5XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmV0UHRzO1xuICB9XG5cbiAgQlJwJGMuZ2V0U2VnbWVudFBvaW50cyA9IGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgdmFyIHJzID0gZWRnZVswXS5fcHJpdmF0ZS5yc2NyYXRjaDtcbiAgICB2YXIgdHlwZSA9IHJzLmVkZ2VUeXBlO1xuXG4gICAgaWYgKHR5cGUgPT09ICdzZWdtZW50cycpIHtcbiAgICAgIHRoaXMucmVjYWxjdWxhdGVSZW5kZXJlZFN0eWxlKGVkZ2UpO1xuICAgICAgcmV0dXJuIGdldFB0cyhycy5zZWdwdHMpO1xuICAgIH1cbiAgfTtcblxuICBCUnAkYy5nZXRDb250cm9sUG9pbnRzID0gZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICB2YXIgcnMgPSBlZGdlWzBdLl9wcml2YXRlLnJzY3JhdGNoO1xuICAgIHZhciB0eXBlID0gcnMuZWRnZVR5cGU7XG5cbiAgICBpZiAodHlwZSA9PT0gJ2JlemllcicgfHwgdHlwZSA9PT0gJ211bHRpYmV6aWVyJyB8fCB0eXBlID09PSAnc2VsZicgfHwgdHlwZSA9PT0gJ2NvbXBvdW5kJykge1xuICAgICAgdGhpcy5yZWNhbGN1bGF0ZVJlbmRlcmVkU3R5bGUoZWRnZSk7XG4gICAgICByZXR1cm4gZ2V0UHRzKHJzLmN0cmxwdHMpO1xuICAgIH1cbiAgfTtcblxuICBCUnAkYy5nZXRFZGdlTWlkcG9pbnQgPSBmdW5jdGlvbiAoZWRnZSkge1xuICAgIHZhciBycyA9IGVkZ2VbMF0uX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgdGhpcy5yZWNhbGN1bGF0ZVJlbmRlcmVkU3R5bGUoZWRnZSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHg6IHJzLm1pZFgsXG4gICAgICB5OiBycy5taWRZXG4gICAgfTtcbiAgfTtcblxuICB2YXIgQlJwJGIgPSB7fTtcblxuICBCUnAkYi5tYW51YWxFbmRwdFRvUHggPSBmdW5jdGlvbiAobm9kZSwgcHJvcCkge1xuICAgIHZhciByID0gdGhpcztcbiAgICB2YXIgbnBvcyA9IG5vZGUucG9zaXRpb24oKTtcbiAgICB2YXIgdyA9IG5vZGUub3V0ZXJXaWR0aCgpO1xuICAgIHZhciBoID0gbm9kZS5vdXRlckhlaWdodCgpO1xuXG4gICAgaWYgKHByb3AudmFsdWUubGVuZ3RoID09PSAyKSB7XG4gICAgICB2YXIgcCA9IFtwcm9wLnBmVmFsdWVbMF0sIHByb3AucGZWYWx1ZVsxXV07XG5cbiAgICAgIGlmIChwcm9wLnVuaXRzWzBdID09PSAnJScpIHtcbiAgICAgICAgcFswXSA9IHBbMF0gKiB3O1xuICAgICAgfVxuXG4gICAgICBpZiAocHJvcC51bml0c1sxXSA9PT0gJyUnKSB7XG4gICAgICAgIHBbMV0gPSBwWzFdICogaDtcbiAgICAgIH1cblxuICAgICAgcFswXSArPSBucG9zLng7XG4gICAgICBwWzFdICs9IG5wb3MueTtcbiAgICAgIHJldHVybiBwO1xuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgYW5nbGUgPSBwcm9wLnBmVmFsdWVbMF07XG4gICAgICBhbmdsZSA9IC1NYXRoLlBJIC8gMiArIGFuZ2xlOyAvLyBzdGFydCBhdCAxMiBvJ2Nsb2NrXG5cbiAgICAgIHZhciBsID0gMiAqIE1hdGgubWF4KHcsIGgpO1xuICAgICAgdmFyIF9wID0gW25wb3MueCArIE1hdGguY29zKGFuZ2xlKSAqIGwsIG5wb3MueSArIE1hdGguc2luKGFuZ2xlKSAqIGxdO1xuICAgICAgcmV0dXJuIHIubm9kZVNoYXBlc1t0aGlzLmdldE5vZGVTaGFwZShub2RlKV0uaW50ZXJzZWN0TGluZShucG9zLngsIG5wb3MueSwgdywgaCwgX3BbMF0sIF9wWzFdLCAwKTtcbiAgICB9XG4gIH07XG5cbiAgQlJwJGIuZmluZEVuZHBvaW50cyA9IGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBpbnRlcnNlY3Q7XG4gICAgdmFyIHNvdXJjZSA9IGVkZ2Uuc291cmNlKClbMF07XG4gICAgdmFyIHRhcmdldCA9IGVkZ2UudGFyZ2V0KClbMF07XG4gICAgdmFyIHNyY1BvcyA9IHNvdXJjZS5wb3NpdGlvbigpO1xuICAgIHZhciB0Z3RQb3MgPSB0YXJnZXQucG9zaXRpb24oKTtcbiAgICB2YXIgdGd0QXJTaGFwZSA9IGVkZ2UucHN0eWxlKCd0YXJnZXQtYXJyb3ctc2hhcGUnKS52YWx1ZTtcbiAgICB2YXIgc3JjQXJTaGFwZSA9IGVkZ2UucHN0eWxlKCdzb3VyY2UtYXJyb3ctc2hhcGUnKS52YWx1ZTtcbiAgICB2YXIgdGd0RGlzdCA9IGVkZ2UucHN0eWxlKCd0YXJnZXQtZGlzdGFuY2UtZnJvbS1ub2RlJykucGZWYWx1ZTtcbiAgICB2YXIgc3JjRGlzdCA9IGVkZ2UucHN0eWxlKCdzb3VyY2UtZGlzdGFuY2UtZnJvbS1ub2RlJykucGZWYWx1ZTtcbiAgICB2YXIgY3VydmVTdHlsZSA9IGVkZ2UucHN0eWxlKCdjdXJ2ZS1zdHlsZScpLnZhbHVlO1xuICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgdmFyIGV0ID0gcnMuZWRnZVR5cGU7XG4gICAgdmFyIHRheGkgPSBjdXJ2ZVN0eWxlID09PSAndGF4aSc7XG4gICAgdmFyIHNlbGYgPSBldCA9PT0gJ3NlbGYnIHx8IGV0ID09PSAnY29tcG91bmQnO1xuICAgIHZhciBiZXppZXIgPSBldCA9PT0gJ2JlemllcicgfHwgZXQgPT09ICdtdWx0aWJlemllcicgfHwgc2VsZjtcbiAgICB2YXIgbXVsdGkgPSBldCAhPT0gJ2Jlemllcic7XG4gICAgdmFyIGxpbmVzID0gZXQgPT09ICdzdHJhaWdodCcgfHwgZXQgPT09ICdzZWdtZW50cyc7XG4gICAgdmFyIHNlZ21lbnRzID0gZXQgPT09ICdzZWdtZW50cyc7XG4gICAgdmFyIGhhc0VuZHB0cyA9IGJlemllciB8fCBtdWx0aSB8fCBsaW5lcztcbiAgICB2YXIgb3ZlcnJpZGVFbmRwdHMgPSBzZWxmIHx8IHRheGk7XG4gICAgdmFyIHNyY01hbkVuZHB0ID0gZWRnZS5wc3R5bGUoJ3NvdXJjZS1lbmRwb2ludCcpO1xuICAgIHZhciBzcmNNYW5FbmRwdFZhbCA9IG92ZXJyaWRlRW5kcHRzID8gJ291dHNpZGUtdG8tbm9kZScgOiBzcmNNYW5FbmRwdC52YWx1ZTtcbiAgICB2YXIgdGd0TWFuRW5kcHQgPSBlZGdlLnBzdHlsZSgndGFyZ2V0LWVuZHBvaW50Jyk7XG4gICAgdmFyIHRndE1hbkVuZHB0VmFsID0gb3ZlcnJpZGVFbmRwdHMgPyAnb3V0c2lkZS10by1ub2RlJyA6IHRndE1hbkVuZHB0LnZhbHVlO1xuICAgIHJzLnNyY01hbkVuZHB0ID0gc3JjTWFuRW5kcHQ7XG4gICAgcnMudGd0TWFuRW5kcHQgPSB0Z3RNYW5FbmRwdDtcbiAgICB2YXIgcDE7IC8vIGxhc3Qga25vd24gcG9pbnQgb2YgZWRnZSBvbiB0YXJnZXQgc2lkZVxuXG4gICAgdmFyIHAyOyAvLyBsYXN0IGtub3duIHBvaW50IG9mIGVkZ2Ugb24gc291cmNlIHNpZGVcblxuICAgIHZhciBwMV9pOyAvLyBwb2ludCB0byBpbnRlcnNlY3Qgd2l0aCB0YXJnZXQgc2hhcGVcblxuICAgIHZhciBwMl9pOyAvLyBwb2ludCB0byBpbnRlcnNlY3Qgd2l0aCBzb3VyY2Ugc2hhcGVcblxuICAgIGlmIChiZXppZXIpIHtcbiAgICAgIHZhciBjcFN0YXJ0ID0gW3JzLmN0cmxwdHNbMF0sIHJzLmN0cmxwdHNbMV1dO1xuICAgICAgdmFyIGNwRW5kID0gbXVsdGkgPyBbcnMuY3RybHB0c1tycy5jdHJscHRzLmxlbmd0aCAtIDJdLCBycy5jdHJscHRzW3JzLmN0cmxwdHMubGVuZ3RoIC0gMV1dIDogY3BTdGFydDtcbiAgICAgIHAxID0gY3BFbmQ7XG4gICAgICBwMiA9IGNwU3RhcnQ7XG4gICAgfSBlbHNlIGlmIChsaW5lcykge1xuICAgICAgdmFyIHNyY0Fycm93RnJvbVB0ID0gIXNlZ21lbnRzID8gW3RndFBvcy54LCB0Z3RQb3MueV0gOiBycy5zZWdwdHMuc2xpY2UoMCwgMik7XG4gICAgICB2YXIgdGd0QXJyb3dGcm9tUHQgPSAhc2VnbWVudHMgPyBbc3JjUG9zLngsIHNyY1Bvcy55XSA6IHJzLnNlZ3B0cy5zbGljZShycy5zZWdwdHMubGVuZ3RoIC0gMik7XG4gICAgICBwMSA9IHRndEFycm93RnJvbVB0O1xuICAgICAgcDIgPSBzcmNBcnJvd0Zyb21QdDtcbiAgICB9XG5cbiAgICBpZiAodGd0TWFuRW5kcHRWYWwgPT09ICdpbnNpZGUtdG8tbm9kZScpIHtcbiAgICAgIGludGVyc2VjdCA9IFt0Z3RQb3MueCwgdGd0UG9zLnldO1xuICAgIH0gZWxzZSBpZiAodGd0TWFuRW5kcHQudW5pdHMpIHtcbiAgICAgIGludGVyc2VjdCA9IHRoaXMubWFudWFsRW5kcHRUb1B4KHRhcmdldCwgdGd0TWFuRW5kcHQpO1xuICAgIH0gZWxzZSBpZiAodGd0TWFuRW5kcHRWYWwgPT09ICdvdXRzaWRlLXRvLWxpbmUnKSB7XG4gICAgICBpbnRlcnNlY3QgPSBycy50Z3RJbnRuOyAvLyB1c2UgY2FjaGVkIHZhbHVlIGZyb20gY3RybHB0IGNhbGNcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHRndE1hbkVuZHB0VmFsID09PSAnb3V0c2lkZS10by1ub2RlJyB8fCB0Z3RNYW5FbmRwdFZhbCA9PT0gJ291dHNpZGUtdG8tbm9kZS1vci1sYWJlbCcpIHtcbiAgICAgICAgcDFfaSA9IHAxO1xuICAgICAgfSBlbHNlIGlmICh0Z3RNYW5FbmRwdFZhbCA9PT0gJ291dHNpZGUtdG8tbGluZScgfHwgdGd0TWFuRW5kcHRWYWwgPT09ICdvdXRzaWRlLXRvLWxpbmUtb3ItbGFiZWwnKSB7XG4gICAgICAgIHAxX2kgPSBbc3JjUG9zLngsIHNyY1Bvcy55XTtcbiAgICAgIH1cblxuICAgICAgaW50ZXJzZWN0ID0gci5ub2RlU2hhcGVzW3RoaXMuZ2V0Tm9kZVNoYXBlKHRhcmdldCldLmludGVyc2VjdExpbmUodGd0UG9zLngsIHRndFBvcy55LCB0YXJnZXQub3V0ZXJXaWR0aCgpLCB0YXJnZXQub3V0ZXJIZWlnaHQoKSwgcDFfaVswXSwgcDFfaVsxXSwgMCk7XG5cbiAgICAgIGlmICh0Z3RNYW5FbmRwdFZhbCA9PT0gJ291dHNpZGUtdG8tbm9kZS1vci1sYWJlbCcgfHwgdGd0TWFuRW5kcHRWYWwgPT09ICdvdXRzaWRlLXRvLWxpbmUtb3ItbGFiZWwnKSB7XG4gICAgICAgIHZhciB0cnMgPSB0YXJnZXQuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgICAgIHZhciBsdyA9IHRycy5sYWJlbFdpZHRoO1xuICAgICAgICB2YXIgbGggPSB0cnMubGFiZWxIZWlnaHQ7XG4gICAgICAgIHZhciBseCA9IHRycy5sYWJlbFg7XG4gICAgICAgIHZhciBseSA9IHRycy5sYWJlbFk7XG4gICAgICAgIHZhciBsdzIgPSBsdyAvIDI7XG4gICAgICAgIHZhciBsaDIgPSBsaCAvIDI7XG4gICAgICAgIHZhciB2YSA9IHRhcmdldC5wc3R5bGUoJ3RleHQtdmFsaWduJykudmFsdWU7XG5cbiAgICAgICAgaWYgKHZhID09PSAndG9wJykge1xuICAgICAgICAgIGx5IC09IGxoMjtcbiAgICAgICAgfSBlbHNlIGlmICh2YSA9PT0gJ2JvdHRvbScpIHtcbiAgICAgICAgICBseSArPSBsaDI7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgaGEgPSB0YXJnZXQucHN0eWxlKCd0ZXh0LWhhbGlnbicpLnZhbHVlO1xuXG4gICAgICAgIGlmIChoYSA9PT0gJ2xlZnQnKSB7XG4gICAgICAgICAgbHggLT0gbHcyO1xuICAgICAgICB9IGVsc2UgaWYgKGhhID09PSAncmlnaHQnKSB7XG4gICAgICAgICAgbHggKz0gbHcyO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGxhYmVsSW50ZXJzZWN0ID0gcG9seWdvbkludGVyc2VjdExpbmUocDFfaVswXSwgcDFfaVsxXSwgW2x4IC0gbHcyLCBseSAtIGxoMiwgbHggKyBsdzIsIGx5IC0gbGgyLCBseCArIGx3MiwgbHkgKyBsaDIsIGx4IC0gbHcyLCBseSArIGxoMl0sIHRndFBvcy54LCB0Z3RQb3MueSk7XG5cbiAgICAgICAgaWYgKGxhYmVsSW50ZXJzZWN0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICB2YXIgcmVmUHQgPSBzcmNQb3M7XG4gICAgICAgICAgdmFyIGludFNxZGlzdCA9IHNxZGlzdChyZWZQdCwgYXJyYXkycG9pbnQoaW50ZXJzZWN0KSk7XG4gICAgICAgICAgdmFyIGxhYkludFNxZGlzdCA9IHNxZGlzdChyZWZQdCwgYXJyYXkycG9pbnQobGFiZWxJbnRlcnNlY3QpKTtcbiAgICAgICAgICB2YXIgbWluU3FEaXN0ID0gaW50U3FkaXN0O1xuXG4gICAgICAgICAgaWYgKGxhYkludFNxZGlzdCA8IGludFNxZGlzdCkge1xuICAgICAgICAgICAgaW50ZXJzZWN0ID0gbGFiZWxJbnRlcnNlY3Q7XG4gICAgICAgICAgICBtaW5TcURpc3QgPSBsYWJJbnRTcWRpc3Q7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGxhYmVsSW50ZXJzZWN0Lmxlbmd0aCA+IDIpIHtcbiAgICAgICAgICAgIHZhciBsYWJJbnQyU3FEaXN0ID0gc3FkaXN0KHJlZlB0LCB7XG4gICAgICAgICAgICAgIHg6IGxhYmVsSW50ZXJzZWN0WzJdLFxuICAgICAgICAgICAgICB5OiBsYWJlbEludGVyc2VjdFszXVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGlmIChsYWJJbnQyU3FEaXN0IDwgbWluU3FEaXN0KSB7XG4gICAgICAgICAgICAgIGludGVyc2VjdCA9IFtsYWJlbEludGVyc2VjdFsyXSwgbGFiZWxJbnRlcnNlY3RbM11dO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBhcnJvd0VuZCA9IHNob3J0ZW5JbnRlcnNlY3Rpb24oaW50ZXJzZWN0LCBwMSwgci5hcnJvd1NoYXBlc1t0Z3RBclNoYXBlXS5zcGFjaW5nKGVkZ2UpICsgdGd0RGlzdCk7XG4gICAgdmFyIGVkZ2VFbmQgPSBzaG9ydGVuSW50ZXJzZWN0aW9uKGludGVyc2VjdCwgcDEsIHIuYXJyb3dTaGFwZXNbdGd0QXJTaGFwZV0uZ2FwKGVkZ2UpICsgdGd0RGlzdCk7XG4gICAgcnMuZW5kWCA9IGVkZ2VFbmRbMF07XG4gICAgcnMuZW5kWSA9IGVkZ2VFbmRbMV07XG4gICAgcnMuYXJyb3dFbmRYID0gYXJyb3dFbmRbMF07XG4gICAgcnMuYXJyb3dFbmRZID0gYXJyb3dFbmRbMV07XG5cbiAgICBpZiAoc3JjTWFuRW5kcHRWYWwgPT09ICdpbnNpZGUtdG8tbm9kZScpIHtcbiAgICAgIGludGVyc2VjdCA9IFtzcmNQb3MueCwgc3JjUG9zLnldO1xuICAgIH0gZWxzZSBpZiAoc3JjTWFuRW5kcHQudW5pdHMpIHtcbiAgICAgIGludGVyc2VjdCA9IHRoaXMubWFudWFsRW5kcHRUb1B4KHNvdXJjZSwgc3JjTWFuRW5kcHQpO1xuICAgIH0gZWxzZSBpZiAoc3JjTWFuRW5kcHRWYWwgPT09ICdvdXRzaWRlLXRvLWxpbmUnKSB7XG4gICAgICBpbnRlcnNlY3QgPSBycy5zcmNJbnRuOyAvLyB1c2UgY2FjaGVkIHZhbHVlIGZyb20gY3RybHB0IGNhbGNcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHNyY01hbkVuZHB0VmFsID09PSAnb3V0c2lkZS10by1ub2RlJyB8fCBzcmNNYW5FbmRwdFZhbCA9PT0gJ291dHNpZGUtdG8tbm9kZS1vci1sYWJlbCcpIHtcbiAgICAgICAgcDJfaSA9IHAyO1xuICAgICAgfSBlbHNlIGlmIChzcmNNYW5FbmRwdFZhbCA9PT0gJ291dHNpZGUtdG8tbGluZScgfHwgc3JjTWFuRW5kcHRWYWwgPT09ICdvdXRzaWRlLXRvLWxpbmUtb3ItbGFiZWwnKSB7XG4gICAgICAgIHAyX2kgPSBbdGd0UG9zLngsIHRndFBvcy55XTtcbiAgICAgIH1cblxuICAgICAgaW50ZXJzZWN0ID0gci5ub2RlU2hhcGVzW3RoaXMuZ2V0Tm9kZVNoYXBlKHNvdXJjZSldLmludGVyc2VjdExpbmUoc3JjUG9zLngsIHNyY1Bvcy55LCBzb3VyY2Uub3V0ZXJXaWR0aCgpLCBzb3VyY2Uub3V0ZXJIZWlnaHQoKSwgcDJfaVswXSwgcDJfaVsxXSwgMCk7XG5cbiAgICAgIGlmIChzcmNNYW5FbmRwdFZhbCA9PT0gJ291dHNpZGUtdG8tbm9kZS1vci1sYWJlbCcgfHwgc3JjTWFuRW5kcHRWYWwgPT09ICdvdXRzaWRlLXRvLWxpbmUtb3ItbGFiZWwnKSB7XG4gICAgICAgIHZhciBzcnMgPSBzb3VyY2UuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgICAgIHZhciBfbHcgPSBzcnMubGFiZWxXaWR0aDtcbiAgICAgICAgdmFyIF9saCA9IHNycy5sYWJlbEhlaWdodDtcbiAgICAgICAgdmFyIF9seCA9IHNycy5sYWJlbFg7XG4gICAgICAgIHZhciBfbHkgPSBzcnMubGFiZWxZO1xuXG4gICAgICAgIHZhciBfbHcyID0gX2x3IC8gMjtcblxuICAgICAgICB2YXIgX2xoMiA9IF9saCAvIDI7XG5cbiAgICAgICAgdmFyIF92YSA9IHNvdXJjZS5wc3R5bGUoJ3RleHQtdmFsaWduJykudmFsdWU7XG5cbiAgICAgICAgaWYgKF92YSA9PT0gJ3RvcCcpIHtcbiAgICAgICAgICBfbHkgLT0gX2xoMjtcbiAgICAgICAgfSBlbHNlIGlmIChfdmEgPT09ICdib3R0b20nKSB7XG4gICAgICAgICAgX2x5ICs9IF9saDI7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgX2hhID0gc291cmNlLnBzdHlsZSgndGV4dC1oYWxpZ24nKS52YWx1ZTtcblxuICAgICAgICBpZiAoX2hhID09PSAnbGVmdCcpIHtcbiAgICAgICAgICBfbHggLT0gX2x3MjtcbiAgICAgICAgfSBlbHNlIGlmIChfaGEgPT09ICdyaWdodCcpIHtcbiAgICAgICAgICBfbHggKz0gX2x3MjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBfbGFiZWxJbnRlcnNlY3QgPSBwb2x5Z29uSW50ZXJzZWN0TGluZShwMl9pWzBdLCBwMl9pWzFdLCBbX2x4IC0gX2x3MiwgX2x5IC0gX2xoMiwgX2x4ICsgX2x3MiwgX2x5IC0gX2xoMiwgX2x4ICsgX2x3MiwgX2x5ICsgX2xoMiwgX2x4IC0gX2x3MiwgX2x5ICsgX2xoMl0sIHNyY1Bvcy54LCBzcmNQb3MueSk7XG5cbiAgICAgICAgaWYgKF9sYWJlbEludGVyc2VjdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgdmFyIF9yZWZQdCA9IHRndFBvcztcblxuICAgICAgICAgIHZhciBfaW50U3FkaXN0ID0gc3FkaXN0KF9yZWZQdCwgYXJyYXkycG9pbnQoaW50ZXJzZWN0KSk7XG5cbiAgICAgICAgICB2YXIgX2xhYkludFNxZGlzdCA9IHNxZGlzdChfcmVmUHQsIGFycmF5MnBvaW50KF9sYWJlbEludGVyc2VjdCkpO1xuXG4gICAgICAgICAgdmFyIF9taW5TcURpc3QgPSBfaW50U3FkaXN0O1xuXG4gICAgICAgICAgaWYgKF9sYWJJbnRTcWRpc3QgPCBfaW50U3FkaXN0KSB7XG4gICAgICAgICAgICBpbnRlcnNlY3QgPSBbX2xhYmVsSW50ZXJzZWN0WzBdLCBfbGFiZWxJbnRlcnNlY3RbMV1dO1xuICAgICAgICAgICAgX21pblNxRGlzdCA9IF9sYWJJbnRTcWRpc3Q7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKF9sYWJlbEludGVyc2VjdC5sZW5ndGggPiAyKSB7XG4gICAgICAgICAgICB2YXIgX2xhYkludDJTcURpc3QgPSBzcWRpc3QoX3JlZlB0LCB7XG4gICAgICAgICAgICAgIHg6IF9sYWJlbEludGVyc2VjdFsyXSxcbiAgICAgICAgICAgICAgeTogX2xhYmVsSW50ZXJzZWN0WzNdXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKF9sYWJJbnQyU3FEaXN0IDwgX21pblNxRGlzdCkge1xuICAgICAgICAgICAgICBpbnRlcnNlY3QgPSBbX2xhYmVsSW50ZXJzZWN0WzJdLCBfbGFiZWxJbnRlcnNlY3RbM11dO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBhcnJvd1N0YXJ0ID0gc2hvcnRlbkludGVyc2VjdGlvbihpbnRlcnNlY3QsIHAyLCByLmFycm93U2hhcGVzW3NyY0FyU2hhcGVdLnNwYWNpbmcoZWRnZSkgKyBzcmNEaXN0KTtcbiAgICB2YXIgZWRnZVN0YXJ0ID0gc2hvcnRlbkludGVyc2VjdGlvbihpbnRlcnNlY3QsIHAyLCByLmFycm93U2hhcGVzW3NyY0FyU2hhcGVdLmdhcChlZGdlKSArIHNyY0Rpc3QpO1xuICAgIHJzLnN0YXJ0WCA9IGVkZ2VTdGFydFswXTtcbiAgICBycy5zdGFydFkgPSBlZGdlU3RhcnRbMV07XG4gICAgcnMuYXJyb3dTdGFydFggPSBhcnJvd1N0YXJ0WzBdO1xuICAgIHJzLmFycm93U3RhcnRZID0gYXJyb3dTdGFydFsxXTtcblxuICAgIGlmIChoYXNFbmRwdHMpIHtcbiAgICAgIGlmICghbnVtYmVyJDEocnMuc3RhcnRYKSB8fCAhbnVtYmVyJDEocnMuc3RhcnRZKSB8fCAhbnVtYmVyJDEocnMuZW5kWCkgfHwgIW51bWJlciQxKHJzLmVuZFkpKSB7XG4gICAgICAgIHJzLmJhZExpbmUgPSB0cnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcnMuYmFkTGluZSA9IGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBCUnAkYi5nZXRTb3VyY2VFbmRwb2ludCA9IGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgdmFyIHJzID0gZWRnZVswXS5fcHJpdmF0ZS5yc2NyYXRjaDtcbiAgICB0aGlzLnJlY2FsY3VsYXRlUmVuZGVyZWRTdHlsZShlZGdlKTtcblxuICAgIHN3aXRjaCAocnMuZWRnZVR5cGUpIHtcbiAgICAgIGNhc2UgJ2hheXN0YWNrJzpcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB4OiBycy5oYXlzdGFja1B0c1swXSxcbiAgICAgICAgICB5OiBycy5oYXlzdGFja1B0c1sxXVxuICAgICAgICB9O1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHg6IHJzLmFycm93U3RhcnRYLFxuICAgICAgICAgIHk6IHJzLmFycm93U3RhcnRZXG4gICAgICAgIH07XG4gICAgfVxuICB9O1xuXG4gIEJScCRiLmdldFRhcmdldEVuZHBvaW50ID0gZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICB2YXIgcnMgPSBlZGdlWzBdLl9wcml2YXRlLnJzY3JhdGNoO1xuICAgIHRoaXMucmVjYWxjdWxhdGVSZW5kZXJlZFN0eWxlKGVkZ2UpO1xuXG4gICAgc3dpdGNoIChycy5lZGdlVHlwZSkge1xuICAgICAgY2FzZSAnaGF5c3RhY2snOlxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHg6IHJzLmhheXN0YWNrUHRzWzJdLFxuICAgICAgICAgIHk6IHJzLmhheXN0YWNrUHRzWzNdXG4gICAgICAgIH07XG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgeDogcnMuYXJyb3dFbmRYLFxuICAgICAgICAgIHk6IHJzLmFycm93RW5kWVxuICAgICAgICB9O1xuICAgIH1cbiAgfTtcblxuICB2YXIgQlJwJGEgPSB7fTtcblxuICBmdW5jdGlvbiBwdXNoQmV6aWVyUHRzKHIsIGVkZ2UsIHB0cykge1xuICAgIHZhciBxYmV6aWVyQXQkMSA9IGZ1bmN0aW9uIHFiZXppZXJBdCQxKHAxLCBwMiwgcDMsIHQpIHtcbiAgICAgIHJldHVybiBxYmV6aWVyQXQocDEsIHAyLCBwMywgdCk7XG4gICAgfTtcblxuICAgIHZhciBfcCA9IGVkZ2UuX3ByaXZhdGU7XG4gICAgdmFyIGJwdHMgPSBfcC5yc3R5bGUuYmV6aWVyUHRzO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCByLmJlemllclByb2pQY3RzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgcCA9IHIuYmV6aWVyUHJvalBjdHNbaV07XG4gICAgICBicHRzLnB1c2goe1xuICAgICAgICB4OiBxYmV6aWVyQXQkMShwdHNbMF0sIHB0c1syXSwgcHRzWzRdLCBwKSxcbiAgICAgICAgeTogcWJlemllckF0JDEocHRzWzFdLCBwdHNbM10sIHB0c1s1XSwgcClcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIEJScCRhLnN0b3JlRWRnZVByb2plY3Rpb25zID0gZnVuY3Rpb24gKGVkZ2UpIHtcbiAgICB2YXIgX3AgPSBlZGdlLl9wcml2YXRlO1xuICAgIHZhciBycyA9IF9wLnJzY3JhdGNoO1xuICAgIHZhciBldCA9IHJzLmVkZ2VUeXBlOyAvLyBjbGVhciB0aGUgY2FjaGVkIHBvaW50cyBzdGF0ZVxuXG4gICAgX3AucnN0eWxlLmJlemllclB0cyA9IG51bGw7XG4gICAgX3AucnN0eWxlLmxpbmVQdHMgPSBudWxsO1xuICAgIF9wLnJzdHlsZS5oYXlzdGFja1B0cyA9IG51bGw7XG5cbiAgICBpZiAoZXQgPT09ICdtdWx0aWJlemllcicgfHwgZXQgPT09ICdiZXppZXInIHx8IGV0ID09PSAnc2VsZicgfHwgZXQgPT09ICdjb21wb3VuZCcpIHtcbiAgICAgIF9wLnJzdHlsZS5iZXppZXJQdHMgPSBbXTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgKyA1IDwgcnMuYWxscHRzLmxlbmd0aDsgaSArPSA0KSB7XG4gICAgICAgIHB1c2hCZXppZXJQdHModGhpcywgZWRnZSwgcnMuYWxscHRzLnNsaWNlKGksIGkgKyA2KSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChldCA9PT0gJ3NlZ21lbnRzJykge1xuICAgICAgdmFyIGxwdHMgPSBfcC5yc3R5bGUubGluZVB0cyA9IFtdO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSArIDEgPCBycy5hbGxwdHMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgICAgbHB0cy5wdXNoKHtcbiAgICAgICAgICB4OiBycy5hbGxwdHNbaV0sXG4gICAgICAgICAgeTogcnMuYWxscHRzW2kgKyAxXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGV0ID09PSAnaGF5c3RhY2snKSB7XG4gICAgICB2YXIgaHB0cyA9IHJzLmhheXN0YWNrUHRzO1xuICAgICAgX3AucnN0eWxlLmhheXN0YWNrUHRzID0gW3tcbiAgICAgICAgeDogaHB0c1swXSxcbiAgICAgICAgeTogaHB0c1sxXVxuICAgICAgfSwge1xuICAgICAgICB4OiBocHRzWzJdLFxuICAgICAgICB5OiBocHRzWzNdXG4gICAgICB9XTtcbiAgICB9XG5cbiAgICBfcC5yc3R5bGUuYXJyb3dXaWR0aCA9IHRoaXMuZ2V0QXJyb3dXaWR0aChlZGdlLnBzdHlsZSgnd2lkdGgnKS5wZlZhbHVlLCBlZGdlLnBzdHlsZSgnYXJyb3ctc2NhbGUnKS52YWx1ZSkgKiB0aGlzLmFycm93U2hhcGVXaWR0aDtcbiAgfTtcblxuICBCUnAkYS5yZWNhbGN1bGF0ZUVkZ2VQcm9qZWN0aW9ucyA9IGZ1bmN0aW9uIChlZGdlcykge1xuICAgIHRoaXMuZmluZEVkZ2VDb250cm9sUG9pbnRzKGVkZ2VzKTtcbiAgfTtcblxuICAvKiBnbG9iYWwgZG9jdW1lbnQgKi9cblxuICB2YXIgQlJwJDkgPSB7fTtcblxuICBCUnAkOS5yZWNhbGN1bGF0ZU5vZGVMYWJlbFByb2plY3Rpb24gPSBmdW5jdGlvbiAobm9kZSkge1xuICAgIHZhciBjb250ZW50ID0gbm9kZS5wc3R5bGUoJ2xhYmVsJykuc3RyVmFsdWU7XG5cbiAgICBpZiAoZW1wdHlTdHJpbmcoY29udGVudCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgdGV4dFgsIHRleHRZO1xuICAgIHZhciBfcCA9IG5vZGUuX3ByaXZhdGU7XG4gICAgdmFyIG5vZGVXaWR0aCA9IG5vZGUud2lkdGgoKTtcbiAgICB2YXIgbm9kZUhlaWdodCA9IG5vZGUuaGVpZ2h0KCk7XG4gICAgdmFyIHBhZGRpbmcgPSBub2RlLnBhZGRpbmcoKTtcbiAgICB2YXIgbm9kZVBvcyA9IG5vZGUucG9zaXRpb24oKTtcbiAgICB2YXIgdGV4dEhhbGlnbiA9IG5vZGUucHN0eWxlKCd0ZXh0LWhhbGlnbicpLnN0clZhbHVlO1xuICAgIHZhciB0ZXh0VmFsaWduID0gbm9kZS5wc3R5bGUoJ3RleHQtdmFsaWduJykuc3RyVmFsdWU7XG4gICAgdmFyIHJzID0gX3AucnNjcmF0Y2g7XG4gICAgdmFyIHJzdHlsZSA9IF9wLnJzdHlsZTtcblxuICAgIHN3aXRjaCAodGV4dEhhbGlnbikge1xuICAgICAgY2FzZSAnbGVmdCc6XG4gICAgICAgIHRleHRYID0gbm9kZVBvcy54IC0gbm9kZVdpZHRoIC8gMiAtIHBhZGRpbmc7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdyaWdodCc6XG4gICAgICAgIHRleHRYID0gbm9kZVBvcy54ICsgbm9kZVdpZHRoIC8gMiArIHBhZGRpbmc7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICAvLyBlLmcuIGNlbnRlclxuICAgICAgICB0ZXh0WCA9IG5vZGVQb3MueDtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKHRleHRWYWxpZ24pIHtcbiAgICAgIGNhc2UgJ3RvcCc6XG4gICAgICAgIHRleHRZID0gbm9kZVBvcy55IC0gbm9kZUhlaWdodCAvIDIgLSBwYWRkaW5nO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnYm90dG9tJzpcbiAgICAgICAgdGV4dFkgPSBub2RlUG9zLnkgKyBub2RlSGVpZ2h0IC8gMiArIHBhZGRpbmc7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICAvLyBlLmcuIG1pZGRsZVxuICAgICAgICB0ZXh0WSA9IG5vZGVQb3MueTtcbiAgICB9XG5cbiAgICBycy5sYWJlbFggPSB0ZXh0WDtcbiAgICBycy5sYWJlbFkgPSB0ZXh0WTtcbiAgICByc3R5bGUubGFiZWxYID0gdGV4dFg7XG4gICAgcnN0eWxlLmxhYmVsWSA9IHRleHRZO1xuICAgIHRoaXMuY2FsY3VsYXRlTGFiZWxBbmdsZXMobm9kZSk7XG4gICAgdGhpcy5hcHBseUxhYmVsRGltZW5zaW9ucyhub2RlKTtcbiAgfTtcblxuICB2YXIgbGluZUFuZ2xlRnJvbURlbHRhID0gZnVuY3Rpb24gbGluZUFuZ2xlRnJvbURlbHRhKGR4LCBkeSkge1xuICAgIHZhciBhbmdsZSA9IE1hdGguYXRhbihkeSAvIGR4KTtcblxuICAgIGlmIChkeCA9PT0gMCAmJiBhbmdsZSA8IDApIHtcbiAgICAgIGFuZ2xlID0gYW5nbGUgKiAtMTtcbiAgICB9XG5cbiAgICByZXR1cm4gYW5nbGU7XG4gIH07XG5cbiAgdmFyIGxpbmVBbmdsZSA9IGZ1bmN0aW9uIGxpbmVBbmdsZShwMCwgcDEpIHtcbiAgICB2YXIgZHggPSBwMS54IC0gcDAueDtcbiAgICB2YXIgZHkgPSBwMS55IC0gcDAueTtcbiAgICByZXR1cm4gbGluZUFuZ2xlRnJvbURlbHRhKGR4LCBkeSk7XG4gIH07XG5cbiAgdmFyIGJlemllckFuZ2xlID0gZnVuY3Rpb24gYmV6aWVyQW5nbGUocDAsIHAxLCBwMiwgdCkge1xuICAgIHZhciB0MCA9IGJvdW5kKDAsIHQgLSAwLjAwMSwgMSk7XG4gICAgdmFyIHQxID0gYm91bmQoMCwgdCArIDAuMDAxLCAxKTtcbiAgICB2YXIgbHAwID0gcWJlemllclB0QXQocDAsIHAxLCBwMiwgdDApO1xuICAgIHZhciBscDEgPSBxYmV6aWVyUHRBdChwMCwgcDEsIHAyLCB0MSk7XG4gICAgcmV0dXJuIGxpbmVBbmdsZShscDAsIGxwMSk7XG4gIH07XG5cbiAgQlJwJDkucmVjYWxjdWxhdGVFZGdlTGFiZWxQcm9qZWN0aW9ucyA9IGZ1bmN0aW9uIChlZGdlKSB7XG4gICAgdmFyIHA7XG4gICAgdmFyIF9wID0gZWRnZS5fcHJpdmF0ZTtcbiAgICB2YXIgcnMgPSBfcC5yc2NyYXRjaDtcbiAgICB2YXIgciA9IHRoaXM7XG4gICAgdmFyIGNvbnRlbnQgPSB7XG4gICAgICBtaWQ6IGVkZ2UucHN0eWxlKCdsYWJlbCcpLnN0clZhbHVlLFxuICAgICAgc291cmNlOiBlZGdlLnBzdHlsZSgnc291cmNlLWxhYmVsJykuc3RyVmFsdWUsXG4gICAgICB0YXJnZXQ6IGVkZ2UucHN0eWxlKCd0YXJnZXQtbGFiZWwnKS5zdHJWYWx1ZVxuICAgIH07XG5cbiAgICBpZiAoY29udGVudC5taWQgfHwgY29udGVudC5zb3VyY2UgfHwgY29udGVudC50YXJnZXQpIDsgZWxzZSB7XG4gICAgICByZXR1cm47IC8vIG5vIGxhYmVscyA9PiBubyBjYWxjc1xuICAgIH0gLy8gYWRkIGNlbnRlciBwb2ludCB0byBzdHlsZSBzbyBib3VuZGluZyBib3ggY2FsY3VsYXRpb25zIGNhbiB1c2UgaXRcbiAgICAvL1xuXG5cbiAgICBwID0ge1xuICAgICAgeDogcnMubWlkWCxcbiAgICAgIHk6IHJzLm1pZFlcbiAgICB9O1xuXG4gICAgdmFyIHNldFJzID0gZnVuY3Rpb24gc2V0UnMocHJvcE5hbWUsIHByZWZpeCwgdmFsdWUpIHtcbiAgICAgIHNldFByZWZpeGVkUHJvcGVydHkoX3AucnNjcmF0Y2gsIHByb3BOYW1lLCBwcmVmaXgsIHZhbHVlKTtcbiAgICAgIHNldFByZWZpeGVkUHJvcGVydHkoX3AucnN0eWxlLCBwcm9wTmFtZSwgcHJlZml4LCB2YWx1ZSk7XG4gICAgfTtcblxuICAgIHNldFJzKCdsYWJlbFgnLCBudWxsLCBwLngpO1xuICAgIHNldFJzKCdsYWJlbFknLCBudWxsLCBwLnkpO1xuICAgIHZhciBtaWRBbmdsZSA9IGxpbmVBbmdsZUZyb21EZWx0YShycy5taWREaXNwWCwgcnMubWlkRGlzcFkpO1xuICAgIHNldFJzKCdsYWJlbEF1dG9BbmdsZScsIG51bGwsIG1pZEFuZ2xlKTtcblxuICAgIHZhciBjcmVhdGVDb250cm9sUG9pbnRJbmZvID0gZnVuY3Rpb24gY3JlYXRlQ29udHJvbFBvaW50SW5mbygpIHtcbiAgICAgIGlmIChjcmVhdGVDb250cm9sUG9pbnRJbmZvLmNhY2hlKSB7XG4gICAgICAgIHJldHVybiBjcmVhdGVDb250cm9sUG9pbnRJbmZvLmNhY2hlO1xuICAgICAgfSAvLyB1c2UgY2FjaGUgc28gb25seSAxeCBwZXIgZWRnZVxuXG5cbiAgICAgIHZhciBjdHJscHRzID0gW107IC8vIHN0b3JlIGVhY2ggY3RybHB0IGluZm8gaW5pdFxuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSArIDUgPCBycy5hbGxwdHMubGVuZ3RoOyBpICs9IDQpIHtcbiAgICAgICAgdmFyIHAwID0ge1xuICAgICAgICAgIHg6IHJzLmFsbHB0c1tpXSxcbiAgICAgICAgICB5OiBycy5hbGxwdHNbaSArIDFdXG4gICAgICAgIH07XG4gICAgICAgIHZhciBwMSA9IHtcbiAgICAgICAgICB4OiBycy5hbGxwdHNbaSArIDJdLFxuICAgICAgICAgIHk6IHJzLmFsbHB0c1tpICsgM11cbiAgICAgICAgfTsgLy8gY3RybHB0XG5cbiAgICAgICAgdmFyIHAyID0ge1xuICAgICAgICAgIHg6IHJzLmFsbHB0c1tpICsgNF0sXG4gICAgICAgICAgeTogcnMuYWxscHRzW2kgKyA1XVxuICAgICAgICB9O1xuICAgICAgICBjdHJscHRzLnB1c2goe1xuICAgICAgICAgIHAwOiBwMCxcbiAgICAgICAgICBwMTogcDEsXG4gICAgICAgICAgcDI6IHAyLFxuICAgICAgICAgIHN0YXJ0RGlzdDogMCxcbiAgICAgICAgICBsZW5ndGg6IDAsXG4gICAgICAgICAgc2VnbWVudHM6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB2YXIgYnB0cyA9IF9wLnJzdHlsZS5iZXppZXJQdHM7XG4gICAgICB2YXIgblByb2pzID0gci5iZXppZXJQcm9qUGN0cy5sZW5ndGg7XG5cbiAgICAgIGZ1bmN0aW9uIGFkZFNlZ21lbnQoY3AsIHAwLCBwMSwgdDAsIHQxKSB7XG4gICAgICAgIHZhciBsZW5ndGggPSBkaXN0KHAwLCBwMSk7XG4gICAgICAgIHZhciBwcmV2U2VnbWVudCA9IGNwLnNlZ21lbnRzW2NwLnNlZ21lbnRzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgc2VnbWVudCA9IHtcbiAgICAgICAgICBwMDogcDAsXG4gICAgICAgICAgcDE6IHAxLFxuICAgICAgICAgIHQwOiB0MCxcbiAgICAgICAgICB0MTogdDEsXG4gICAgICAgICAgc3RhcnREaXN0OiBwcmV2U2VnbWVudCA/IHByZXZTZWdtZW50LnN0YXJ0RGlzdCArIHByZXZTZWdtZW50Lmxlbmd0aCA6IDAsXG4gICAgICAgICAgbGVuZ3RoOiBsZW5ndGhcbiAgICAgICAgfTtcbiAgICAgICAgY3Auc2VnbWVudHMucHVzaChzZWdtZW50KTtcbiAgICAgICAgY3AubGVuZ3RoICs9IGxlbmd0aDtcbiAgICAgIH0gLy8gdXBkYXRlIGVhY2ggY3RybHB0IHdpdGggc2VnbWVudCBpbmZvXG5cblxuICAgICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IGN0cmxwdHMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciBjcCA9IGN0cmxwdHNbX2ldO1xuICAgICAgICB2YXIgcHJldkNwID0gY3RybHB0c1tfaSAtIDFdO1xuXG4gICAgICAgIGlmIChwcmV2Q3ApIHtcbiAgICAgICAgICBjcC5zdGFydERpc3QgPSBwcmV2Q3Auc3RhcnREaXN0ICsgcHJldkNwLmxlbmd0aDtcbiAgICAgICAgfVxuXG4gICAgICAgIGFkZFNlZ21lbnQoY3AsIGNwLnAwLCBicHRzW19pICogblByb2pzXSwgMCwgci5iZXppZXJQcm9qUGN0c1swXSk7IC8vIGZpcnN0XG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBuUHJvanMgLSAxOyBqKyspIHtcbiAgICAgICAgICBhZGRTZWdtZW50KGNwLCBicHRzW19pICogblByb2pzICsgal0sIGJwdHNbX2kgKiBuUHJvanMgKyBqICsgMV0sIHIuYmV6aWVyUHJvalBjdHNbal0sIHIuYmV6aWVyUHJvalBjdHNbaiArIDFdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGFkZFNlZ21lbnQoY3AsIGJwdHNbX2kgKiBuUHJvanMgKyBuUHJvanMgLSAxXSwgY3AucDIsIHIuYmV6aWVyUHJvalBjdHNbblByb2pzIC0gMV0sIDEpOyAvLyBsYXN0XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBjcmVhdGVDb250cm9sUG9pbnRJbmZvLmNhY2hlID0gY3RybHB0cztcbiAgICB9O1xuXG4gICAgdmFyIGNhbGN1bGF0ZUVuZFByb2plY3Rpb24gPSBmdW5jdGlvbiBjYWxjdWxhdGVFbmRQcm9qZWN0aW9uKHByZWZpeCkge1xuICAgICAgdmFyIGFuZ2xlO1xuICAgICAgdmFyIGlzU3JjID0gcHJlZml4ID09PSAnc291cmNlJztcblxuICAgICAgaWYgKCFjb250ZW50W3ByZWZpeF0pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgb2Zmc2V0ID0gZWRnZS5wc3R5bGUocHJlZml4ICsgJy10ZXh0LW9mZnNldCcpLnBmVmFsdWU7XG5cbiAgICAgIHN3aXRjaCAocnMuZWRnZVR5cGUpIHtcbiAgICAgICAgY2FzZSAnc2VsZic6XG4gICAgICAgIGNhc2UgJ2NvbXBvdW5kJzpcbiAgICAgICAgY2FzZSAnYmV6aWVyJzpcbiAgICAgICAgY2FzZSAnbXVsdGliZXppZXInOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHZhciBjcHMgPSBjcmVhdGVDb250cm9sUG9pbnRJbmZvKCk7XG4gICAgICAgICAgICB2YXIgc2VsZWN0ZWQ7XG4gICAgICAgICAgICB2YXIgc3RhcnREaXN0ID0gMDtcbiAgICAgICAgICAgIHZhciB0b3RhbERpc3QgPSAwOyAvLyBmaW5kIHRoZSBzZWdtZW50IHdlJ3JlIG9uXG5cbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgIHZhciBfY3AgPSBjcHNbaXNTcmMgPyBpIDogY3BzLmxlbmd0aCAtIDEgLSBpXTtcblxuICAgICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IF9jcC5zZWdtZW50cy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIHZhciBfc2VnID0gX2NwLnNlZ21lbnRzW2lzU3JjID8gaiA6IF9jcC5zZWdtZW50cy5sZW5ndGggLSAxIC0gal07XG4gICAgICAgICAgICAgICAgdmFyIGxhc3RTZWcgPSBpID09PSBjcHMubGVuZ3RoIC0gMSAmJiBqID09PSBfY3Auc2VnbWVudHMubGVuZ3RoIC0gMTtcbiAgICAgICAgICAgICAgICBzdGFydERpc3QgPSB0b3RhbERpc3Q7XG4gICAgICAgICAgICAgICAgdG90YWxEaXN0ICs9IF9zZWcubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRvdGFsRGlzdCA+PSBvZmZzZXQgfHwgbGFzdFNlZykge1xuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWQgPSB7XG4gICAgICAgICAgICAgICAgICAgIGNwOiBfY3AsXG4gICAgICAgICAgICAgICAgICAgIHNlZ21lbnQ6IF9zZWdcbiAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBpZiAoc2VsZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgY3AgPSBzZWxlY3RlZC5jcDtcbiAgICAgICAgICAgIHZhciBzZWcgPSBzZWxlY3RlZC5zZWdtZW50O1xuICAgICAgICAgICAgdmFyIHRTZWdtZW50ID0gKG9mZnNldCAtIHN0YXJ0RGlzdCkgLyBzZWcubGVuZ3RoO1xuICAgICAgICAgICAgdmFyIHNlZ0R0ID0gc2VnLnQxIC0gc2VnLnQwO1xuICAgICAgICAgICAgdmFyIHQgPSBpc1NyYyA/IHNlZy50MCArIHNlZ0R0ICogdFNlZ21lbnQgOiBzZWcudDEgLSBzZWdEdCAqIHRTZWdtZW50O1xuICAgICAgICAgICAgdCA9IGJvdW5kKDAsIHQsIDEpO1xuICAgICAgICAgICAgcCA9IHFiZXppZXJQdEF0KGNwLnAwLCBjcC5wMSwgY3AucDIsIHQpO1xuICAgICAgICAgICAgYW5nbGUgPSBiZXppZXJBbmdsZShjcC5wMCwgY3AucDEsIGNwLnAyLCB0KTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cblxuICAgICAgICBjYXNlICdzdHJhaWdodCc6XG4gICAgICAgIGNhc2UgJ3NlZ21lbnRzJzpcbiAgICAgICAgY2FzZSAnaGF5c3RhY2snOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHZhciBkID0gMCxcbiAgICAgICAgICAgICAgICBkaSxcbiAgICAgICAgICAgICAgICBkMDtcbiAgICAgICAgICAgIHZhciBwMCwgcDE7XG4gICAgICAgICAgICB2YXIgbCA9IHJzLmFsbHB0cy5sZW5ndGg7XG5cbiAgICAgICAgICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiArIDMgPCBsOyBfaTIgKz0gMikge1xuICAgICAgICAgICAgICBpZiAoaXNTcmMpIHtcbiAgICAgICAgICAgICAgICBwMCA9IHtcbiAgICAgICAgICAgICAgICAgIHg6IHJzLmFsbHB0c1tfaTJdLFxuICAgICAgICAgICAgICAgICAgeTogcnMuYWxscHRzW19pMiArIDFdXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBwMSA9IHtcbiAgICAgICAgICAgICAgICAgIHg6IHJzLmFsbHB0c1tfaTIgKyAyXSxcbiAgICAgICAgICAgICAgICAgIHk6IHJzLmFsbHB0c1tfaTIgKyAzXVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcDAgPSB7XG4gICAgICAgICAgICAgICAgICB4OiBycy5hbGxwdHNbbCAtIDIgLSBfaTJdLFxuICAgICAgICAgICAgICAgICAgeTogcnMuYWxscHRzW2wgLSAxIC0gX2kyXVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgcDEgPSB7XG4gICAgICAgICAgICAgICAgICB4OiBycy5hbGxwdHNbbCAtIDQgLSBfaTJdLFxuICAgICAgICAgICAgICAgICAgeTogcnMuYWxscHRzW2wgLSAzIC0gX2kyXVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBkaSA9IGRpc3QocDAsIHAxKTtcbiAgICAgICAgICAgICAgZDAgPSBkO1xuICAgICAgICAgICAgICBkICs9IGRpO1xuXG4gICAgICAgICAgICAgIGlmIChkID49IG9mZnNldCkge1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBwRCA9IG9mZnNldCAtIGQwO1xuXG4gICAgICAgICAgICB2YXIgX3QgPSBwRCAvIGRpO1xuXG4gICAgICAgICAgICBfdCA9IGJvdW5kKDAsIF90LCAxKTtcbiAgICAgICAgICAgIHAgPSBsaW5lQXQocDAsIHAxLCBfdCk7XG4gICAgICAgICAgICBhbmdsZSA9IGxpbmVBbmdsZShwMCwgcDEpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBzZXRScygnbGFiZWxYJywgcHJlZml4LCBwLngpO1xuICAgICAgc2V0UnMoJ2xhYmVsWScsIHByZWZpeCwgcC55KTtcbiAgICAgIHNldFJzKCdsYWJlbEF1dG9BbmdsZScsIHByZWZpeCwgYW5nbGUpO1xuICAgIH07XG5cbiAgICBjYWxjdWxhdGVFbmRQcm9qZWN0aW9uKCdzb3VyY2UnKTtcbiAgICBjYWxjdWxhdGVFbmRQcm9qZWN0aW9uKCd0YXJnZXQnKTtcbiAgICB0aGlzLmFwcGx5TGFiZWxEaW1lbnNpb25zKGVkZ2UpO1xuICB9O1xuXG4gIEJScCQ5LmFwcGx5TGFiZWxEaW1lbnNpb25zID0gZnVuY3Rpb24gKGVsZSkge1xuICAgIHRoaXMuYXBwbHlQcmVmaXhlZExhYmVsRGltZW5zaW9ucyhlbGUpO1xuXG4gICAgaWYgKGVsZS5pc0VkZ2UoKSkge1xuICAgICAgdGhpcy5hcHBseVByZWZpeGVkTGFiZWxEaW1lbnNpb25zKGVsZSwgJ3NvdXJjZScpO1xuICAgICAgdGhpcy5hcHBseVByZWZpeGVkTGFiZWxEaW1lbnNpb25zKGVsZSwgJ3RhcmdldCcpO1xuICAgIH1cbiAgfTtcblxuICBCUnAkOS5hcHBseVByZWZpeGVkTGFiZWxEaW1lbnNpb25zID0gZnVuY3Rpb24gKGVsZSwgcHJlZml4KSB7XG4gICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgIHZhciB0ZXh0ID0gdGhpcy5nZXRMYWJlbFRleHQoZWxlLCBwcmVmaXgpO1xuICAgIHZhciBsYWJlbERpbXMgPSB0aGlzLmNhbGN1bGF0ZUxhYmVsRGltZW5zaW9ucyhlbGUsIHRleHQpO1xuICAgIHZhciBsaW5lSGVpZ2h0ID0gZWxlLnBzdHlsZSgnbGluZS1oZWlnaHQnKS5wZlZhbHVlO1xuICAgIHZhciB0ZXh0V3JhcCA9IGVsZS5wc3R5bGUoJ3RleHQtd3JhcCcpLnN0clZhbHVlO1xuICAgIHZhciBsaW5lcyA9IGdldFByZWZpeGVkUHJvcGVydHkoX3AucnNjcmF0Y2gsICdsYWJlbFdyYXBDYWNoZWRMaW5lcycsIHByZWZpeCkgfHwgW107XG4gICAgdmFyIG51bUxpbmVzID0gdGV4dFdyYXAgIT09ICd3cmFwJyA/IDEgOiBNYXRoLm1heChsaW5lcy5sZW5ndGgsIDEpO1xuICAgIHZhciBub3JtUGVyTGluZUhlaWdodCA9IGxhYmVsRGltcy5oZWlnaHQgLyBudW1MaW5lcztcbiAgICB2YXIgbGFiZWxMaW5lSGVpZ2h0ID0gbm9ybVBlckxpbmVIZWlnaHQgKiBsaW5lSGVpZ2h0O1xuICAgIHZhciB3aWR0aCA9IGxhYmVsRGltcy53aWR0aDtcbiAgICB2YXIgaGVpZ2h0ID0gbGFiZWxEaW1zLmhlaWdodCArIChudW1MaW5lcyAtIDEpICogKGxpbmVIZWlnaHQgLSAxKSAqIG5vcm1QZXJMaW5lSGVpZ2h0O1xuICAgIHNldFByZWZpeGVkUHJvcGVydHkoX3AucnN0eWxlLCAnbGFiZWxXaWR0aCcsIHByZWZpeCwgd2lkdGgpO1xuICAgIHNldFByZWZpeGVkUHJvcGVydHkoX3AucnNjcmF0Y2gsICdsYWJlbFdpZHRoJywgcHJlZml4LCB3aWR0aCk7XG4gICAgc2V0UHJlZml4ZWRQcm9wZXJ0eShfcC5yc3R5bGUsICdsYWJlbEhlaWdodCcsIHByZWZpeCwgaGVpZ2h0KTtcbiAgICBzZXRQcmVmaXhlZFByb3BlcnR5KF9wLnJzY3JhdGNoLCAnbGFiZWxIZWlnaHQnLCBwcmVmaXgsIGhlaWdodCk7XG4gICAgc2V0UHJlZml4ZWRQcm9wZXJ0eShfcC5yc2NyYXRjaCwgJ2xhYmVsTGluZUhlaWdodCcsIHByZWZpeCwgbGFiZWxMaW5lSGVpZ2h0KTtcbiAgfTtcblxuICBCUnAkOS5nZXRMYWJlbFRleHQgPSBmdW5jdGlvbiAoZWxlLCBwcmVmaXgpIHtcbiAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG4gICAgdmFyIHBmZCA9IHByZWZpeCA/IHByZWZpeCArICctJyA6ICcnO1xuICAgIHZhciB0ZXh0ID0gZWxlLnBzdHlsZShwZmQgKyAnbGFiZWwnKS5zdHJWYWx1ZTtcbiAgICB2YXIgdGV4dFRyYW5zZm9ybSA9IGVsZS5wc3R5bGUoJ3RleHQtdHJhbnNmb3JtJykudmFsdWU7XG5cbiAgICB2YXIgcnNjcmF0Y2ggPSBmdW5jdGlvbiByc2NyYXRjaChwcm9wTmFtZSwgdmFsdWUpIHtcbiAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICBzZXRQcmVmaXhlZFByb3BlcnR5KF9wLnJzY3JhdGNoLCBwcm9wTmFtZSwgcHJlZml4LCB2YWx1ZSk7XG4gICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBnZXRQcmVmaXhlZFByb3BlcnR5KF9wLnJzY3JhdGNoLCBwcm9wTmFtZSwgcHJlZml4KTtcbiAgICAgIH1cbiAgICB9OyAvLyBmb3IgZW1wdHkgdGV4dCwgc2tpcCBhbGwgcHJvY2Vzc2luZ1xuXG5cbiAgICBpZiAoIXRleHQpIHtcbiAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICBpZiAodGV4dFRyYW5zZm9ybSA9PSAnbm9uZScpIDsgZWxzZSBpZiAodGV4dFRyYW5zZm9ybSA9PSAndXBwZXJjYXNlJykge1xuICAgICAgdGV4dCA9IHRleHQudG9VcHBlckNhc2UoKTtcbiAgICB9IGVsc2UgaWYgKHRleHRUcmFuc2Zvcm0gPT0gJ2xvd2VyY2FzZScpIHtcbiAgICAgIHRleHQgPSB0ZXh0LnRvTG93ZXJDYXNlKCk7XG4gICAgfVxuXG4gICAgdmFyIHdyYXBTdHlsZSA9IGVsZS5wc3R5bGUoJ3RleHQtd3JhcCcpLnZhbHVlO1xuXG4gICAgaWYgKHdyYXBTdHlsZSA9PT0gJ3dyYXAnKSB7XG4gICAgICB2YXIgbGFiZWxLZXkgPSByc2NyYXRjaCgnbGFiZWxLZXknKTsgLy8gc2F2ZSByZWNhbGMgaWYgdGhlIGxhYmVsIGlzIHRoZSBzYW1lIGFzIGJlZm9yZVxuXG4gICAgICBpZiAobGFiZWxLZXkgIT0gbnVsbCAmJiByc2NyYXRjaCgnbGFiZWxXcmFwS2V5JykgPT09IGxhYmVsS2V5KSB7XG4gICAgICAgIHJldHVybiByc2NyYXRjaCgnbGFiZWxXcmFwQ2FjaGVkVGV4dCcpO1xuICAgICAgfVxuXG4gICAgICB2YXIgendzcCA9IFwiXFx1MjAwQlwiO1xuICAgICAgdmFyIGxpbmVzID0gdGV4dC5zcGxpdCgnXFxuJyk7XG4gICAgICB2YXIgbWF4VyA9IGVsZS5wc3R5bGUoJ3RleHQtbWF4LXdpZHRoJykucGZWYWx1ZTtcbiAgICAgIHZhciBvdmVyZmxvdyA9IGVsZS5wc3R5bGUoJ3RleHQtb3ZlcmZsb3ctd3JhcCcpLnZhbHVlO1xuICAgICAgdmFyIG92ZXJmbG93QW55ID0gb3ZlcmZsb3cgPT09ICdhbnl3aGVyZSc7XG4gICAgICB2YXIgd3JhcHBlZExpbmVzID0gW107XG4gICAgICB2YXIgd29yZHNSZWdleCA9IC9bXFxzXFx1MjAwYl0rLztcbiAgICAgIHZhciB3b3JkU2VwYXJhdG9yID0gb3ZlcmZsb3dBbnkgPyAnJyA6ICcgJztcblxuICAgICAgZm9yICh2YXIgbCA9IDA7IGwgPCBsaW5lcy5sZW5ndGg7IGwrKykge1xuICAgICAgICB2YXIgbGluZSA9IGxpbmVzW2xdO1xuICAgICAgICB2YXIgbGluZURpbXMgPSB0aGlzLmNhbGN1bGF0ZUxhYmVsRGltZW5zaW9ucyhlbGUsIGxpbmUpO1xuICAgICAgICB2YXIgbGluZVcgPSBsaW5lRGltcy53aWR0aDtcblxuICAgICAgICBpZiAob3ZlcmZsb3dBbnkpIHtcbiAgICAgICAgICB2YXIgcHJvY2Vzc2VkTGluZSA9IGxpbmUuc3BsaXQoJycpLmpvaW4oendzcCk7XG4gICAgICAgICAgbGluZSA9IHByb2Nlc3NlZExpbmU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobGluZVcgPiBtYXhXKSB7XG4gICAgICAgICAgLy8gbGluZSBpcyB0b28gbG9uZ1xuICAgICAgICAgIHZhciB3b3JkcyA9IGxpbmUuc3BsaXQod29yZHNSZWdleCk7XG4gICAgICAgICAgdmFyIHN1YmxpbmUgPSAnJztcblxuICAgICAgICAgIGZvciAodmFyIHcgPSAwOyB3IDwgd29yZHMubGVuZ3RoOyB3KyspIHtcbiAgICAgICAgICAgIHZhciB3b3JkID0gd29yZHNbd107XG4gICAgICAgICAgICB2YXIgdGVzdExpbmUgPSBzdWJsaW5lLmxlbmd0aCA9PT0gMCA/IHdvcmQgOiBzdWJsaW5lICsgd29yZFNlcGFyYXRvciArIHdvcmQ7XG4gICAgICAgICAgICB2YXIgdGVzdERpbXMgPSB0aGlzLmNhbGN1bGF0ZUxhYmVsRGltZW5zaW9ucyhlbGUsIHRlc3RMaW5lKTtcbiAgICAgICAgICAgIHZhciB0ZXN0VyA9IHRlc3REaW1zLndpZHRoO1xuXG4gICAgICAgICAgICBpZiAodGVzdFcgPD0gbWF4Vykge1xuICAgICAgICAgICAgICAvLyB3b3JkIGZpdHMgb24gY3VycmVudCBsaW5lXG4gICAgICAgICAgICAgIHN1YmxpbmUgKz0gd29yZCArIHdvcmRTZXBhcmF0b3I7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAvLyB3b3JkIHN0YXJ0cyBuZXcgbGluZVxuICAgICAgICAgICAgICBpZiAoc3VibGluZSkge1xuICAgICAgICAgICAgICAgIHdyYXBwZWRMaW5lcy5wdXNoKHN1YmxpbmUpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgc3VibGluZSA9IHdvcmQgKyB3b3JkU2VwYXJhdG9yO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gaWYgdGhlcmUncyByZW1haW5pbmcgdGV4dCwgcHV0IGl0IGluIGEgd3JhcHBlZCBsaW5lXG5cblxuICAgICAgICAgIGlmICghc3VibGluZS5tYXRjaCgvXltcXHNcXHUyMDBiXSskLykpIHtcbiAgICAgICAgICAgIHdyYXBwZWRMaW5lcy5wdXNoKHN1YmxpbmUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBsaW5lIGlzIGFscmVhZHkgc2hvcnQgZW5vdWdoXG4gICAgICAgICAgd3JhcHBlZExpbmVzLnB1c2gobGluZSk7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gZm9yXG5cblxuICAgICAgcnNjcmF0Y2goJ2xhYmVsV3JhcENhY2hlZExpbmVzJywgd3JhcHBlZExpbmVzKTtcbiAgICAgIHRleHQgPSByc2NyYXRjaCgnbGFiZWxXcmFwQ2FjaGVkVGV4dCcsIHdyYXBwZWRMaW5lcy5qb2luKCdcXG4nKSk7XG4gICAgICByc2NyYXRjaCgnbGFiZWxXcmFwS2V5JywgbGFiZWxLZXkpO1xuICAgIH0gZWxzZSBpZiAod3JhcFN0eWxlID09PSAnZWxsaXBzaXMnKSB7XG4gICAgICB2YXIgX21heFcgPSBlbGUucHN0eWxlKCd0ZXh0LW1heC13aWR0aCcpLnBmVmFsdWU7XG4gICAgICB2YXIgZWxsaXBzaXplZCA9ICcnO1xuICAgICAgdmFyIGVsbGlwc2lzID0gXCJcXHUyMDI2XCI7XG4gICAgICB2YXIgaW5jTGFzdENoID0gZmFsc2U7XG5cbiAgICAgIGlmICh0aGlzLmNhbGN1bGF0ZUxhYmVsRGltZW5zaW9ucyhlbGUsIHRleHQpLndpZHRoIDwgX21heFcpIHtcbiAgICAgICAgLy8gdGhlIGxhYmVsIGFscmVhZHkgZml0c1xuICAgICAgICByZXR1cm4gdGV4dDtcbiAgICAgIH1cblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0ZXh0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciB3aWR0aFdpdGhOZXh0Q2ggPSB0aGlzLmNhbGN1bGF0ZUxhYmVsRGltZW5zaW9ucyhlbGUsIGVsbGlwc2l6ZWQgKyB0ZXh0W2ldICsgZWxsaXBzaXMpLndpZHRoO1xuXG4gICAgICAgIGlmICh3aWR0aFdpdGhOZXh0Q2ggPiBfbWF4Vykge1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgZWxsaXBzaXplZCArPSB0ZXh0W2ldO1xuXG4gICAgICAgIGlmIChpID09PSB0ZXh0Lmxlbmd0aCAtIDEpIHtcbiAgICAgICAgICBpbmNMYXN0Q2ggPSB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICghaW5jTGFzdENoKSB7XG4gICAgICAgIGVsbGlwc2l6ZWQgKz0gZWxsaXBzaXM7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBlbGxpcHNpemVkO1xuICAgIH0gLy8gaWYgZWxsaXBzaXplXG5cblxuICAgIHJldHVybiB0ZXh0O1xuICB9O1xuXG4gIEJScCQ5LmdldExhYmVsSnVzdGlmaWNhdGlvbiA9IGZ1bmN0aW9uIChlbGUpIHtcbiAgICB2YXIganVzdGlmaWNhdGlvbiA9IGVsZS5wc3R5bGUoJ3RleHQtanVzdGlmaWNhdGlvbicpLnN0clZhbHVlO1xuICAgIHZhciB0ZXh0SGFsaWduID0gZWxlLnBzdHlsZSgndGV4dC1oYWxpZ24nKS5zdHJWYWx1ZTtcblxuICAgIGlmIChqdXN0aWZpY2F0aW9uID09PSAnYXV0bycpIHtcbiAgICAgIGlmIChlbGUuaXNOb2RlKCkpIHtcbiAgICAgICAgc3dpdGNoICh0ZXh0SGFsaWduKSB7XG4gICAgICAgICAgY2FzZSAnbGVmdCc6XG4gICAgICAgICAgICByZXR1cm4gJ3JpZ2h0JztcblxuICAgICAgICAgIGNhc2UgJ3JpZ2h0JzpcbiAgICAgICAgICAgIHJldHVybiAnbGVmdCc7XG5cbiAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgcmV0dXJuICdjZW50ZXInO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gJ2NlbnRlcic7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBqdXN0aWZpY2F0aW9uO1xuICAgIH1cbiAgfTtcblxuICBCUnAkOS5jYWxjdWxhdGVMYWJlbERpbWVuc2lvbnMgPSBmdW5jdGlvbiAoZWxlLCB0ZXh0KSB7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBjYWNoZUtleSA9IGhhc2hTdHJpbmcodGV4dCwgZWxlLl9wcml2YXRlLmxhYmVsRGltc0tleSk7XG4gICAgdmFyIGNhY2hlID0gci5sYWJlbERpbUNhY2hlIHx8IChyLmxhYmVsRGltQ2FjaGUgPSBbXSk7XG4gICAgdmFyIGV4aXN0aW5nVmFsID0gY2FjaGVbY2FjaGVLZXldO1xuXG4gICAgaWYgKGV4aXN0aW5nVmFsICE9IG51bGwpIHtcbiAgICAgIHJldHVybiBleGlzdGluZ1ZhbDtcbiAgICB9XG5cbiAgICB2YXIgcGFkZGluZyA9IDA7IC8vIGFkZCBwYWRkaW5nIGFyb3VuZCB0ZXh0IGRpbXMsIGFzIHRoZSBtZWFzdXJlbWVudCBpc24ndCB0aGF0IGFjY3VyYXRlXG5cbiAgICB2YXIgZlN0eWxlID0gZWxlLnBzdHlsZSgnZm9udC1zdHlsZScpLnN0clZhbHVlO1xuICAgIHZhciBzaXplID0gZWxlLnBzdHlsZSgnZm9udC1zaXplJykucGZWYWx1ZTtcbiAgICB2YXIgZmFtaWx5ID0gZWxlLnBzdHlsZSgnZm9udC1mYW1pbHknKS5zdHJWYWx1ZTtcbiAgICB2YXIgd2VpZ2h0ID0gZWxlLnBzdHlsZSgnZm9udC13ZWlnaHQnKS5zdHJWYWx1ZTtcbiAgICB2YXIgY2FudmFzID0gdGhpcy5sYWJlbENhbGNDYW52YXM7XG4gICAgdmFyIGMyZCA9IHRoaXMubGFiZWxDYWxjQ2FudmFzQ29udGV4dDtcblxuICAgIGlmICghY2FudmFzKSB7XG4gICAgICBjYW52YXMgPSB0aGlzLmxhYmVsQ2FsY0NhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgICAgYzJkID0gdGhpcy5sYWJlbENhbGNDYW52YXNDb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgICB2YXIgZHMgPSBjYW52YXMuc3R5bGU7XG4gICAgICBkcy5wb3NpdGlvbiA9ICdhYnNvbHV0ZSc7XG4gICAgICBkcy5sZWZ0ID0gJy05OTk5cHgnO1xuICAgICAgZHMudG9wID0gJy05OTk5cHgnO1xuICAgICAgZHMuekluZGV4ID0gJy0xJztcbiAgICAgIGRzLnZpc2liaWxpdHkgPSAnaGlkZGVuJztcbiAgICAgIGRzLnBvaW50ZXJFdmVudHMgPSAnbm9uZSc7XG4gICAgfVxuXG4gICAgYzJkLmZvbnQgPSBcIlwiLmNvbmNhdChmU3R5bGUsIFwiIFwiKS5jb25jYXQod2VpZ2h0LCBcIiBcIikuY29uY2F0KHNpemUsIFwicHggXCIpLmNvbmNhdChmYW1pbHkpO1xuICAgIHZhciB3aWR0aCA9IDA7XG4gICAgdmFyIGhlaWdodCA9IDA7XG4gICAgdmFyIGxpbmVzID0gdGV4dC5zcGxpdCgnXFxuJyk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgbGluZSA9IGxpbmVzW2ldO1xuICAgICAgdmFyIG1ldHJpY3MgPSBjMmQubWVhc3VyZVRleHQobGluZSk7XG4gICAgICB2YXIgdyA9IE1hdGguY2VpbChtZXRyaWNzLndpZHRoKTtcbiAgICAgIHZhciBoID0gc2l6ZTtcbiAgICAgIHdpZHRoID0gTWF0aC5tYXgodywgd2lkdGgpO1xuICAgICAgaGVpZ2h0ICs9IGg7XG4gICAgfVxuXG4gICAgd2lkdGggKz0gcGFkZGluZztcbiAgICBoZWlnaHQgKz0gcGFkZGluZztcbiAgICByZXR1cm4gY2FjaGVbY2FjaGVLZXldID0ge1xuICAgICAgd2lkdGg6IHdpZHRoLFxuICAgICAgaGVpZ2h0OiBoZWlnaHRcbiAgICB9O1xuICB9O1xuXG4gIEJScCQ5LmNhbGN1bGF0ZUxhYmVsQW5nbGUgPSBmdW5jdGlvbiAoZWxlLCBwcmVmaXgpIHtcbiAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG4gICAgdmFyIHJzID0gX3AucnNjcmF0Y2g7XG4gICAgdmFyIGlzRWRnZSA9IGVsZS5pc0VkZ2UoKTtcbiAgICB2YXIgcHJlZml4RGFzaCA9IHByZWZpeCA/IHByZWZpeCArICctJyA6ICcnO1xuICAgIHZhciByb3QgPSBlbGUucHN0eWxlKHByZWZpeERhc2ggKyAndGV4dC1yb3RhdGlvbicpO1xuICAgIHZhciByb3RTdHIgPSByb3Quc3RyVmFsdWU7XG5cbiAgICBpZiAocm90U3RyID09PSAnbm9uZScpIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH0gZWxzZSBpZiAoaXNFZGdlICYmIHJvdFN0ciA9PT0gJ2F1dG9yb3RhdGUnKSB7XG4gICAgICByZXR1cm4gcnMubGFiZWxBdXRvQW5nbGU7XG4gICAgfSBlbHNlIGlmIChyb3RTdHIgPT09ICdhdXRvcm90YXRlJykge1xuICAgICAgcmV0dXJuIDA7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiByb3QucGZWYWx1ZTtcbiAgICB9XG4gIH07XG5cbiAgQlJwJDkuY2FsY3VsYXRlTGFiZWxBbmdsZXMgPSBmdW5jdGlvbiAoZWxlKSB7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBpc0VkZ2UgPSBlbGUuaXNFZGdlKCk7XG4gICAgdmFyIF9wID0gZWxlLl9wcml2YXRlO1xuICAgIHZhciBycyA9IF9wLnJzY3JhdGNoO1xuICAgIHJzLmxhYmVsQW5nbGUgPSByLmNhbGN1bGF0ZUxhYmVsQW5nbGUoZWxlKTtcblxuICAgIGlmIChpc0VkZ2UpIHtcbiAgICAgIHJzLnNvdXJjZUxhYmVsQW5nbGUgPSByLmNhbGN1bGF0ZUxhYmVsQW5nbGUoZWxlLCAnc291cmNlJyk7XG4gICAgICBycy50YXJnZXRMYWJlbEFuZ2xlID0gci5jYWxjdWxhdGVMYWJlbEFuZ2xlKGVsZSwgJ3RhcmdldCcpO1xuICAgIH1cbiAgfTtcblxuICB2YXIgQlJwJDggPSB7fTtcbiAgdmFyIFRPT19TTUFMTF9DVVRfUkVDVCA9IDI4O1xuICB2YXIgd2FybmVkQ3V0UmVjdCA9IGZhbHNlO1xuXG4gIEJScCQ4LmdldE5vZGVTaGFwZSA9IGZ1bmN0aW9uIChub2RlKSB7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBzaGFwZSA9IG5vZGUucHN0eWxlKCdzaGFwZScpLnZhbHVlO1xuXG4gICAgaWYgKHNoYXBlID09PSAnY3V0cmVjdGFuZ2xlJyAmJiAobm9kZS53aWR0aCgpIDwgVE9PX1NNQUxMX0NVVF9SRUNUIHx8IG5vZGUuaGVpZ2h0KCkgPCBUT09fU01BTExfQ1VUX1JFQ1QpKSB7XG4gICAgICBpZiAoIXdhcm5lZEN1dFJlY3QpIHtcbiAgICAgICAgd2FybignVGhlIGBjdXRyZWN0YW5nbGVgIG5vZGUgc2hhcGUgY2FuIG5vdCBiZSB1c2VkIGF0IHNtYWxsIHNpemVzIHNvIGByZWN0YW5nbGVgIGlzIHVzZWQgaW5zdGVhZCcpO1xuICAgICAgICB3YXJuZWRDdXRSZWN0ID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuICdyZWN0YW5nbGUnO1xuICAgIH1cblxuICAgIGlmIChub2RlLmlzUGFyZW50KCkpIHtcbiAgICAgIGlmIChzaGFwZSA9PT0gJ3JlY3RhbmdsZScgfHwgc2hhcGUgPT09ICdyb3VuZHJlY3RhbmdsZScgfHwgc2hhcGUgPT09ICdyb3VuZC1yZWN0YW5nbGUnIHx8IHNoYXBlID09PSAnY3V0cmVjdGFuZ2xlJyB8fCBzaGFwZSA9PT0gJ2N1dC1yZWN0YW5nbGUnIHx8IHNoYXBlID09PSAnYmFycmVsJykge1xuICAgICAgICByZXR1cm4gc2hhcGU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gJ3JlY3RhbmdsZSc7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHNoYXBlID09PSAncG9seWdvbicpIHtcbiAgICAgIHZhciBwb2ludHMgPSBub2RlLnBzdHlsZSgnc2hhcGUtcG9seWdvbi1wb2ludHMnKS52YWx1ZTtcbiAgICAgIHJldHVybiByLm5vZGVTaGFwZXMubWFrZVBvbHlnb24ocG9pbnRzKS5uYW1lO1xuICAgIH1cblxuICAgIHJldHVybiBzaGFwZTtcbiAgfTtcblxuICB2YXIgQlJwJDcgPSB7fTtcblxuICBCUnAkNy5yZWdpc3RlckNhbGN1bGF0aW9uTGlzdGVuZXJzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBjeSA9IHRoaXMuY3k7XG4gICAgdmFyIGVsZXNUb1VwZGF0ZSA9IGN5LmNvbGxlY3Rpb24oKTtcbiAgICB2YXIgciA9IHRoaXM7XG5cbiAgICB2YXIgZW5xdWV1ZSA9IGZ1bmN0aW9uIGVucXVldWUoZWxlcykge1xuICAgICAgdmFyIGRpcnR5U3R5bGVDYWNoZXMgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IHRydWU7XG4gICAgICBlbGVzVG9VcGRhdGUubWVyZ2UoZWxlcyk7XG5cbiAgICAgIGlmIChkaXJ0eVN0eWxlQ2FjaGVzKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBlbGUgPSBlbGVzW2ldO1xuICAgICAgICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICAgICAgICB2YXIgcnN0eWxlID0gX3AucnN0eWxlO1xuICAgICAgICAgIHJzdHlsZS5jbGVhbiA9IGZhbHNlO1xuICAgICAgICAgIHJzdHlsZS5jbGVhbkNvbm5lY3RlZCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHIuYmluZGVyKGN5KS5vbignYm91bmRzLiogZGlydHkuKicsIGZ1bmN0aW9uIG9uRGlydHlCb3VuZHMoZSkge1xuICAgICAgdmFyIGVsZSA9IGUudGFyZ2V0O1xuICAgICAgZW5xdWV1ZShlbGUpO1xuICAgIH0pLm9uKCdzdHlsZS4qIGJhY2tncm91bmQuKicsIGZ1bmN0aW9uIG9uRGlydHlTdHlsZShlKSB7XG4gICAgICB2YXIgZWxlID0gZS50YXJnZXQ7XG4gICAgICBlbnF1ZXVlKGVsZSwgZmFsc2UpO1xuICAgIH0pO1xuXG4gICAgdmFyIHVwZGF0ZUVsZUNhbGNzID0gZnVuY3Rpb24gdXBkYXRlRWxlQ2FsY3Mod2lsbERyYXcpIHtcbiAgICAgIGlmICh3aWxsRHJhdykge1xuICAgICAgICB2YXIgZm5zID0gci5vblVwZGF0ZUVsZUNhbGNzRm5zOyAvLyBiZWNhdXNlIHdlIG5lZWQgdG8gaGF2ZSB1cC10by1kYXRlIHN0eWxlIChlLmcuIHN0eWxlc2hlZXQgbWFwcGVycylcbiAgICAgICAgLy8gYmVmb3JlIGNhbGN1bGF0aW5nIHJlbmRlcmVkIHN0eWxlIChhbmQgcHN0eWxlIG1pZ2h0IG5vdCBiZSBjYWxsZWQgeWV0KVxuXG4gICAgICAgIGVsZXNUb1VwZGF0ZS5jbGVhblN0eWxlKCk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBlbGVzVG9VcGRhdGUubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgZWxlID0gZWxlc1RvVXBkYXRlW2ldO1xuICAgICAgICAgIHZhciByc3R5bGUgPSBlbGUuX3ByaXZhdGUucnN0eWxlO1xuXG4gICAgICAgICAgaWYgKGVsZS5pc05vZGUoKSAmJiAhcnN0eWxlLmNsZWFuQ29ubmVjdGVkKSB7XG4gICAgICAgICAgICBlbnF1ZXVlKGVsZS5jb25uZWN0ZWRFZGdlcygpKTtcbiAgICAgICAgICAgIHJzdHlsZS5jbGVhbkNvbm5lY3RlZCA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGZucykge1xuICAgICAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBmbnMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgZm4gPSBmbnNbX2ldO1xuICAgICAgICAgICAgZm4od2lsbERyYXcsIGVsZXNUb1VwZGF0ZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgci5yZWNhbGN1bGF0ZVJlbmRlcmVkU3R5bGUoZWxlc1RvVXBkYXRlKTtcbiAgICAgICAgZWxlc1RvVXBkYXRlID0gY3kuY29sbGVjdGlvbigpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICByLmZsdXNoUmVuZGVyZWRTdHlsZVF1ZXVlID0gZnVuY3Rpb24gKCkge1xuICAgICAgdXBkYXRlRWxlQ2FsY3ModHJ1ZSk7XG4gICAgfTtcblxuICAgIHIuYmVmb3JlUmVuZGVyKHVwZGF0ZUVsZUNhbGNzLCByLmJlZm9yZVJlbmRlclByaW9yaXRpZXMuZWxlQ2FsY3MpO1xuICB9O1xuXG4gIEJScCQ3Lm9uVXBkYXRlRWxlQ2FsY3MgPSBmdW5jdGlvbiAoZm4pIHtcbiAgICB2YXIgZm5zID0gdGhpcy5vblVwZGF0ZUVsZUNhbGNzRm5zID0gdGhpcy5vblVwZGF0ZUVsZUNhbGNzRm5zIHx8IFtdO1xuICAgIGZucy5wdXNoKGZuKTtcbiAgfTtcblxuICBCUnAkNy5yZWNhbGN1bGF0ZVJlbmRlcmVkU3R5bGUgPSBmdW5jdGlvbiAoZWxlcywgdXNlQ2FjaGUpIHtcbiAgICB2YXIgaXNDbGVhbkNvbm5lY3RlZCA9IGZ1bmN0aW9uIGlzQ2xlYW5Db25uZWN0ZWQoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlLl9wcml2YXRlLnJzdHlsZS5jbGVhbkNvbm5lY3RlZDtcbiAgICB9O1xuXG4gICAgdmFyIGVkZ2VzID0gW107XG4gICAgdmFyIG5vZGVzID0gW107IC8vIHRoZSByZW5kZXJlciBjYW4ndCBiZSB1c2VkIGZvciBjYWxjcyB3aGVuIGRlc3Ryb3llZCwgZS5nLiBlbGUuYm91bmRpbmdCb3goKVxuXG4gICAgaWYgKHRoaXMuZGVzdHJveWVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfSAvLyB1c2UgY2FjaGUgYnkgZGVmYXVsdCBmb3IgcGVyZlxuXG5cbiAgICBpZiAodXNlQ2FjaGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdXNlQ2FjaGUgPSB0cnVlO1xuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG4gICAgICB2YXIgX3AgPSBlbGUuX3ByaXZhdGU7XG4gICAgICB2YXIgcnN0eWxlID0gX3AucnN0eWxlOyAvLyBhbiBlZGdlIG1heSBiZSBpbXBsaWNpdGx5IGRpcnR5IGIvYyBvZiBvbmUgb2YgaXRzIGNvbm5lY3RlZCBub2Rlc1xuICAgICAgLy8gKGFuZCBhIHJlcXVlc3QgZm9yIHJlY2FsYyBtYXkgY29tZSBpbiBiZXR3ZWVuIGZyYW1lcylcblxuICAgICAgaWYgKGVsZS5pc0VkZ2UoKSAmJiAoIWlzQ2xlYW5Db25uZWN0ZWQoZWxlLnNvdXJjZSgpKSB8fCAhaXNDbGVhbkNvbm5lY3RlZChlbGUudGFyZ2V0KCkpKSkge1xuICAgICAgICByc3R5bGUuY2xlYW4gPSBmYWxzZTtcbiAgICAgIH0gLy8gb25seSB1cGRhdGUgaWYgZGlydHkgYW5kIGluIGdyYXBoXG5cblxuICAgICAgaWYgKHVzZUNhY2hlICYmIHJzdHlsZS5jbGVhbiB8fCBlbGUucmVtb3ZlZCgpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfSAvLyBvbmx5IHVwZGF0ZSBpZiBub3QgZGlzcGxheTogbm9uZVxuXG5cbiAgICAgIGlmIChlbGUucHN0eWxlKCdkaXNwbGF5JykudmFsdWUgPT09ICdub25lJykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKF9wLmdyb3VwID09PSAnbm9kZXMnKSB7XG4gICAgICAgIG5vZGVzLnB1c2goZWxlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGVkZ2VzXG4gICAgICAgIGVkZ2VzLnB1c2goZWxlKTtcbiAgICAgIH1cblxuICAgICAgcnN0eWxlLmNsZWFuID0gdHJ1ZTtcbiAgICB9IC8vIHVwZGF0ZSBub2RlIGRhdGEgZnJvbSBwcm9qZWN0aW9uc1xuXG5cbiAgICBmb3IgKHZhciBfaTIgPSAwOyBfaTIgPCBub2Rlcy5sZW5ndGg7IF9pMisrKSB7XG4gICAgICB2YXIgX2VsZSA9IG5vZGVzW19pMl07XG4gICAgICB2YXIgX3AyID0gX2VsZS5fcHJpdmF0ZTtcbiAgICAgIHZhciBfcnN0eWxlID0gX3AyLnJzdHlsZTtcblxuICAgICAgdmFyIHBvcyA9IF9lbGUucG9zaXRpb24oKTtcblxuICAgICAgdGhpcy5yZWNhbGN1bGF0ZU5vZGVMYWJlbFByb2plY3Rpb24oX2VsZSk7XG4gICAgICBfcnN0eWxlLm5vZGVYID0gcG9zLng7XG4gICAgICBfcnN0eWxlLm5vZGVZID0gcG9zLnk7XG4gICAgICBfcnN0eWxlLm5vZGVXID0gX2VsZS5wc3R5bGUoJ3dpZHRoJykucGZWYWx1ZTtcbiAgICAgIF9yc3R5bGUubm9kZUggPSBfZWxlLnBzdHlsZSgnaGVpZ2h0JykucGZWYWx1ZTtcbiAgICB9XG5cbiAgICB0aGlzLnJlY2FsY3VsYXRlRWRnZVByb2plY3Rpb25zKGVkZ2VzKTsgLy8gdXBkYXRlIGVkZ2UgZGF0YSBmcm9tIHByb2plY3Rpb25zXG5cbiAgICBmb3IgKHZhciBfaTMgPSAwOyBfaTMgPCBlZGdlcy5sZW5ndGg7IF9pMysrKSB7XG4gICAgICB2YXIgX2VsZTIgPSBlZGdlc1tfaTNdO1xuICAgICAgdmFyIF9wMyA9IF9lbGUyLl9wcml2YXRlO1xuICAgICAgdmFyIF9yc3R5bGUyID0gX3AzLnJzdHlsZTtcbiAgICAgIHZhciBycyA9IF9wMy5yc2NyYXRjaDsgLy8gdXBkYXRlIHJzdHlsZSBwb3NpdGlvbnNcblxuICAgICAgX3JzdHlsZTIuc3JjWCA9IHJzLmFycm93U3RhcnRYO1xuICAgICAgX3JzdHlsZTIuc3JjWSA9IHJzLmFycm93U3RhcnRZO1xuICAgICAgX3JzdHlsZTIudGd0WCA9IHJzLmFycm93RW5kWDtcbiAgICAgIF9yc3R5bGUyLnRndFkgPSBycy5hcnJvd0VuZFk7XG4gICAgICBfcnN0eWxlMi5taWRYID0gcnMubWlkWDtcbiAgICAgIF9yc3R5bGUyLm1pZFkgPSBycy5taWRZO1xuICAgICAgX3JzdHlsZTIubGFiZWxBbmdsZSA9IHJzLmxhYmVsQW5nbGU7XG4gICAgICBfcnN0eWxlMi5zb3VyY2VMYWJlbEFuZ2xlID0gcnMuc291cmNlTGFiZWxBbmdsZTtcbiAgICAgIF9yc3R5bGUyLnRhcmdldExhYmVsQW5nbGUgPSBycy50YXJnZXRMYWJlbEFuZ2xlO1xuICAgIH1cbiAgfTtcblxuICB2YXIgQlJwJDYgPSB7fTtcblxuICBCUnAkNi51cGRhdGVDYWNoZWRHcmFiYmVkRWxlcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZWxlcyA9IHRoaXMuY2FjaGVkWlNvcnRlZEVsZXM7XG5cbiAgICBpZiAoIWVsZXMpIHtcbiAgICAgIC8vIGp1c3QgbGV0IHRoaXMgYmUgcmVjYWxjdWxhdGVkIG9uIHRoZSBuZXh0IHogc29ydCB0aWNrXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgZWxlcy5kcmFnID0gW107XG4gICAgZWxlcy5ub25kcmFnID0gW107XG4gICAgdmFyIGdyYWJUYXJnZXRzID0gW107XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBlbGUgPSBlbGVzW2ldO1xuICAgICAgdmFyIHJzID0gZWxlLl9wcml2YXRlLnJzY3JhdGNoO1xuXG4gICAgICBpZiAoZWxlLmdyYWJiZWQoKSAmJiAhZWxlLmlzUGFyZW50KCkpIHtcbiAgICAgICAgZ3JhYlRhcmdldHMucHVzaChlbGUpO1xuICAgICAgfSBlbHNlIGlmIChycy5pbkRyYWdMYXllcikge1xuICAgICAgICBlbGVzLmRyYWcucHVzaChlbGUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWxlcy5ub25kcmFnLnB1c2goZWxlKTtcbiAgICAgIH1cbiAgICB9IC8vIHB1dCB0aGUgZ3JhYiB0YXJnZXQgbm9kZXMgbGFzdCBzbyBpdCdzIG9uIHRvcCBvZiBpdHMgbmVpZ2hib3VyaG9vZFxuXG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGdyYWJUYXJnZXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZWxlID0gZ3JhYlRhcmdldHNbaV07XG4gICAgICBlbGVzLmRyYWcucHVzaChlbGUpO1xuICAgIH1cbiAgfTtcblxuICBCUnAkNi5pbnZhbGlkYXRlQ2FjaGVkWlNvcnRlZEVsZXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5jYWNoZWRaU29ydGVkRWxlcyA9IG51bGw7XG4gIH07XG5cbiAgQlJwJDYuZ2V0Q2FjaGVkWlNvcnRlZEVsZXMgPSBmdW5jdGlvbiAoZm9yY2VSZWNhbGMpIHtcbiAgICBpZiAoZm9yY2VSZWNhbGMgfHwgIXRoaXMuY2FjaGVkWlNvcnRlZEVsZXMpIHtcbiAgICAgIHZhciBlbGVzID0gdGhpcy5jeS5tdXRhYmxlRWxlbWVudHMoKS50b0FycmF5KCk7XG4gICAgICBlbGVzLnNvcnQoekluZGV4U29ydCk7XG4gICAgICBlbGVzLmludGVyYWN0aXZlID0gZWxlcy5maWx0ZXIoZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICByZXR1cm4gZWxlLmludGVyYWN0aXZlKCk7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuY2FjaGVkWlNvcnRlZEVsZXMgPSBlbGVzO1xuICAgICAgdGhpcy51cGRhdGVDYWNoZWRHcmFiYmVkRWxlcygpO1xuICAgIH0gZWxzZSB7XG4gICAgICBlbGVzID0gdGhpcy5jYWNoZWRaU29ydGVkRWxlcztcbiAgICB9XG5cbiAgICByZXR1cm4gZWxlcztcbiAgfTtcblxuICB2YXIgQlJwJDUgPSB7fTtcbiAgW0JScCRlLCBCUnAkZCwgQlJwJGMsIEJScCRiLCBCUnAkYSwgQlJwJDksIEJScCQ4LCBCUnAkNywgQlJwJDZdLmZvckVhY2goZnVuY3Rpb24gKHByb3BzKSB7XG4gICAgZXh0ZW5kKEJScCQ1LCBwcm9wcyk7XG4gIH0pO1xuXG4gIHZhciBCUnAkNCA9IHt9O1xuXG4gIEJScCQ0LmdldENhY2hlZEltYWdlID0gZnVuY3Rpb24gKHVybCwgY3Jvc3NPcmlnaW4sIG9uTG9hZCkge1xuICAgIHZhciByID0gdGhpcztcbiAgICB2YXIgaW1hZ2VDYWNoZSA9IHIuaW1hZ2VDYWNoZSA9IHIuaW1hZ2VDYWNoZSB8fCB7fTtcbiAgICB2YXIgY2FjaGUgPSBpbWFnZUNhY2hlW3VybF07XG5cbiAgICBpZiAoY2FjaGUpIHtcbiAgICAgIGlmICghY2FjaGUuaW1hZ2UuY29tcGxldGUpIHtcbiAgICAgICAgY2FjaGUuaW1hZ2UuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIG9uTG9hZCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBjYWNoZS5pbWFnZTtcbiAgICB9IGVsc2Uge1xuICAgICAgY2FjaGUgPSBpbWFnZUNhY2hlW3VybF0gPSBpbWFnZUNhY2hlW3VybF0gfHwge307XG4gICAgICB2YXIgaW1hZ2UgPSBjYWNoZS5pbWFnZSA9IG5ldyBJbWFnZSgpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cbiAgICAgIGltYWdlLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCBvbkxvYWQpO1xuICAgICAgaW1hZ2UuYWRkRXZlbnRMaXN0ZW5lcignZXJyb3InLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGltYWdlLmVycm9yID0gdHJ1ZTtcbiAgICAgIH0pOyAvLyAjMTU4MiBzYWZhcmkgZG9lc24ndCBsb2FkIGRhdGEgdXJpcyB3aXRoIGNyb3NzT3JpZ2luIHByb3Blcmx5XG4gICAgICAvLyBodHRwczovL2J1Z3Mud2Via2l0Lm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTIzOTc4XG5cbiAgICAgIHZhciBkYXRhVXJpUHJlZml4ID0gJ2RhdGE6JztcbiAgICAgIHZhciBpc0RhdGFVcmkgPSB1cmwuc3Vic3RyaW5nKDAsIGRhdGFVcmlQcmVmaXgubGVuZ3RoKS50b0xvd2VyQ2FzZSgpID09PSBkYXRhVXJpUHJlZml4O1xuXG4gICAgICBpZiAoIWlzRGF0YVVyaSkge1xuICAgICAgICAvLyBpZiBjcm9zc29yaWdpbiBpcyAnbnVsbCcoc3RyaW5naWZpZWQpLCB0aGVuIG1hbnVhbGx5IHNldCBpdCB0byBudWxsIFxuICAgICAgICBjcm9zc09yaWdpbiA9IGNyb3NzT3JpZ2luID09PSAnbnVsbCcgPyBudWxsIDogY3Jvc3NPcmlnaW47XG4gICAgICAgIGltYWdlLmNyb3NzT3JpZ2luID0gY3Jvc3NPcmlnaW47IC8vIHByZXZlbnQgdGFpbnRlZCBjYW52YXNcbiAgICAgIH1cblxuICAgICAgaW1hZ2Uuc3JjID0gdXJsO1xuICAgICAgcmV0dXJuIGltYWdlO1xuICAgIH1cbiAgfTtcblxuICB2YXIgQlJwJDMgPSB7fTtcbiAgLyogZ2xvYmFsIGRvY3VtZW50LCB3aW5kb3csIFJlc2l6ZU9ic2VydmVyLCBNdXRhdGlvbk9ic2VydmVyICovXG5cbiAgQlJwJDMucmVnaXN0ZXJCaW5kaW5nID0gZnVuY3Rpb24gKHRhcmdldCwgZXZlbnQsIGhhbmRsZXIsIHVzZUNhcHR1cmUpIHtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkoYXJndW1lbnRzLCBbMV0pOyAvLyBjb3B5XG5cbiAgICB2YXIgYiA9IHRoaXMuYmluZGVyKHRhcmdldCk7XG4gICAgcmV0dXJuIGIub24uYXBwbHkoYiwgYXJncyk7XG4gIH07XG5cbiAgQlJwJDMuYmluZGVyID0gZnVuY3Rpb24gKHRndCkge1xuICAgIHZhciByID0gdGhpcztcbiAgICB2YXIgY29udGFpbmVyV2luZG93ID0gci5jeS53aW5kb3coKTtcbiAgICB2YXIgdGd0SXNEb20gPSB0Z3QgPT09IGNvbnRhaW5lcldpbmRvdyB8fCB0Z3QgPT09IGNvbnRhaW5lcldpbmRvdy5kb2N1bWVudCB8fCB0Z3QgPT09IGNvbnRhaW5lcldpbmRvdy5kb2N1bWVudC5ib2R5IHx8IGRvbUVsZW1lbnQodGd0KTtcblxuICAgIGlmIChyLnN1cHBvcnRzUGFzc2l2ZUV2ZW50cyA9PSBudWxsKSB7XG4gICAgICAvLyBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9XSUNHL0V2ZW50TGlzdGVuZXJPcHRpb25zL2Jsb2IvZ2gtcGFnZXMvZXhwbGFpbmVyLm1kI2ZlYXR1cmUtZGV0ZWN0aW9uXG4gICAgICB2YXIgc3VwcG9ydHNQYXNzaXZlID0gZmFsc2U7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIHZhciBvcHRzID0gT2JqZWN0LmRlZmluZVByb3BlcnR5KHt9LCAncGFzc2l2ZScsIHtcbiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgICAgIHN1cHBvcnRzUGFzc2l2ZSA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBjb250YWluZXJXaW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigndGVzdCcsIG51bGwsIG9wdHMpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7Ly8gbm90IHN1cHBvcnRlZFxuICAgICAgfVxuXG4gICAgICByLnN1cHBvcnRzUGFzc2l2ZUV2ZW50cyA9IHN1cHBvcnRzUGFzc2l2ZTtcbiAgICB9XG5cbiAgICB2YXIgb24gPSBmdW5jdGlvbiBvbihldmVudCwgaGFuZGxlciwgdXNlQ2FwdHVyZSkge1xuICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuXG4gICAgICBpZiAodGd0SXNEb20gJiYgci5zdXBwb3J0c1Bhc3NpdmVFdmVudHMpIHtcbiAgICAgICAgLy8gcmVwbGFjZSB1c2VDYXB0dXJlIHcvIG9wdHMgb2JqXG4gICAgICAgIGFyZ3NbMl0gPSB7XG4gICAgICAgICAgY2FwdHVyZTogdXNlQ2FwdHVyZSAhPSBudWxsID8gdXNlQ2FwdHVyZSA6IGZhbHNlLFxuICAgICAgICAgIHBhc3NpdmU6IGZhbHNlLFxuICAgICAgICAgIG9uY2U6IGZhbHNlXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIHIuYmluZGluZ3MucHVzaCh7XG4gICAgICAgIHRhcmdldDogdGd0LFxuICAgICAgICBhcmdzOiBhcmdzXG4gICAgICB9KTtcbiAgICAgICh0Z3QuYWRkRXZlbnRMaXN0ZW5lciB8fCB0Z3Qub24pLmFwcGx5KHRndCwgYXJncyk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIG9uOiBvbixcbiAgICAgIGFkZEV2ZW50TGlzdGVuZXI6IG9uLFxuICAgICAgYWRkTGlzdGVuZXI6IG9uLFxuICAgICAgYmluZDogb25cbiAgICB9O1xuICB9O1xuXG4gIEJScCQzLm5vZGVJc0RyYWdnYWJsZSA9IGZ1bmN0aW9uIChub2RlKSB7XG4gICAgcmV0dXJuIG5vZGUgJiYgbm9kZS5pc05vZGUoKSAmJiAhbm9kZS5sb2NrZWQoKSAmJiBub2RlLmdyYWJiYWJsZSgpO1xuICB9O1xuXG4gIEJScCQzLm5vZGVJc0dyYWJiYWJsZSA9IGZ1bmN0aW9uIChub2RlKSB7XG4gICAgcmV0dXJuIHRoaXMubm9kZUlzRHJhZ2dhYmxlKG5vZGUpICYmIG5vZGUuaW50ZXJhY3RpdmUoKTtcbiAgfTtcblxuICBCUnAkMy5sb2FkID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciByID0gdGhpcztcbiAgICB2YXIgY29udGFpbmVyV2luZG93ID0gci5jeS53aW5kb3coKTtcblxuICAgIHZhciBpc1NlbGVjdGVkID0gZnVuY3Rpb24gaXNTZWxlY3RlZChlbGUpIHtcbiAgICAgIHJldHVybiBlbGUuc2VsZWN0ZWQoKTtcbiAgICB9O1xuXG4gICAgdmFyIHRyaWdnZXJFdmVudHMgPSBmdW5jdGlvbiB0cmlnZ2VyRXZlbnRzKHRhcmdldCwgbmFtZXMsIGUsIHBvc2l0aW9uKSB7XG4gICAgICBpZiAodGFyZ2V0ID09IG51bGwpIHtcbiAgICAgICAgdGFyZ2V0ID0gci5jeTtcbiAgICAgIH1cblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuYW1lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgbmFtZSA9IG5hbWVzW2ldO1xuICAgICAgICB0YXJnZXQuZW1pdCh7XG4gICAgICAgICAgb3JpZ2luYWxFdmVudDogZSxcbiAgICAgICAgICB0eXBlOiBuYW1lLFxuICAgICAgICAgIHBvc2l0aW9uOiBwb3NpdGlvblxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGlzTXVsdFNlbEtleURvd24gPSBmdW5jdGlvbiBpc011bHRTZWxLZXlEb3duKGUpIHtcbiAgICAgIHJldHVybiBlLnNoaWZ0S2V5IHx8IGUubWV0YUtleSB8fCBlLmN0cmxLZXk7IC8vIG1heWJlIGUuYWx0S2V5XG4gICAgfTtcblxuICAgIHZhciBhbGxvd1Bhbm5pbmdQYXNzdGhyb3VnaCA9IGZ1bmN0aW9uIGFsbG93UGFubmluZ1Bhc3N0aHJvdWdoKGRvd24sIGRvd25zKSB7XG4gICAgICB2YXIgYWxsb3dQYXNzdGhyb3VnaCA9IHRydWU7XG5cbiAgICAgIGlmIChyLmN5Lmhhc0NvbXBvdW5kTm9kZXMoKSAmJiBkb3duICYmIGRvd24ucGFubmFibGUoKSkge1xuICAgICAgICAvLyBhIGdyYWJiYWJsZSBjb21wb3VuZCBub2RlIGJlbG93IHRoZSBlbGUgPT4gbm8gcGFzc3Rocm91Z2ggcGFubmluZ1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgZG93bnMgJiYgaSA8IGRvd25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgdmFyIGRvd24gPSBkb3duc1tpXTsgLy9pZiBhbnkgcGFyZW50IG5vZGUgaW4gZXZlbnQgaGllcmFyY2h5IGlzbid0IHBhbm5hYmxlLCByZWplY3QgcGFzc3Rocm91Z2hcblxuICAgICAgICAgIGlmIChkb3duLmlzTm9kZSgpICYmIGRvd24uaXNQYXJlbnQoKSAmJiAhZG93bi5wYW5uYWJsZSgpKSB7XG4gICAgICAgICAgICBhbGxvd1Bhc3N0aHJvdWdoID0gZmFsc2U7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGFsbG93UGFzc3Rocm91Z2ggPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gYWxsb3dQYXNzdGhyb3VnaDtcbiAgICB9O1xuXG4gICAgdmFyIHNldEdyYWJiZWQgPSBmdW5jdGlvbiBzZXRHcmFiYmVkKGVsZSkge1xuICAgICAgZWxlWzBdLl9wcml2YXRlLmdyYWJiZWQgPSB0cnVlO1xuICAgIH07XG5cbiAgICB2YXIgc2V0RnJlZWQgPSBmdW5jdGlvbiBzZXRGcmVlZChlbGUpIHtcbiAgICAgIGVsZVswXS5fcHJpdmF0ZS5ncmFiYmVkID0gZmFsc2U7XG4gICAgfTtcblxuICAgIHZhciBzZXRJbkRyYWdMYXllciA9IGZ1bmN0aW9uIHNldEluRHJhZ0xheWVyKGVsZSkge1xuICAgICAgZWxlWzBdLl9wcml2YXRlLnJzY3JhdGNoLmluRHJhZ0xheWVyID0gdHJ1ZTtcbiAgICB9O1xuXG4gICAgdmFyIHNldE91dERyYWdMYXllciA9IGZ1bmN0aW9uIHNldE91dERyYWdMYXllcihlbGUpIHtcbiAgICAgIGVsZVswXS5fcHJpdmF0ZS5yc2NyYXRjaC5pbkRyYWdMYXllciA9IGZhbHNlO1xuICAgIH07XG5cbiAgICB2YXIgc2V0R3JhYlRhcmdldCA9IGZ1bmN0aW9uIHNldEdyYWJUYXJnZXQoZWxlKSB7XG4gICAgICBlbGVbMF0uX3ByaXZhdGUucnNjcmF0Y2guaXNHcmFiVGFyZ2V0ID0gdHJ1ZTtcbiAgICB9O1xuXG4gICAgdmFyIHJlbW92ZUdyYWJUYXJnZXQgPSBmdW5jdGlvbiByZW1vdmVHcmFiVGFyZ2V0KGVsZSkge1xuICAgICAgZWxlWzBdLl9wcml2YXRlLnJzY3JhdGNoLmlzR3JhYlRhcmdldCA9IGZhbHNlO1xuICAgIH07XG5cbiAgICB2YXIgYWRkVG9EcmFnTGlzdCA9IGZ1bmN0aW9uIGFkZFRvRHJhZ0xpc3QoZWxlLCBvcHRzKSB7XG4gICAgICB2YXIgbGlzdCA9IG9wdHMuYWRkVG9MaXN0O1xuICAgICAgdmFyIGxpc3RIYXNFbGUgPSBsaXN0LmhhcyhlbGUpO1xuXG4gICAgICBpZiAoIWxpc3RIYXNFbGUgJiYgZWxlLmdyYWJiYWJsZSgpICYmICFlbGUubG9ja2VkKCkpIHtcbiAgICAgICAgbGlzdC5tZXJnZShlbGUpO1xuICAgICAgICBzZXRHcmFiYmVkKGVsZSk7XG4gICAgICB9XG4gICAgfTsgLy8gaGVscGVyIGZ1bmN0aW9uIHRvIGRldGVybWluZSB3aGljaCBjaGlsZCBub2RlcyBhbmQgaW5uZXIgZWRnZXNcbiAgICAvLyBvZiBhIGNvbXBvdW5kIG5vZGUgdG8gYmUgZHJhZ2dlZCBhcyB3ZWxsIGFzIHRoZSBncmFiYmVkIGFuZCBzZWxlY3RlZCBub2Rlc1xuXG5cbiAgICB2YXIgYWRkRGVzY2VuZGFudHNUb0RyYWcgPSBmdW5jdGlvbiBhZGREZXNjZW5kYW50c1RvRHJhZyhub2RlLCBvcHRzKSB7XG4gICAgICBpZiAoIW5vZGUuY3koKS5oYXNDb21wb3VuZE5vZGVzKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAob3B0cy5pbkRyYWdMYXllciA9PSBudWxsICYmIG9wdHMuYWRkVG9MaXN0ID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBub3RoaW5nIHRvIGRvXG5cblxuICAgICAgdmFyIGlubmVyTm9kZXMgPSBub2RlLmRlc2NlbmRhbnRzKCk7XG5cbiAgICAgIGlmIChvcHRzLmluRHJhZ0xheWVyKSB7XG4gICAgICAgIGlubmVyTm9kZXMuZm9yRWFjaChzZXRJbkRyYWdMYXllcik7XG4gICAgICAgIGlubmVyTm9kZXMuY29ubmVjdGVkRWRnZXMoKS5mb3JFYWNoKHNldEluRHJhZ0xheWVyKTtcbiAgICAgIH1cblxuICAgICAgaWYgKG9wdHMuYWRkVG9MaXN0KSB7XG4gICAgICAgIGFkZFRvRHJhZ0xpc3QoaW5uZXJOb2Rlcywgb3B0cyk7XG4gICAgICB9XG4gICAgfTsgLy8gYWRkcyB0aGUgZ2l2ZW4gbm9kZXMgYW5kIGl0cyBuZWlnaGJvdXJob29kIHRvIHRoZSBkcmFnIGxheWVyXG5cblxuICAgIHZhciBhZGROb2Rlc1RvRHJhZyA9IGZ1bmN0aW9uIGFkZE5vZGVzVG9EcmFnKG5vZGVzLCBvcHRzKSB7XG4gICAgICBvcHRzID0gb3B0cyB8fCB7fTtcbiAgICAgIHZhciBoYXNDb21wb3VuZE5vZGVzID0gbm9kZXMuY3koKS5oYXNDb21wb3VuZE5vZGVzKCk7XG5cbiAgICAgIGlmIChvcHRzLmluRHJhZ0xheWVyKSB7XG4gICAgICAgIG5vZGVzLmZvckVhY2goc2V0SW5EcmFnTGF5ZXIpO1xuICAgICAgICBub2Rlcy5uZWlnaGJvcmhvb2QoKS5zdGRGaWx0ZXIoZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICAgIHJldHVybiAhaGFzQ29tcG91bmROb2RlcyB8fCBlbGUuaXNFZGdlKCk7XG4gICAgICAgIH0pLmZvckVhY2goc2V0SW5EcmFnTGF5ZXIpO1xuICAgICAgfVxuXG4gICAgICBpZiAob3B0cy5hZGRUb0xpc3QpIHtcbiAgICAgICAgbm9kZXMuZm9yRWFjaChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgICAgYWRkVG9EcmFnTGlzdChlbGUsIG9wdHMpO1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgYWRkRGVzY2VuZGFudHNUb0RyYWcobm9kZXMsIG9wdHMpOyAvLyBhbHdheXMgYWRkIHRvIGRyYWdcbiAgICAgIC8vIGFsc28gYWRkIG5vZGVzIGFuZCBlZGdlcyByZWxhdGVkIHRvIHRoZSB0b3Btb3N0IGFuY2VzdG9yXG5cbiAgICAgIHVwZGF0ZUFuY2VzdG9yc0luRHJhZ0xheWVyKG5vZGVzLCB7XG4gICAgICAgIGluRHJhZ0xheWVyOiBvcHRzLmluRHJhZ0xheWVyXG4gICAgICB9KTtcbiAgICAgIHIudXBkYXRlQ2FjaGVkR3JhYmJlZEVsZXMoKTtcbiAgICB9O1xuXG4gICAgdmFyIGFkZE5vZGVUb0RyYWcgPSBhZGROb2Rlc1RvRHJhZztcblxuICAgIHZhciBmcmVlRHJhZ2dlZEVsZW1lbnRzID0gZnVuY3Rpb24gZnJlZURyYWdnZWRFbGVtZW50cyhncmFiYmVkRWxlcykge1xuICAgICAgaWYgKCFncmFiYmVkRWxlcykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIGp1c3QgZ28gb3ZlciBhbGwgZWxlbWVudHMgcmF0aGVyIHRoYW4gZG9pbmcgYSBidW5jaCBvZiAocG9zc2libHkgZXhwZW5zaXZlKSB0cmF2ZXJzYWxzXG5cblxuICAgICAgci5nZXRDYWNoZWRaU29ydGVkRWxlcygpLmZvckVhY2goZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICBzZXRGcmVlZChlbGUpO1xuICAgICAgICBzZXRPdXREcmFnTGF5ZXIoZWxlKTtcbiAgICAgICAgcmVtb3ZlR3JhYlRhcmdldChlbGUpO1xuICAgICAgfSk7XG4gICAgICByLnVwZGF0ZUNhY2hlZEdyYWJiZWRFbGVzKCk7XG4gICAgfTsgLy8gaGVscGVyIGZ1bmN0aW9uIHRvIGRldGVybWluZSB3aGljaCBhbmNlc3RvciBub2RlcyBhbmQgZWRnZXMgc2hvdWxkIGdvXG4gICAgLy8gdG8gdGhlIGRyYWcgbGF5ZXIgKG9yIHNob3VsZCBiZSByZW1vdmVkIGZyb20gZHJhZyBsYXllcikuXG5cblxuICAgIHZhciB1cGRhdGVBbmNlc3RvcnNJbkRyYWdMYXllciA9IGZ1bmN0aW9uIHVwZGF0ZUFuY2VzdG9yc0luRHJhZ0xheWVyKG5vZGUsIG9wdHMpIHtcbiAgICAgIGlmIChvcHRzLmluRHJhZ0xheWVyID09IG51bGwgJiYgb3B0cy5hZGRUb0xpc3QgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIG5vdGhpbmcgdG8gZG9cblxuXG4gICAgICBpZiAoIW5vZGUuY3koKS5oYXNDb21wb3VuZE5vZGVzKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBmaW5kIHRvcC1sZXZlbCBwYXJlbnRcblxuXG4gICAgICB2YXIgcGFyZW50ID0gbm9kZS5hbmNlc3RvcnMoKS5vcnBoYW5zKCk7IC8vIG5vIHBhcmVudCBub2RlOiBubyBub2RlcyB0byBhZGQgdG8gdGhlIGRyYWcgbGF5ZXJcblxuICAgICAgaWYgKHBhcmVudC5zYW1lKG5vZGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIG5vZGVzID0gcGFyZW50LmRlc2NlbmRhbnRzKCkuc3Bhd25TZWxmKCkubWVyZ2UocGFyZW50KS51bm1lcmdlKG5vZGUpLnVubWVyZ2Uobm9kZS5kZXNjZW5kYW50cygpKTtcbiAgICAgIHZhciBlZGdlcyA9IG5vZGVzLmNvbm5lY3RlZEVkZ2VzKCk7XG5cbiAgICAgIGlmIChvcHRzLmluRHJhZ0xheWVyKSB7XG4gICAgICAgIGVkZ2VzLmZvckVhY2goc2V0SW5EcmFnTGF5ZXIpO1xuICAgICAgICBub2Rlcy5mb3JFYWNoKHNldEluRHJhZ0xheWVyKTtcbiAgICAgIH1cblxuICAgICAgaWYgKG9wdHMuYWRkVG9MaXN0KSB7XG4gICAgICAgIG5vZGVzLmZvckVhY2goZnVuY3Rpb24gKGVsZSkge1xuICAgICAgICAgIGFkZFRvRHJhZ0xpc3QoZWxlLCBvcHRzKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHZhciBibHVyQWN0aXZlRG9tRWxlbWVudCA9IGZ1bmN0aW9uIGJsdXJBY3RpdmVEb21FbGVtZW50KCkge1xuICAgICAgaWYgKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgIT0gbnVsbCAmJiBkb2N1bWVudC5hY3RpdmVFbGVtZW50LmJsdXIgIT0gbnVsbCkge1xuICAgICAgICBkb2N1bWVudC5hY3RpdmVFbGVtZW50LmJsdXIoKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGhhdmVNdXRhdGlvbnNBcGkgPSB0eXBlb2YgTXV0YXRpb25PYnNlcnZlciAhPT0gJ3VuZGVmaW5lZCc7XG4gICAgdmFyIGhhdmVSZXNpemVPYnNlcnZlckFwaSA9IHR5cGVvZiBSZXNpemVPYnNlcnZlciAhPT0gJ3VuZGVmaW5lZCc7IC8vIHdhdGNoIGZvciB3aGVuIHRoZSBjeSBjb250YWluZXIgaXMgcmVtb3ZlZCBmcm9tIHRoZSBkb21cblxuICAgIGlmIChoYXZlTXV0YXRpb25zQXBpKSB7XG4gICAgICByLnJlbW92ZU9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoZnVuY3Rpb24gKG11dG5zKSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtdXRucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBtdXRuID0gbXV0bnNbaV07XG4gICAgICAgICAgdmFyIHJOb2RlcyA9IG11dG4ucmVtb3ZlZE5vZGVzO1xuXG4gICAgICAgICAgaWYgKHJOb2Rlcykge1xuICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCByTm9kZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgdmFyIHJOb2RlID0gck5vZGVzW2pdO1xuXG4gICAgICAgICAgICAgIGlmIChyTm9kZSA9PT0gci5jb250YWluZXIpIHtcbiAgICAgICAgICAgICAgICByLmRlc3Ryb3koKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIGlmIChyLmNvbnRhaW5lci5wYXJlbnROb2RlKSB7XG4gICAgICAgIHIucmVtb3ZlT2JzZXJ2ZXIub2JzZXJ2ZShyLmNvbnRhaW5lci5wYXJlbnROb2RlLCB7XG4gICAgICAgICAgY2hpbGRMaXN0OiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICByLnJlZ2lzdGVyQmluZGluZyhyLmNvbnRhaW5lciwgJ0RPTU5vZGVSZW1vdmVkJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICAgICAgICByLmRlc3Ryb3koKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHZhciBvblJlc2l6ZSA9IGRlYm91bmNlXzEoZnVuY3Rpb24gKCkge1xuICAgICAgci5jeS5yZXNpemUoKTtcbiAgICB9LCAxMDApO1xuXG4gICAgaWYgKGhhdmVNdXRhdGlvbnNBcGkpIHtcbiAgICAgIHIuc3R5bGVPYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKG9uUmVzaXplKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuXG4gICAgICByLnN0eWxlT2JzZXJ2ZXIub2JzZXJ2ZShyLmNvbnRhaW5lciwge1xuICAgICAgICBhdHRyaWJ1dGVzOiB0cnVlXG4gICAgICB9KTtcbiAgICB9IC8vIGF1dG8gcmVzaXplXG5cblxuICAgIHIucmVnaXN0ZXJCaW5kaW5nKGNvbnRhaW5lcldpbmRvdywgJ3Jlc2l6ZScsIG9uUmVzaXplKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuXG4gICAgaWYgKGhhdmVSZXNpemVPYnNlcnZlckFwaSkge1xuICAgICAgci5yZXNpemVPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcihvblJlc2l6ZSk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcblxuICAgICAgci5yZXNpemVPYnNlcnZlci5vYnNlcnZlKHIuY29udGFpbmVyKTtcbiAgICB9XG5cbiAgICB2YXIgZm9yRWFjaFVwID0gZnVuY3Rpb24gZm9yRWFjaFVwKGRvbUVsZSwgZm4pIHtcbiAgICAgIHdoaWxlIChkb21FbGUgIT0gbnVsbCkge1xuICAgICAgICBmbihkb21FbGUpO1xuICAgICAgICBkb21FbGUgPSBkb21FbGUucGFyZW50Tm9kZTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGludmFsaWRhdGVDb29yZHMgPSBmdW5jdGlvbiBpbnZhbGlkYXRlQ29vcmRzKCkge1xuICAgICAgci5pbnZhbGlkYXRlQ29udGFpbmVyQ2xpZW50Q29vcmRzQ2FjaGUoKTtcbiAgICB9O1xuXG4gICAgZm9yRWFjaFVwKHIuY29udGFpbmVyLCBmdW5jdGlvbiAoZG9tRWxlKSB7XG4gICAgICByLnJlZ2lzdGVyQmluZGluZyhkb21FbGUsICd0cmFuc2l0aW9uZW5kJywgaW52YWxpZGF0ZUNvb3Jkcyk7XG4gICAgICByLnJlZ2lzdGVyQmluZGluZyhkb21FbGUsICdhbmltYXRpb25lbmQnLCBpbnZhbGlkYXRlQ29vcmRzKTtcbiAgICAgIHIucmVnaXN0ZXJCaW5kaW5nKGRvbUVsZSwgJ3Njcm9sbCcsIGludmFsaWRhdGVDb29yZHMpO1xuICAgIH0pOyAvLyBzdG9wIHJpZ2h0IGNsaWNrIG1lbnUgZnJvbSBhcHBlYXJpbmcgb24gY3lcblxuICAgIHIucmVnaXN0ZXJCaW5kaW5nKHIuY29udGFpbmVyLCAnY29udGV4dG1lbnUnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH0pO1xuXG4gICAgdmFyIGluQm94U2VsZWN0aW9uID0gZnVuY3Rpb24gaW5Cb3hTZWxlY3Rpb24oKSB7XG4gICAgICByZXR1cm4gci5zZWxlY3Rpb25bNF0gIT09IDA7XG4gICAgfTtcblxuICAgIHZhciBldmVudEluQ29udGFpbmVyID0gZnVuY3Rpb24gZXZlbnRJbkNvbnRhaW5lcihlKSB7XG4gICAgICAvLyBzYXZlIGN5Y2xlcyBpZiBtb3VzZSBldmVudHMgYXJlbid0IHRvIGJlIGNhcHR1cmVkXG4gICAgICB2YXIgY29udGFpbmVyUGFnZUNvb3JkcyA9IHIuZmluZENvbnRhaW5lckNsaWVudENvb3JkcygpO1xuICAgICAgdmFyIHggPSBjb250YWluZXJQYWdlQ29vcmRzWzBdO1xuICAgICAgdmFyIHkgPSBjb250YWluZXJQYWdlQ29vcmRzWzFdO1xuICAgICAgdmFyIHdpZHRoID0gY29udGFpbmVyUGFnZUNvb3Jkc1syXTtcbiAgICAgIHZhciBoZWlnaHQgPSBjb250YWluZXJQYWdlQ29vcmRzWzNdO1xuICAgICAgdmFyIHBvc2l0aW9ucyA9IGUudG91Y2hlcyA/IGUudG91Y2hlcyA6IFtlXTtcbiAgICAgIHZhciBhdExlYXN0T25lUG9zSW5zaWRlID0gZmFsc2U7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9zaXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBwID0gcG9zaXRpb25zW2ldO1xuXG4gICAgICAgIGlmICh4IDw9IHAuY2xpZW50WCAmJiBwLmNsaWVudFggPD0geCArIHdpZHRoICYmIHkgPD0gcC5jbGllbnRZICYmIHAuY2xpZW50WSA8PSB5ICsgaGVpZ2h0KSB7XG4gICAgICAgICAgYXRMZWFzdE9uZVBvc0luc2lkZSA9IHRydWU7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKCFhdExlYXN0T25lUG9zSW5zaWRlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgdmFyIGNvbnRhaW5lciA9IHIuY29udGFpbmVyO1xuICAgICAgdmFyIHRhcmdldCA9IGUudGFyZ2V0O1xuICAgICAgdmFyIHRQYXJlbnQgPSB0YXJnZXQucGFyZW50Tm9kZTtcbiAgICAgIHZhciBjb250YWluZXJJc1RhcmdldCA9IGZhbHNlO1xuXG4gICAgICB3aGlsZSAodFBhcmVudCkge1xuICAgICAgICBpZiAodFBhcmVudCA9PT0gY29udGFpbmVyKSB7XG4gICAgICAgICAgY29udGFpbmVySXNUYXJnZXQgPSB0cnVlO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgdFBhcmVudCA9IHRQYXJlbnQucGFyZW50Tm9kZTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFjb250YWluZXJJc1RhcmdldCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9IC8vIGlmIHRhcmdldCBpcyBvdXRpc2RlIGN5IGNvbnRhaW5lciwgdGhlbiB0aGlzIGV2ZW50IGlzIG5vdCBmb3IgdXNcblxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9OyAvLyBQcmltYXJ5IGtleVxuXG5cbiAgICByLnJlZ2lzdGVyQmluZGluZyhyLmNvbnRhaW5lciwgJ21vdXNlZG93bicsIGZ1bmN0aW9uIG1vdXNlZG93bkhhbmRsZXIoZSkge1xuICAgICAgaWYgKCFldmVudEluQ29udGFpbmVyKGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgYmx1ckFjdGl2ZURvbUVsZW1lbnQoKTtcbiAgICAgIHIuaG92ZXJEYXRhLmNhcHR1cmUgPSB0cnVlO1xuICAgICAgci5ob3ZlckRhdGEud2hpY2ggPSBlLndoaWNoO1xuICAgICAgdmFyIGN5ID0gci5jeTtcbiAgICAgIHZhciBncG9zID0gW2UuY2xpZW50WCwgZS5jbGllbnRZXTtcbiAgICAgIHZhciBwb3MgPSByLnByb2plY3RJbnRvVmlld3BvcnQoZ3Bvc1swXSwgZ3Bvc1sxXSk7XG4gICAgICB2YXIgc2VsZWN0ID0gci5zZWxlY3Rpb247XG4gICAgICB2YXIgbmVhcnMgPSByLmZpbmROZWFyZXN0RWxlbWVudHMocG9zWzBdLCBwb3NbMV0sIHRydWUsIGZhbHNlKTtcbiAgICAgIHZhciBuZWFyID0gbmVhcnNbMF07XG4gICAgICB2YXIgZHJhZ2dlZEVsZW1lbnRzID0gci5kcmFnRGF0YS5wb3NzaWJsZURyYWdFbGVtZW50cztcbiAgICAgIHIuaG92ZXJEYXRhLm1kb3duUG9zID0gcG9zO1xuICAgICAgci5ob3ZlckRhdGEubWRvd25HUG9zID0gZ3BvcztcblxuICAgICAgdmFyIGNoZWNrRm9yVGFwaG9sZCA9IGZ1bmN0aW9uIGNoZWNrRm9yVGFwaG9sZCgpIHtcbiAgICAgICAgci5ob3ZlckRhdGEudGFwaG9sZENhbmNlbGxlZCA9IGZhbHNlO1xuICAgICAgICBjbGVhclRpbWVvdXQoci5ob3ZlckRhdGEudGFwaG9sZFRpbWVvdXQpO1xuICAgICAgICByLmhvdmVyRGF0YS50YXBob2xkVGltZW91dCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGlmIChyLmhvdmVyRGF0YS50YXBob2xkQ2FuY2VsbGVkKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHZhciBlbGUgPSByLmhvdmVyRGF0YS5kb3duO1xuXG4gICAgICAgICAgICBpZiAoZWxlKSB7XG4gICAgICAgICAgICAgIGVsZS5lbWl0KHtcbiAgICAgICAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgICAgICAgIHR5cGU6ICd0YXBob2xkJyxcbiAgICAgICAgICAgICAgICBwb3NpdGlvbjoge1xuICAgICAgICAgICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgICAgICAgICAgeTogcG9zWzFdXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGN5LmVtaXQoe1xuICAgICAgICAgICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgICAgICAgICAgdHlwZTogJ3RhcGhvbGQnLFxuICAgICAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgICAgICB4OiBwb3NbMF0sXG4gICAgICAgICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSwgci50YXBob2xkRHVyYXRpb24pO1xuICAgICAgfTsgLy8gUmlnaHQgY2xpY2sgYnV0dG9uXG5cblxuICAgICAgaWYgKGUud2hpY2ggPT0gMykge1xuICAgICAgICByLmhvdmVyRGF0YS5jeHRTdGFydGVkID0gdHJ1ZTtcbiAgICAgICAgdmFyIGN4dEV2dCA9IHtcbiAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgIHR5cGU6ICdjeHR0YXBzdGFydCcsXG4gICAgICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgICAgIHg6IHBvc1swXSxcbiAgICAgICAgICAgIHk6IHBvc1sxXVxuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBpZiAobmVhcikge1xuICAgICAgICAgIG5lYXIuYWN0aXZhdGUoKTtcbiAgICAgICAgICBuZWFyLmVtaXQoY3h0RXZ0KTtcbiAgICAgICAgICByLmhvdmVyRGF0YS5kb3duID0gbmVhcjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjeS5lbWl0KGN4dEV2dCk7XG4gICAgICAgIH1cblxuICAgICAgICByLmhvdmVyRGF0YS5kb3duVGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgICAgICByLmhvdmVyRGF0YS5jeHREcmFnZ2VkID0gZmFsc2U7IC8vIFByaW1hcnkgYnV0dG9uXG4gICAgICB9IGVsc2UgaWYgKGUud2hpY2ggPT0gMSkge1xuICAgICAgICBpZiAobmVhcikge1xuICAgICAgICAgIG5lYXIuYWN0aXZhdGUoKTtcbiAgICAgICAgfSAvLyBFbGVtZW50IGRyYWdnaW5nXG5cblxuICAgICAgICB7XG4gICAgICAgICAgLy8gSWYgc29tZXRoaW5nIGlzIHVuZGVyIHRoZSBjdXJzb3IgYW5kIGl0IGlzIGRyYWdnYWJsZSwgcHJlcGFyZSB0byBncmFiIGl0XG4gICAgICAgICAgaWYgKG5lYXIgIT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKHIubm9kZUlzR3JhYmJhYmxlKG5lYXIpKSB7XG4gICAgICAgICAgICAgIHZhciBtYWtlRXZlbnQgPSBmdW5jdGlvbiBtYWtlRXZlbnQodHlwZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgICAgICAgICAgdHlwZTogdHlwZSxcbiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgICAgICAgIHg6IHBvc1swXSxcbiAgICAgICAgICAgICAgICAgICAgeTogcG9zWzFdXG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICB2YXIgdHJpZ2dlckdyYWIgPSBmdW5jdGlvbiB0cmlnZ2VyR3JhYihlbGUpIHtcbiAgICAgICAgICAgICAgICBlbGUuZW1pdChtYWtlRXZlbnQoJ2dyYWInKSk7XG4gICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgc2V0R3JhYlRhcmdldChuZWFyKTtcblxuICAgICAgICAgICAgICBpZiAoIW5lYXIuc2VsZWN0ZWQoKSkge1xuICAgICAgICAgICAgICAgIGRyYWdnZWRFbGVtZW50cyA9IHIuZHJhZ0RhdGEucG9zc2libGVEcmFnRWxlbWVudHMgPSBjeS5jb2xsZWN0aW9uKCk7XG4gICAgICAgICAgICAgICAgYWRkTm9kZVRvRHJhZyhuZWFyLCB7XG4gICAgICAgICAgICAgICAgICBhZGRUb0xpc3Q6IGRyYWdnZWRFbGVtZW50c1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIG5lYXIuZW1pdChtYWtlRXZlbnQoJ2dyYWJvbicpKS5lbWl0KG1ha2VFdmVudCgnZ3JhYicpKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkcmFnZ2VkRWxlbWVudHMgPSByLmRyYWdEYXRhLnBvc3NpYmxlRHJhZ0VsZW1lbnRzID0gY3kuY29sbGVjdGlvbigpO1xuICAgICAgICAgICAgICAgIHZhciBzZWxlY3RlZE5vZGVzID0gY3kuJChmdW5jdGlvbiAoZWxlKSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gZWxlLmlzTm9kZSgpICYmIGVsZS5zZWxlY3RlZCgpICYmIHIubm9kZUlzR3JhYmJhYmxlKGVsZSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgYWRkTm9kZXNUb0RyYWcoc2VsZWN0ZWROb2Rlcywge1xuICAgICAgICAgICAgICAgICAgYWRkVG9MaXN0OiBkcmFnZ2VkRWxlbWVudHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBuZWFyLmVtaXQobWFrZUV2ZW50KCdncmFib24nKSk7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWROb2Rlcy5mb3JFYWNoKHRyaWdnZXJHcmFiKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHIucmVkcmF3SGludCgnZWxlcycsIHRydWUpO1xuICAgICAgICAgICAgICByLnJlZHJhd0hpbnQoJ2RyYWcnLCB0cnVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICByLmhvdmVyRGF0YS5kb3duID0gbmVhcjtcbiAgICAgICAgICByLmhvdmVyRGF0YS5kb3ducyA9IG5lYXJzO1xuICAgICAgICAgIHIuaG92ZXJEYXRhLmRvd25UaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgICAgIH1cbiAgICAgICAgdHJpZ2dlckV2ZW50cyhuZWFyLCBbJ21vdXNlZG93bicsICd0YXBzdGFydCcsICd2bW91c2Vkb3duJ10sIGUsIHtcbiAgICAgICAgICB4OiBwb3NbMF0sXG4gICAgICAgICAgeTogcG9zWzFdXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChuZWFyID09IG51bGwpIHtcbiAgICAgICAgICBzZWxlY3RbNF0gPSAxO1xuICAgICAgICAgIHIuZGF0YS5iZ0FjdGl2ZVBvc2lzdGlvbiA9IHtcbiAgICAgICAgICAgIHg6IHBvc1swXSxcbiAgICAgICAgICAgIHk6IHBvc1sxXVxuICAgICAgICAgIH07XG4gICAgICAgICAgci5yZWRyYXdIaW50KCdzZWxlY3QnLCB0cnVlKTtcbiAgICAgICAgICByLnJlZHJhdygpO1xuICAgICAgICB9IGVsc2UgaWYgKG5lYXIucGFubmFibGUoKSkge1xuICAgICAgICAgIHNlbGVjdFs0XSA9IDE7IC8vIGZvciBmdXR1cmUgcGFuXG4gICAgICAgIH1cblxuICAgICAgICBjaGVja0ZvclRhcGhvbGQoKTtcbiAgICAgIH0gLy8gSW5pdGlhbGl6ZSBzZWxlY3Rpb24gYm94IGNvb3JkaW5hdGVzXG5cblxuICAgICAgc2VsZWN0WzBdID0gc2VsZWN0WzJdID0gcG9zWzBdO1xuICAgICAgc2VsZWN0WzFdID0gc2VsZWN0WzNdID0gcG9zWzFdO1xuICAgIH0sIGZhbHNlKTtcbiAgICByLnJlZ2lzdGVyQmluZGluZyhjb250YWluZXJXaW5kb3csICdtb3VzZW1vdmUnLCBmdW5jdGlvbiBtb3VzZW1vdmVIYW5kbGVyKGUpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbiAgICAgIHZhciBjYXB0dXJlID0gci5ob3ZlckRhdGEuY2FwdHVyZTtcblxuICAgICAgaWYgKCFjYXB0dXJlICYmICFldmVudEluQ29udGFpbmVyKGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIHByZXZlbnREZWZhdWx0ID0gZmFsc2U7XG4gICAgICB2YXIgY3kgPSByLmN5O1xuICAgICAgdmFyIHpvb20gPSBjeS56b29tKCk7XG4gICAgICB2YXIgZ3BvcyA9IFtlLmNsaWVudFgsIGUuY2xpZW50WV07XG4gICAgICB2YXIgcG9zID0gci5wcm9qZWN0SW50b1ZpZXdwb3J0KGdwb3NbMF0sIGdwb3NbMV0pO1xuICAgICAgdmFyIG1kb3duUG9zID0gci5ob3ZlckRhdGEubWRvd25Qb3M7XG4gICAgICB2YXIgbWRvd25HUG9zID0gci5ob3ZlckRhdGEubWRvd25HUG9zO1xuICAgICAgdmFyIHNlbGVjdCA9IHIuc2VsZWN0aW9uO1xuICAgICAgdmFyIG5lYXIgPSBudWxsO1xuXG4gICAgICBpZiAoIXIuaG92ZXJEYXRhLmRyYWdnaW5nRWxlcyAmJiAhci5ob3ZlckRhdGEuZHJhZ2dpbmcgJiYgIXIuaG92ZXJEYXRhLnNlbGVjdGluZykge1xuICAgICAgICBuZWFyID0gci5maW5kTmVhcmVzdEVsZW1lbnQocG9zWzBdLCBwb3NbMV0sIHRydWUsIGZhbHNlKTtcbiAgICAgIH1cblxuICAgICAgdmFyIGxhc3QgPSByLmhvdmVyRGF0YS5sYXN0O1xuICAgICAgdmFyIGRvd24gPSByLmhvdmVyRGF0YS5kb3duO1xuICAgICAgdmFyIGRpc3AgPSBbcG9zWzBdIC0gc2VsZWN0WzJdLCBwb3NbMV0gLSBzZWxlY3RbM11dO1xuICAgICAgdmFyIGRyYWdnZWRFbGVtZW50cyA9IHIuZHJhZ0RhdGEucG9zc2libGVEcmFnRWxlbWVudHM7XG4gICAgICB2YXIgaXNPdmVyVGhyZXNob2xkRHJhZztcblxuICAgICAgaWYgKG1kb3duR1Bvcykge1xuICAgICAgICB2YXIgZHggPSBncG9zWzBdIC0gbWRvd25HUG9zWzBdO1xuICAgICAgICB2YXIgZHgyID0gZHggKiBkeDtcbiAgICAgICAgdmFyIGR5ID0gZ3Bvc1sxXSAtIG1kb3duR1Bvc1sxXTtcbiAgICAgICAgdmFyIGR5MiA9IGR5ICogZHk7XG4gICAgICAgIHZhciBkaXN0MiA9IGR4MiArIGR5MjtcbiAgICAgICAgci5ob3ZlckRhdGEuaXNPdmVyVGhyZXNob2xkRHJhZyA9IGlzT3ZlclRocmVzaG9sZERyYWcgPSBkaXN0MiA+PSByLmRlc2t0b3BUYXBUaHJlc2hvbGQyO1xuICAgICAgfVxuXG4gICAgICB2YXIgbXVsdFNlbEtleURvd24gPSBpc011bHRTZWxLZXlEb3duKGUpO1xuXG4gICAgICBpZiAoaXNPdmVyVGhyZXNob2xkRHJhZykge1xuICAgICAgICByLmhvdmVyRGF0YS50YXBob2xkQ2FuY2VsbGVkID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgdmFyIHVwZGF0ZURyYWdEZWx0YSA9IGZ1bmN0aW9uIHVwZGF0ZURyYWdEZWx0YSgpIHtcbiAgICAgICAgdmFyIGRyYWdEZWx0YSA9IHIuaG92ZXJEYXRhLmRyYWdEZWx0YSA9IHIuaG92ZXJEYXRhLmRyYWdEZWx0YSB8fCBbXTtcblxuICAgICAgICBpZiAoZHJhZ0RlbHRhLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIGRyYWdEZWx0YS5wdXNoKGRpc3BbMF0pO1xuICAgICAgICAgIGRyYWdEZWx0YS5wdXNoKGRpc3BbMV0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGRyYWdEZWx0YVswXSArPSBkaXNwWzBdO1xuICAgICAgICAgIGRyYWdEZWx0YVsxXSArPSBkaXNwWzFdO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICBwcmV2ZW50RGVmYXVsdCA9IHRydWU7XG4gICAgICB0cmlnZ2VyRXZlbnRzKG5lYXIsIFsnbW91c2Vtb3ZlJywgJ3Ztb3VzZW1vdmUnLCAndGFwZHJhZyddLCBlLCB7XG4gICAgICAgIHg6IHBvc1swXSxcbiAgICAgICAgeTogcG9zWzFdXG4gICAgICB9KTtcblxuICAgICAgdmFyIGdvSW50b0JveE1vZGUgPSBmdW5jdGlvbiBnb0ludG9Cb3hNb2RlKCkge1xuICAgICAgICByLmRhdGEuYmdBY3RpdmVQb3Npc3Rpb24gPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgaWYgKCFyLmhvdmVyRGF0YS5zZWxlY3RpbmcpIHtcbiAgICAgICAgICBjeS5lbWl0KHtcbiAgICAgICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgICAgICB0eXBlOiAnYm94c3RhcnQnLFxuICAgICAgICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNlbGVjdFs0XSA9IDE7XG4gICAgICAgIHIuaG92ZXJEYXRhLnNlbGVjdGluZyA9IHRydWU7XG4gICAgICAgIHIucmVkcmF3SGludCgnc2VsZWN0JywgdHJ1ZSk7XG4gICAgICAgIHIucmVkcmF3KCk7XG4gICAgICB9OyAvLyB0cmlnZ2VyIGNvbnRleHQgZHJhZyBpZiBybW91c2UgZG93blxuXG5cbiAgICAgIGlmIChyLmhvdmVyRGF0YS53aGljaCA9PT0gMykge1xuICAgICAgICAvLyBidXQgb25seSBpZiBvdmVyIHRocmVzaG9sZFxuICAgICAgICBpZiAoaXNPdmVyVGhyZXNob2xkRHJhZykge1xuICAgICAgICAgIHZhciBjeHRFdnQgPSB7XG4gICAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgICAgdHlwZTogJ2N4dGRyYWcnLFxuICAgICAgICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgaWYgKGRvd24pIHtcbiAgICAgICAgICAgIGRvd24uZW1pdChjeHRFdnQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjeS5lbWl0KGN4dEV2dCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgci5ob3ZlckRhdGEuY3h0RHJhZ2dlZCA9IHRydWU7XG5cbiAgICAgICAgICBpZiAoIXIuaG92ZXJEYXRhLmN4dE92ZXIgfHwgbmVhciAhPT0gci5ob3ZlckRhdGEuY3h0T3Zlcikge1xuICAgICAgICAgICAgaWYgKHIuaG92ZXJEYXRhLmN4dE92ZXIpIHtcbiAgICAgICAgICAgICAgci5ob3ZlckRhdGEuY3h0T3Zlci5lbWl0KHtcbiAgICAgICAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgICAgICAgIHR5cGU6ICdjeHRkcmFnb3V0JyxcbiAgICAgICAgICAgICAgICBwb3NpdGlvbjoge1xuICAgICAgICAgICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgICAgICAgICAgeTogcG9zWzFdXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgci5ob3ZlckRhdGEuY3h0T3ZlciA9IG5lYXI7XG5cbiAgICAgICAgICAgIGlmIChuZWFyKSB7XG4gICAgICAgICAgICAgIG5lYXIuZW1pdCh7XG4gICAgICAgICAgICAgICAgb3JpZ2luYWxFdmVudDogZSxcbiAgICAgICAgICAgICAgICB0eXBlOiAnY3h0ZHJhZ292ZXInLFxuICAgICAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgICAgICB4OiBwb3NbMF0sXG4gICAgICAgICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSAvLyBDaGVjayBpZiB3ZSBhcmUgZHJhZyBwYW5uaW5nIHRoZSBlbnRpcmUgZ3JhcGhcblxuICAgICAgfSBlbHNlIGlmIChyLmhvdmVyRGF0YS5kcmFnZ2luZykge1xuICAgICAgICBwcmV2ZW50RGVmYXVsdCA9IHRydWU7XG5cbiAgICAgICAgaWYgKGN5LnBhbm5pbmdFbmFibGVkKCkgJiYgY3kudXNlclBhbm5pbmdFbmFibGVkKCkpIHtcbiAgICAgICAgICB2YXIgZGVsdGFQO1xuXG4gICAgICAgICAgaWYgKHIuaG92ZXJEYXRhLmp1c3RTdGFydGVkUGFuKSB7XG4gICAgICAgICAgICB2YXIgbWRQb3MgPSByLmhvdmVyRGF0YS5tZG93blBvcztcbiAgICAgICAgICAgIGRlbHRhUCA9IHtcbiAgICAgICAgICAgICAgeDogKHBvc1swXSAtIG1kUG9zWzBdKSAqIHpvb20sXG4gICAgICAgICAgICAgIHk6IChwb3NbMV0gLSBtZFBvc1sxXSkgKiB6b29tXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgci5ob3ZlckRhdGEuanVzdFN0YXJ0ZWRQYW4gPSBmYWxzZTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZGVsdGFQID0ge1xuICAgICAgICAgICAgICB4OiBkaXNwWzBdICogem9vbSxcbiAgICAgICAgICAgICAgeTogZGlzcFsxXSAqIHpvb21cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY3kucGFuQnkoZGVsdGFQKTtcbiAgICAgICAgICBjeS5lbWl0KCdkcmFncGFuJyk7XG4gICAgICAgICAgci5ob3ZlckRhdGEuZHJhZ2dlZCA9IHRydWU7XG4gICAgICAgIH0gLy8gTmVlZHMgcmVwcm9qZWN0IGR1ZSB0byBwYW4gY2hhbmdpbmcgdmlld3BvcnRcblxuXG4gICAgICAgIHBvcyA9IHIucHJvamVjdEludG9WaWV3cG9ydChlLmNsaWVudFgsIGUuY2xpZW50WSk7IC8vIENoZWNrcyBwcmltYXJ5IGJ1dHRvbiBkb3duICYgb3V0IG9mIHRpbWUgJiBtb3VzZSBub3QgbW92ZWQgbXVjaFxuICAgICAgfSBlbHNlIGlmIChzZWxlY3RbNF0gPT0gMSAmJiAoZG93biA9PSBudWxsIHx8IGRvd24ucGFubmFibGUoKSkpIHtcbiAgICAgICAgaWYgKGlzT3ZlclRocmVzaG9sZERyYWcpIHtcbiAgICAgICAgICBpZiAoIXIuaG92ZXJEYXRhLmRyYWdnaW5nICYmIGN5LmJveFNlbGVjdGlvbkVuYWJsZWQoKSAmJiAobXVsdFNlbEtleURvd24gfHwgIWN5LnBhbm5pbmdFbmFibGVkKCkgfHwgIWN5LnVzZXJQYW5uaW5nRW5hYmxlZCgpKSkge1xuICAgICAgICAgICAgZ29JbnRvQm94TW9kZSgpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoIXIuaG92ZXJEYXRhLnNlbGVjdGluZyAmJiBjeS5wYW5uaW5nRW5hYmxlZCgpICYmIGN5LnVzZXJQYW5uaW5nRW5hYmxlZCgpKSB7XG4gICAgICAgICAgICB2YXIgYWxsb3dQYXNzdGhyb3VnaCA9IGFsbG93UGFubmluZ1Bhc3N0aHJvdWdoKGRvd24sIHIuaG92ZXJEYXRhLmRvd25zKTtcblxuICAgICAgICAgICAgaWYgKGFsbG93UGFzc3Rocm91Z2gpIHtcbiAgICAgICAgICAgICAgci5ob3ZlckRhdGEuZHJhZ2dpbmcgPSB0cnVlO1xuICAgICAgICAgICAgICByLmhvdmVyRGF0YS5qdXN0U3RhcnRlZFBhbiA9IHRydWU7XG4gICAgICAgICAgICAgIHNlbGVjdFs0XSA9IDA7XG4gICAgICAgICAgICAgIHIuZGF0YS5iZ0FjdGl2ZVBvc2lzdGlvbiA9IGFycmF5MnBvaW50KG1kb3duUG9zKTtcbiAgICAgICAgICAgICAgci5yZWRyYXdIaW50KCdzZWxlY3QnLCB0cnVlKTtcbiAgICAgICAgICAgICAgci5yZWRyYXcoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoZG93biAmJiBkb3duLnBhbm5hYmxlKCkgJiYgZG93bi5hY3RpdmUoKSkge1xuICAgICAgICAgICAgZG93bi51bmFjdGl2YXRlKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoZG93biAmJiBkb3duLnBhbm5hYmxlKCkgJiYgZG93bi5hY3RpdmUoKSkge1xuICAgICAgICAgIGRvd24udW5hY3RpdmF0ZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCghZG93biB8fCAhZG93bi5ncmFiYmVkKCkpICYmIG5lYXIgIT0gbGFzdCkge1xuICAgICAgICAgIGlmIChsYXN0KSB7XG4gICAgICAgICAgICB0cmlnZ2VyRXZlbnRzKGxhc3QsIFsnbW91c2VvdXQnLCAndGFwZHJhZ291dCddLCBlLCB7XG4gICAgICAgICAgICAgIHg6IHBvc1swXSxcbiAgICAgICAgICAgICAgeTogcG9zWzFdXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAobmVhcikge1xuICAgICAgICAgICAgdHJpZ2dlckV2ZW50cyhuZWFyLCBbJ21vdXNlb3ZlcicsICd0YXBkcmFnb3ZlciddLCBlLCB7XG4gICAgICAgICAgICAgIHg6IHBvc1swXSxcbiAgICAgICAgICAgICAgeTogcG9zWzFdXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByLmhvdmVyRGF0YS5sYXN0ID0gbmVhcjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChkb3duKSB7XG4gICAgICAgICAgaWYgKGlzT3ZlclRocmVzaG9sZERyYWcpIHtcbiAgICAgICAgICAgIC8vIHRoZW4gd2UgY2FuIHRha2UgYWN0aW9uXG4gICAgICAgICAgICBpZiAoY3kuYm94U2VsZWN0aW9uRW5hYmxlZCgpICYmIG11bHRTZWxLZXlEb3duKSB7XG4gICAgICAgICAgICAgIC8vIHRoZW4gc2VsZWN0aW9uIG92ZXJyaWRlc1xuICAgICAgICAgICAgICBpZiAoZG93biAmJiBkb3duLmdyYWJiZWQoKSkge1xuICAgICAgICAgICAgICAgIGZyZWVEcmFnZ2VkRWxlbWVudHMoZHJhZ2dlZEVsZW1lbnRzKTtcbiAgICAgICAgICAgICAgICBkb3duLmVtaXQoJ2ZyZWVvbicpO1xuICAgICAgICAgICAgICAgIGRyYWdnZWRFbGVtZW50cy5lbWl0KCdmcmVlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAoci5kcmFnRGF0YS5kaWREcmFnKSB7XG4gICAgICAgICAgICAgICAgICBkb3duLmVtaXQoJ2RyYWdmcmVlb24nKTtcbiAgICAgICAgICAgICAgICAgIGRyYWdnZWRFbGVtZW50cy5lbWl0KCdkcmFnZnJlZScpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGdvSW50b0JveE1vZGUoKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoZG93biAmJiBkb3duLmdyYWJiZWQoKSAmJiByLm5vZGVJc0RyYWdnYWJsZShkb3duKSkge1xuICAgICAgICAgICAgICAvLyBkcmFnIG5vZGVcbiAgICAgICAgICAgICAgdmFyIGp1c3RTdGFydGVkRHJhZyA9ICFyLmRyYWdEYXRhLmRpZERyYWc7XG5cbiAgICAgICAgICAgICAgaWYgKGp1c3RTdGFydGVkRHJhZykge1xuICAgICAgICAgICAgICAgIHIucmVkcmF3SGludCgnZWxlcycsIHRydWUpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgci5kcmFnRGF0YS5kaWREcmFnID0gdHJ1ZTsgLy8gaW5kaWNhdGUgdGhhdCB3ZSBhY3R1YWxseSBkaWQgZHJhZyB0aGUgbm9kZVxuICAgICAgICAgICAgICAvLyBub3csIGFkZCB0aGUgZWxlbWVudHMgdG8gdGhlIGRyYWcgbGF5ZXIgaWYgbm90IGRvbmUgYWxyZWFkeVxuXG4gICAgICAgICAgICAgIGlmICghci5ob3ZlckRhdGEuZHJhZ2dpbmdFbGVzKSB7XG4gICAgICAgICAgICAgICAgYWRkTm9kZXNUb0RyYWcoZHJhZ2dlZEVsZW1lbnRzLCB7XG4gICAgICAgICAgICAgICAgICBpbkRyYWdMYXllcjogdHJ1ZVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgdmFyIHRvdGFsU2hpZnQgPSB7XG4gICAgICAgICAgICAgICAgeDogMCxcbiAgICAgICAgICAgICAgICB5OiAwXG4gICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgaWYgKG51bWJlciQxKGRpc3BbMF0pICYmIG51bWJlciQxKGRpc3BbMV0pKSB7XG4gICAgICAgICAgICAgICAgdG90YWxTaGlmdC54ICs9IGRpc3BbMF07XG4gICAgICAgICAgICAgICAgdG90YWxTaGlmdC55ICs9IGRpc3BbMV07XG5cbiAgICAgICAgICAgICAgICBpZiAoanVzdFN0YXJ0ZWREcmFnKSB7XG4gICAgICAgICAgICAgICAgICB2YXIgZHJhZ0RlbHRhID0gci5ob3ZlckRhdGEuZHJhZ0RlbHRhO1xuXG4gICAgICAgICAgICAgICAgICBpZiAoZHJhZ0RlbHRhICYmIG51bWJlciQxKGRyYWdEZWx0YVswXSkgJiYgbnVtYmVyJDEoZHJhZ0RlbHRhWzFdKSkge1xuICAgICAgICAgICAgICAgICAgICB0b3RhbFNoaWZ0LnggKz0gZHJhZ0RlbHRhWzBdO1xuICAgICAgICAgICAgICAgICAgICB0b3RhbFNoaWZ0LnkgKz0gZHJhZ0RlbHRhWzFdO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHIuaG92ZXJEYXRhLmRyYWdnaW5nRWxlcyA9IHRydWU7XG4gICAgICAgICAgICAgIGRyYWdnZWRFbGVtZW50cy5zaWxlbnRTaGlmdCh0b3RhbFNoaWZ0KS5lbWl0KCdwb3NpdGlvbiBkcmFnJyk7XG4gICAgICAgICAgICAgIHIucmVkcmF3SGludCgnZHJhZycsIHRydWUpO1xuICAgICAgICAgICAgICByLnJlZHJhdygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBvdGhlcndpc2Ugc2F2ZSBkcmFnIGRlbHRhIGZvciB3aGVuIHdlIGFjdHVhbGx5IHN0YXJ0IGRyYWdnaW5nIHNvIHRoZSByZWxhdGl2ZSBncmFiIHBvcyBpcyBjb25zdGFudFxuICAgICAgICAgICAgdXBkYXRlRHJhZ0RlbHRhKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IC8vIHByZXZlbnQgdGhlIGRyYWdnaW5nIGZyb20gdHJpZ2dlcmluZyB0ZXh0IHNlbGVjdGlvbiBvbiB0aGUgcGFnZVxuXG5cbiAgICAgICAgcHJldmVudERlZmF1bHQgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICBzZWxlY3RbMl0gPSBwb3NbMF07XG4gICAgICBzZWxlY3RbM10gPSBwb3NbMV07XG5cbiAgICAgIGlmIChwcmV2ZW50RGVmYXVsdCkge1xuICAgICAgICBpZiAoZS5zdG9wUHJvcGFnYXRpb24pIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIGlmIChlLnByZXZlbnREZWZhdWx0KSBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9LCBmYWxzZSk7XG4gICAgdmFyIGNsaWNrVGltZW91dCwgZGlkRG91YmxlQ2xpY2ssIHByZXZDbGlja1RpbWVTdGFtcDtcbiAgICByLnJlZ2lzdGVyQmluZGluZyhjb250YWluZXJXaW5kb3csICdtb3VzZXVwJywgZnVuY3Rpb24gbW91c2V1cEhhbmRsZXIoZSkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuICAgICAgdmFyIGNhcHR1cmUgPSByLmhvdmVyRGF0YS5jYXB0dXJlO1xuXG4gICAgICBpZiAoIWNhcHR1cmUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICByLmhvdmVyRGF0YS5jYXB0dXJlID0gZmFsc2U7XG4gICAgICB2YXIgY3kgPSByLmN5O1xuICAgICAgdmFyIHBvcyA9IHIucHJvamVjdEludG9WaWV3cG9ydChlLmNsaWVudFgsIGUuY2xpZW50WSk7XG4gICAgICB2YXIgc2VsZWN0ID0gci5zZWxlY3Rpb247XG4gICAgICB2YXIgbmVhciA9IHIuZmluZE5lYXJlc3RFbGVtZW50KHBvc1swXSwgcG9zWzFdLCB0cnVlLCBmYWxzZSk7XG4gICAgICB2YXIgZHJhZ2dlZEVsZW1lbnRzID0gci5kcmFnRGF0YS5wb3NzaWJsZURyYWdFbGVtZW50cztcbiAgICAgIHZhciBkb3duID0gci5ob3ZlckRhdGEuZG93bjtcbiAgICAgIHZhciBtdWx0U2VsS2V5RG93biA9IGlzTXVsdFNlbEtleURvd24oZSk7XG5cbiAgICAgIGlmIChyLmRhdGEuYmdBY3RpdmVQb3Npc3Rpb24pIHtcbiAgICAgICAgci5yZWRyYXdIaW50KCdzZWxlY3QnLCB0cnVlKTtcbiAgICAgICAgci5yZWRyYXcoKTtcbiAgICAgIH1cblxuICAgICAgci5ob3ZlckRhdGEudGFwaG9sZENhbmNlbGxlZCA9IHRydWU7XG4gICAgICByLmRhdGEuYmdBY3RpdmVQb3Npc3Rpb24gPSB1bmRlZmluZWQ7IC8vIG5vdCBhY3RpdmUgYmcgbm93XG5cbiAgICAgIGlmIChkb3duKSB7XG4gICAgICAgIGRvd24udW5hY3RpdmF0ZSgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoci5ob3ZlckRhdGEud2hpY2ggPT09IDMpIHtcbiAgICAgICAgdmFyIGN4dEV2dCA9IHtcbiAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgIHR5cGU6ICdjeHR0YXBlbmQnLFxuICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICB4OiBwb3NbMF0sXG4gICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKGRvd24pIHtcbiAgICAgICAgICBkb3duLmVtaXQoY3h0RXZ0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjeS5lbWl0KGN4dEV2dCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXIuaG92ZXJEYXRhLmN4dERyYWdnZWQpIHtcbiAgICAgICAgICB2YXIgY3h0VGFwID0ge1xuICAgICAgICAgICAgb3JpZ2luYWxFdmVudDogZSxcbiAgICAgICAgICAgIHR5cGU6ICdjeHR0YXAnLFxuICAgICAgICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgaWYgKGRvd24pIHtcbiAgICAgICAgICAgIGRvd24uZW1pdChjeHRUYXApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjeS5lbWl0KGN4dFRhcCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgci5ob3ZlckRhdGEuY3h0RHJhZ2dlZCA9IGZhbHNlO1xuICAgICAgICByLmhvdmVyRGF0YS53aGljaCA9IG51bGw7XG4gICAgICB9IGVsc2UgaWYgKHIuaG92ZXJEYXRhLndoaWNoID09PSAxKSB7XG4gICAgICAgIHRyaWdnZXJFdmVudHMobmVhciwgWydtb3VzZXVwJywgJ3RhcGVuZCcsICd2bW91c2V1cCddLCBlLCB7XG4gICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgIHk6IHBvc1sxXVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoIXIuZHJhZ0RhdGEuZGlkRHJhZyAmJiAvLyBkaWRuJ3QgbW92ZSBhIG5vZGUgYXJvdW5kXG4gICAgICAgICFyLmhvdmVyRGF0YS5kcmFnZ2VkICYmIC8vIGRpZG4ndCBwYW5cbiAgICAgICAgIXIuaG92ZXJEYXRhLnNlbGVjdGluZyAmJiAvLyBub3QgYm94IHNlbGVjdGlvblxuICAgICAgICAhci5ob3ZlckRhdGEuaXNPdmVyVGhyZXNob2xkRHJhZyAvLyBkaWRuJ3QgbW92ZSB0b28gbXVjaFxuICAgICAgICApIHtcbiAgICAgICAgICB0cmlnZ2VyRXZlbnRzKGRvd24sIFtcImNsaWNrXCIsIFwidGFwXCIsIFwidmNsaWNrXCJdLCBlLCB7XG4gICAgICAgICAgICB4OiBwb3NbMF0sXG4gICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICBkaWREb3VibGVDbGljayA9IGZhbHNlO1xuXG4gICAgICAgICAgaWYgKGUudGltZVN0YW1wIC0gcHJldkNsaWNrVGltZVN0YW1wIDw9IGN5Lm11bHRpQ2xpY2tEZWJvdW5jZVRpbWUoKSkge1xuICAgICAgICAgICAgY2xpY2tUaW1lb3V0ICYmIGNsZWFyVGltZW91dChjbGlja1RpbWVvdXQpO1xuICAgICAgICAgICAgZGlkRG91YmxlQ2xpY2sgPSB0cnVlO1xuICAgICAgICAgICAgcHJldkNsaWNrVGltZVN0YW1wID0gbnVsbDtcbiAgICAgICAgICAgIHRyaWdnZXJFdmVudHMoZG93biwgW1wiZGJsY2xpY2tcIiwgXCJkYmx0YXBcIiwgXCJ2ZGJsY2xpY2tcIl0sIGUsIHtcbiAgICAgICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjbGlja1RpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgaWYgKGRpZERvdWJsZUNsaWNrKSByZXR1cm47XG4gICAgICAgICAgICAgIHRyaWdnZXJFdmVudHMoZG93biwgW1wib25lY2xpY2tcIiwgXCJvbmV0YXBcIiwgXCJ2b25lY2xpY2tcIl0sIGUsIHtcbiAgICAgICAgICAgICAgICB4OiBwb3NbMF0sXG4gICAgICAgICAgICAgICAgeTogcG9zWzFdXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSwgY3kubXVsdGlDbGlja0RlYm91bmNlVGltZSgpKTtcbiAgICAgICAgICAgIHByZXZDbGlja1RpbWVTdGFtcCA9IGUudGltZVN0YW1wO1xuICAgICAgICAgIH1cbiAgICAgICAgfSAvLyBEZXNlbGVjdCBhbGwgZWxlbWVudHMgaWYgbm90aGluZyBpcyBjdXJyZW50bHkgdW5kZXIgdGhlIG1vdXNlIGN1cnNvciBhbmQgd2UgYXJlbid0IGRyYWdnaW5nIHNvbWV0aGluZ1xuXG5cbiAgICAgICAgaWYgKGRvd24gPT0gbnVsbCAvLyBub3QgbW91c2Vkb3duIG9uIG5vZGVcbiAgICAgICAgJiYgIXIuZHJhZ0RhdGEuZGlkRHJhZyAvLyBkaWRuJ3QgbW92ZSB0aGUgbm9kZSBhcm91bmRcbiAgICAgICAgJiYgIXIuaG92ZXJEYXRhLnNlbGVjdGluZyAvLyBub3QgYm94IHNlbGVjdGlvblxuICAgICAgICAmJiAhci5ob3ZlckRhdGEuZHJhZ2dlZCAvLyBkaWRuJ3QgcGFuXG4gICAgICAgICYmICFpc011bHRTZWxLZXlEb3duKGUpKSB7XG4gICAgICAgICAgY3kuJChpc1NlbGVjdGVkKS51bnNlbGVjdChbJ3RhcHVuc2VsZWN0J10pO1xuXG4gICAgICAgICAgaWYgKGRyYWdnZWRFbGVtZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICByLnJlZHJhd0hpbnQoJ2VsZXMnLCB0cnVlKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByLmRyYWdEYXRhLnBvc3NpYmxlRHJhZ0VsZW1lbnRzID0gZHJhZ2dlZEVsZW1lbnRzID0gY3kuY29sbGVjdGlvbigpO1xuICAgICAgICB9IC8vIFNpbmdsZSBzZWxlY3Rpb25cblxuXG4gICAgICAgIGlmIChuZWFyID09IGRvd24gJiYgIXIuZHJhZ0RhdGEuZGlkRHJhZyAmJiAhci5ob3ZlckRhdGEuc2VsZWN0aW5nKSB7XG4gICAgICAgICAgaWYgKG5lYXIgIT0gbnVsbCAmJiBuZWFyLl9wcml2YXRlLnNlbGVjdGFibGUpIHtcbiAgICAgICAgICAgIGlmIChyLmhvdmVyRGF0YS5kcmFnZ2luZykgOyBlbHNlIGlmIChjeS5zZWxlY3Rpb25UeXBlKCkgPT09ICdhZGRpdGl2ZScgfHwgbXVsdFNlbEtleURvd24pIHtcbiAgICAgICAgICAgICAgaWYgKG5lYXIuc2VsZWN0ZWQoKSkge1xuICAgICAgICAgICAgICAgIG5lYXIudW5zZWxlY3QoWyd0YXB1bnNlbGVjdCddKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZWFyLnNlbGVjdChbJ3RhcHNlbGVjdCddKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaWYgKCFtdWx0U2VsS2V5RG93bikge1xuICAgICAgICAgICAgICAgIGN5LiQoaXNTZWxlY3RlZCkudW5tZXJnZShuZWFyKS51bnNlbGVjdChbJ3RhcHVuc2VsZWN0J10pO1xuICAgICAgICAgICAgICAgIG5lYXIuc2VsZWN0KFsndGFwc2VsZWN0J10pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHIucmVkcmF3SGludCgnZWxlcycsIHRydWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyLmhvdmVyRGF0YS5zZWxlY3RpbmcpIHtcbiAgICAgICAgICB2YXIgYm94ID0gY3kuY29sbGVjdGlvbihyLmdldEFsbEluQm94KHNlbGVjdFswXSwgc2VsZWN0WzFdLCBzZWxlY3RbMl0sIHNlbGVjdFszXSkpO1xuICAgICAgICAgIHIucmVkcmF3SGludCgnc2VsZWN0JywgdHJ1ZSk7XG5cbiAgICAgICAgICBpZiAoYm94Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHIucmVkcmF3SGludCgnZWxlcycsIHRydWUpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGN5LmVtaXQoe1xuICAgICAgICAgICAgdHlwZTogJ2JveGVuZCcsXG4gICAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIHZhciBlbGVXb3VsZEJlU2VsZWN0ZWQgPSBmdW5jdGlvbiBlbGVXb3VsZEJlU2VsZWN0ZWQoZWxlKSB7XG4gICAgICAgICAgICByZXR1cm4gZWxlLnNlbGVjdGFibGUoKSAmJiAhZWxlLnNlbGVjdGVkKCk7XG4gICAgICAgICAgfTtcblxuICAgICAgICAgIGlmIChjeS5zZWxlY3Rpb25UeXBlKCkgPT09ICdhZGRpdGl2ZScpIHtcbiAgICAgICAgICAgIGJveC5lbWl0KCdib3gnKS5zdGRGaWx0ZXIoZWxlV291bGRCZVNlbGVjdGVkKS5zZWxlY3QoKS5lbWl0KCdib3hzZWxlY3QnKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKCFtdWx0U2VsS2V5RG93bikge1xuICAgICAgICAgICAgICBjeS4kKGlzU2VsZWN0ZWQpLnVubWVyZ2UoYm94KS51bnNlbGVjdCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBib3guZW1pdCgnYm94Jykuc3RkRmlsdGVyKGVsZVdvdWxkQmVTZWxlY3RlZCkuc2VsZWN0KCkuZW1pdCgnYm94c2VsZWN0Jyk7XG4gICAgICAgICAgfSAvLyBhbHdheXMgbmVlZCByZWRyYXcgaW4gY2FzZSBlbGVzIHVuc2VsZWN0YWJsZVxuXG5cbiAgICAgICAgICByLnJlZHJhdygpO1xuICAgICAgICB9IC8vIENhbmNlbCBkcmFnIHBhblxuXG5cbiAgICAgICAgaWYgKHIuaG92ZXJEYXRhLmRyYWdnaW5nKSB7XG4gICAgICAgICAgci5ob3ZlckRhdGEuZHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgICByLnJlZHJhd0hpbnQoJ3NlbGVjdCcsIHRydWUpO1xuICAgICAgICAgIHIucmVkcmF3SGludCgnZWxlcycsIHRydWUpO1xuICAgICAgICAgIHIucmVkcmF3KCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXNlbGVjdFs0XSkge1xuICAgICAgICAgIHIucmVkcmF3SGludCgnZHJhZycsIHRydWUpO1xuICAgICAgICAgIHIucmVkcmF3SGludCgnZWxlcycsIHRydWUpO1xuICAgICAgICAgIHZhciBkb3duV2FzR3JhYmJlZCA9IGRvd24gJiYgZG93bi5ncmFiYmVkKCk7XG4gICAgICAgICAgZnJlZURyYWdnZWRFbGVtZW50cyhkcmFnZ2VkRWxlbWVudHMpO1xuXG4gICAgICAgICAgaWYgKGRvd25XYXNHcmFiYmVkKSB7XG4gICAgICAgICAgICBkb3duLmVtaXQoJ2ZyZWVvbicpO1xuICAgICAgICAgICAgZHJhZ2dlZEVsZW1lbnRzLmVtaXQoJ2ZyZWUnKTtcblxuICAgICAgICAgICAgaWYgKHIuZHJhZ0RhdGEuZGlkRHJhZykge1xuICAgICAgICAgICAgICBkb3duLmVtaXQoJ2RyYWdmcmVlb24nKTtcbiAgICAgICAgICAgICAgZHJhZ2dlZEVsZW1lbnRzLmVtaXQoJ2RyYWdmcmVlJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IC8vIGVsc2Ugbm90IHJpZ2h0IG1vdXNlXG5cblxuICAgICAgc2VsZWN0WzRdID0gMDtcbiAgICAgIHIuaG92ZXJEYXRhLmRvd24gPSBudWxsO1xuICAgICAgci5ob3ZlckRhdGEuY3h0U3RhcnRlZCA9IGZhbHNlO1xuICAgICAgci5ob3ZlckRhdGEuZHJhZ2dpbmdFbGVzID0gZmFsc2U7XG4gICAgICByLmhvdmVyRGF0YS5zZWxlY3RpbmcgPSBmYWxzZTtcbiAgICAgIHIuaG92ZXJEYXRhLmlzT3ZlclRocmVzaG9sZERyYWcgPSBmYWxzZTtcbiAgICAgIHIuZHJhZ0RhdGEuZGlkRHJhZyA9IGZhbHNlO1xuICAgICAgci5ob3ZlckRhdGEuZHJhZ2dlZCA9IGZhbHNlO1xuICAgICAgci5ob3ZlckRhdGEuZHJhZ0RlbHRhID0gW107XG4gICAgICByLmhvdmVyRGF0YS5tZG93blBvcyA9IG51bGw7XG4gICAgICByLmhvdmVyRGF0YS5tZG93bkdQb3MgPSBudWxsO1xuICAgIH0sIGZhbHNlKTtcblxuICAgIHZhciB3aGVlbEhhbmRsZXIgPSBmdW5jdGlvbiB3aGVlbEhhbmRsZXIoZSkge1xuICAgICAgaWYgKHIuc2Nyb2xsaW5nUGFnZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHdoaWxlIHNjcm9sbGluZywgaWdub3JlIHdoZWVsLXRvLXpvb21cblxuXG4gICAgICB2YXIgY3kgPSByLmN5O1xuICAgICAgdmFyIHpvb20gPSBjeS56b29tKCk7XG4gICAgICB2YXIgcGFuID0gY3kucGFuKCk7XG4gICAgICB2YXIgcG9zID0gci5wcm9qZWN0SW50b1ZpZXdwb3J0KGUuY2xpZW50WCwgZS5jbGllbnRZKTtcbiAgICAgIHZhciBycG9zID0gW3Bvc1swXSAqIHpvb20gKyBwYW4ueCwgcG9zWzFdICogem9vbSArIHBhbi55XTtcblxuICAgICAgaWYgKHIuaG92ZXJEYXRhLmRyYWdnaW5nRWxlcyB8fCByLmhvdmVyRGF0YS5kcmFnZ2luZyB8fCByLmhvdmVyRGF0YS5jeHRTdGFydGVkIHx8IGluQm94U2VsZWN0aW9uKCkpIHtcbiAgICAgICAgLy8gaWYgcGFuIGRyYWdnaW5nIG9yIGN4dCBkcmFnZ2luZywgd2hlZWwgbW92ZW1lbnRzIG1ha2Ugbm8gem9vbVxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGN5LnBhbm5pbmdFbmFibGVkKCkgJiYgY3kudXNlclBhbm5pbmdFbmFibGVkKCkgJiYgY3kuem9vbWluZ0VuYWJsZWQoKSAmJiBjeS51c2VyWm9vbWluZ0VuYWJsZWQoKSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHIuZGF0YS53aGVlbFpvb21pbmcgPSB0cnVlO1xuICAgICAgICBjbGVhclRpbWVvdXQoci5kYXRhLndoZWVsVGltZW91dCk7XG4gICAgICAgIHIuZGF0YS53aGVlbFRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByLmRhdGEud2hlZWxab29taW5nID0gZmFsc2U7XG4gICAgICAgICAgci5yZWRyYXdIaW50KCdlbGVzJywgdHJ1ZSk7XG4gICAgICAgICAgci5yZWRyYXcoKTtcbiAgICAgICAgfSwgMTUwKTtcbiAgICAgICAgdmFyIGRpZmY7XG5cbiAgICAgICAgaWYgKGUuZGVsdGFZICE9IG51bGwpIHtcbiAgICAgICAgICBkaWZmID0gZS5kZWx0YVkgLyAtMjUwO1xuICAgICAgICB9IGVsc2UgaWYgKGUud2hlZWxEZWx0YVkgIT0gbnVsbCkge1xuICAgICAgICAgIGRpZmYgPSBlLndoZWVsRGVsdGFZIC8gMTAwMDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBkaWZmID0gZS53aGVlbERlbHRhIC8gMTAwMDtcbiAgICAgICAgfVxuXG4gICAgICAgIGRpZmYgPSBkaWZmICogci53aGVlbFNlbnNpdGl2aXR5O1xuICAgICAgICB2YXIgbmVlZHNXaGVlbEZpeCA9IGUuZGVsdGFNb2RlID09PSAxO1xuXG4gICAgICAgIGlmIChuZWVkc1doZWVsRml4KSB7XG4gICAgICAgICAgLy8gZml4ZXMgc2xvdyB3aGVlbCBldmVudHMgb24gZmYvbGludXggYW5kIGZmL3dpbmRvd3NcbiAgICAgICAgICBkaWZmICo9IDMzO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIG5ld1pvb20gPSBjeS56b29tKCkgKiBNYXRoLnBvdygxMCwgZGlmZik7XG5cbiAgICAgICAgaWYgKGUudHlwZSA9PT0gJ2dlc3R1cmVjaGFuZ2UnKSB7XG4gICAgICAgICAgbmV3Wm9vbSA9IHIuZ2VzdHVyZVN0YXJ0Wm9vbSAqIGUuc2NhbGU7XG4gICAgICAgIH1cblxuICAgICAgICBjeS56b29tKHtcbiAgICAgICAgICBsZXZlbDogbmV3Wm9vbSxcbiAgICAgICAgICByZW5kZXJlZFBvc2l0aW9uOiB7XG4gICAgICAgICAgICB4OiBycG9zWzBdLFxuICAgICAgICAgICAgeTogcnBvc1sxXVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGN5LmVtaXQoZS50eXBlID09PSAnZ2VzdHVyZWNoYW5nZScgPyAncGluY2h6b29tJyA6ICdzY3JvbGx6b29tJyk7XG4gICAgICB9XG4gICAgfTsgLy8gRnVuY3Rpb25zIHRvIGhlbHAgd2l0aCB3aGV0aGVyIG1vdXNlIHdoZWVsIHNob3VsZCB0cmlnZ2VyIHpvb21pbmdcbiAgICAvLyAtLVxuXG5cbiAgICByLnJlZ2lzdGVyQmluZGluZyhyLmNvbnRhaW5lciwgJ3doZWVsJywgd2hlZWxIYW5kbGVyLCB0cnVlKTsgLy8gZGlzYWJsZSBub25zdGFuZGFyZCB3aGVlbCBldmVudHNcbiAgICAvLyByLnJlZ2lzdGVyQmluZGluZyhyLmNvbnRhaW5lciwgJ21vdXNld2hlZWwnLCB3aGVlbEhhbmRsZXIsIHRydWUpO1xuICAgIC8vIHIucmVnaXN0ZXJCaW5kaW5nKHIuY29udGFpbmVyLCAnRE9NTW91c2VTY3JvbGwnLCB3aGVlbEhhbmRsZXIsIHRydWUpO1xuICAgIC8vIHIucmVnaXN0ZXJCaW5kaW5nKHIuY29udGFpbmVyLCAnTW96TW91c2VQaXhlbFNjcm9sbCcsIHdoZWVsSGFuZGxlciwgdHJ1ZSk7IC8vIG9sZGVyIGZpcmVmb3hcblxuICAgIHIucmVnaXN0ZXJCaW5kaW5nKGNvbnRhaW5lcldpbmRvdywgJ3Njcm9sbCcsIGZ1bmN0aW9uIHNjcm9sbEhhbmRsZXIoZSkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICAgICAgci5zY3JvbGxpbmdQYWdlID0gdHJ1ZTtcbiAgICAgIGNsZWFyVGltZW91dChyLnNjcm9sbGluZ1BhZ2VUaW1lb3V0KTtcbiAgICAgIHIuc2Nyb2xsaW5nUGFnZVRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgci5zY3JvbGxpbmdQYWdlID0gZmFsc2U7XG4gICAgICB9LCAyNTApO1xuICAgIH0sIHRydWUpOyAvLyBkZXNrdG9wIHNhZmFyaSBwaW5jaCB0byB6b29tIHN0YXJ0XG5cbiAgICByLnJlZ2lzdGVyQmluZGluZyhyLmNvbnRhaW5lciwgJ2dlc3R1cmVzdGFydCcsIGZ1bmN0aW9uIGdlc3R1cmVTdGFydEhhbmRsZXIoZSkge1xuICAgICAgci5nZXN0dXJlU3RhcnRab29tID0gci5jeS56b29tKCk7XG5cbiAgICAgIGlmICghci5oYXNUb3VjaFN0YXJ0ZWQpIHtcbiAgICAgICAgLy8gZG9uJ3QgYWZmZWN0IHRvdWNoIGRldmljZXMgbGlrZSBpcGhvbmVcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuICAgIH0sIHRydWUpO1xuICAgIHIucmVnaXN0ZXJCaW5kaW5nKHIuY29udGFpbmVyLCAnZ2VzdHVyZWNoYW5nZScsIGZ1bmN0aW9uIChlKSB7XG4gICAgICBpZiAoIXIuaGFzVG91Y2hTdGFydGVkKSB7XG4gICAgICAgIC8vIGRvbid0IGFmZmVjdCB0b3VjaCBkZXZpY2VzIGxpa2UgaXBob25lXG4gICAgICAgIHdoZWVsSGFuZGxlcihlKTtcbiAgICAgIH1cbiAgICB9LCB0cnVlKTsgLy8gRnVuY3Rpb25zIHRvIGhlbHAgd2l0aCBoYW5kbGluZyBtb3VzZW91dC9tb3VzZW92ZXIgb24gdGhlIEN5dG9zY2FwZSBjb250YWluZXJcbiAgICAvLyBIYW5kbGUgbW91c2VvdXQgb24gQ3l0b3NjYXBlIGNvbnRhaW5lclxuXG4gICAgci5yZWdpc3RlckJpbmRpbmcoci5jb250YWluZXIsICdtb3VzZW91dCcsIGZ1bmN0aW9uIG1vdXNlT3V0SGFuZGxlcihlKSB7XG4gICAgICB2YXIgcG9zID0gci5wcm9qZWN0SW50b1ZpZXdwb3J0KGUuY2xpZW50WCwgZS5jbGllbnRZKTtcbiAgICAgIHIuY3kuZW1pdCh7XG4gICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgIHR5cGU6ICdtb3VzZW91dCcsXG4gICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgIHk6IHBvc1sxXVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9LCBmYWxzZSk7XG4gICAgci5yZWdpc3RlckJpbmRpbmcoci5jb250YWluZXIsICdtb3VzZW92ZXInLCBmdW5jdGlvbiBtb3VzZU92ZXJIYW5kbGVyKGUpIHtcbiAgICAgIHZhciBwb3MgPSByLnByb2plY3RJbnRvVmlld3BvcnQoZS5jbGllbnRYLCBlLmNsaWVudFkpO1xuICAgICAgci5jeS5lbWl0KHtcbiAgICAgICAgb3JpZ2luYWxFdmVudDogZSxcbiAgICAgICAgdHlwZTogJ21vdXNlb3ZlcicsXG4gICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgeDogcG9zWzBdLFxuICAgICAgICAgIHk6IHBvc1sxXVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9LCBmYWxzZSk7XG4gICAgdmFyIGYxeDEsIGYxeTEsIGYyeDEsIGYyeTE7IC8vIHN0YXJ0aW5nIHBvaW50cyBmb3IgcGluY2gtdG8tem9vbVxuXG4gICAgdmFyIGRpc3RhbmNlMSwgZGlzdGFuY2UxU3E7IC8vIGluaXRpYWwgZGlzdGFuY2UgYmV0d2VlbiBmaW5nZXIgMSBhbmQgZmluZ2VyIDIgZm9yIHBpbmNoLXRvLXpvb21cblxuICAgIHZhciBjZW50ZXIxLCBtb2RlbENlbnRlcjE7IC8vIGNlbnRlciBwb2ludCBvbiBzdGFydCBwaW5jaCB0byB6b29tXG5cbiAgICB2YXIgb2Zmc2V0TGVmdCwgb2Zmc2V0VG9wO1xuICAgIHZhciBjb250YWluZXJXaWR0aCwgY29udGFpbmVySGVpZ2h0O1xuICAgIHZhciB0d29GaW5nZXJzU3RhcnRJbnNpZGU7XG5cbiAgICB2YXIgZGlzdGFuY2UgPSBmdW5jdGlvbiBkaXN0YW5jZSh4MSwgeTEsIHgyLCB5Mikge1xuICAgICAgcmV0dXJuIE1hdGguc3FydCgoeDIgLSB4MSkgKiAoeDIgLSB4MSkgKyAoeTIgLSB5MSkgKiAoeTIgLSB5MSkpO1xuICAgIH07XG5cbiAgICB2YXIgZGlzdGFuY2VTcSA9IGZ1bmN0aW9uIGRpc3RhbmNlU3EoeDEsIHkxLCB4MiwgeTIpIHtcbiAgICAgIHJldHVybiAoeDIgLSB4MSkgKiAoeDIgLSB4MSkgKyAoeTIgLSB5MSkgKiAoeTIgLSB5MSk7XG4gICAgfTtcblxuICAgIHZhciB0b3VjaHN0YXJ0SGFuZGxlcjtcbiAgICByLnJlZ2lzdGVyQmluZGluZyhyLmNvbnRhaW5lciwgJ3RvdWNoc3RhcnQnLCB0b3VjaHN0YXJ0SGFuZGxlciA9IGZ1bmN0aW9uIHRvdWNoc3RhcnRIYW5kbGVyKGUpIHtcbiAgICAgIHIuaGFzVG91Y2hTdGFydGVkID0gdHJ1ZTtcblxuICAgICAgaWYgKCFldmVudEluQ29udGFpbmVyKGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgYmx1ckFjdGl2ZURvbUVsZW1lbnQoKTtcbiAgICAgIHIudG91Y2hEYXRhLmNhcHR1cmUgPSB0cnVlO1xuICAgICAgci5kYXRhLmJnQWN0aXZlUG9zaXN0aW9uID0gdW5kZWZpbmVkO1xuICAgICAgdmFyIGN5ID0gci5jeTtcbiAgICAgIHZhciBub3cgPSByLnRvdWNoRGF0YS5ub3c7XG4gICAgICB2YXIgZWFybGllciA9IHIudG91Y2hEYXRhLmVhcmxpZXI7XG5cbiAgICAgIGlmIChlLnRvdWNoZXNbMF0pIHtcbiAgICAgICAgdmFyIHBvcyA9IHIucHJvamVjdEludG9WaWV3cG9ydChlLnRvdWNoZXNbMF0uY2xpZW50WCwgZS50b3VjaGVzWzBdLmNsaWVudFkpO1xuICAgICAgICBub3dbMF0gPSBwb3NbMF07XG4gICAgICAgIG5vd1sxXSA9IHBvc1sxXTtcbiAgICAgIH1cblxuICAgICAgaWYgKGUudG91Y2hlc1sxXSkge1xuICAgICAgICB2YXIgcG9zID0gci5wcm9qZWN0SW50b1ZpZXdwb3J0KGUudG91Y2hlc1sxXS5jbGllbnRYLCBlLnRvdWNoZXNbMV0uY2xpZW50WSk7XG4gICAgICAgIG5vd1syXSA9IHBvc1swXTtcbiAgICAgICAgbm93WzNdID0gcG9zWzFdO1xuICAgICAgfVxuXG4gICAgICBpZiAoZS50b3VjaGVzWzJdKSB7XG4gICAgICAgIHZhciBwb3MgPSByLnByb2plY3RJbnRvVmlld3BvcnQoZS50b3VjaGVzWzJdLmNsaWVudFgsIGUudG91Y2hlc1syXS5jbGllbnRZKTtcbiAgICAgICAgbm93WzRdID0gcG9zWzBdO1xuICAgICAgICBub3dbNV0gPSBwb3NbMV07XG4gICAgICB9IC8vIHJlY29yZCBzdGFydGluZyBwb2ludHMgZm9yIHBpbmNoLXRvLXpvb21cblxuXG4gICAgICBpZiAoZS50b3VjaGVzWzFdKSB7XG4gICAgICAgIHIudG91Y2hEYXRhLnNpbmdsZVRvdWNoTW92ZWQgPSB0cnVlO1xuICAgICAgICBmcmVlRHJhZ2dlZEVsZW1lbnRzKHIuZHJhZ0RhdGEudG91Y2hEcmFnRWxlcyk7XG4gICAgICAgIHZhciBvZmZzZXRzID0gci5maW5kQ29udGFpbmVyQ2xpZW50Q29vcmRzKCk7XG4gICAgICAgIG9mZnNldExlZnQgPSBvZmZzZXRzWzBdO1xuICAgICAgICBvZmZzZXRUb3AgPSBvZmZzZXRzWzFdO1xuICAgICAgICBjb250YWluZXJXaWR0aCA9IG9mZnNldHNbMl07XG4gICAgICAgIGNvbnRhaW5lckhlaWdodCA9IG9mZnNldHNbM107XG4gICAgICAgIGYxeDEgPSBlLnRvdWNoZXNbMF0uY2xpZW50WCAtIG9mZnNldExlZnQ7XG4gICAgICAgIGYxeTEgPSBlLnRvdWNoZXNbMF0uY2xpZW50WSAtIG9mZnNldFRvcDtcbiAgICAgICAgZjJ4MSA9IGUudG91Y2hlc1sxXS5jbGllbnRYIC0gb2Zmc2V0TGVmdDtcbiAgICAgICAgZjJ5MSA9IGUudG91Y2hlc1sxXS5jbGllbnRZIC0gb2Zmc2V0VG9wO1xuICAgICAgICB0d29GaW5nZXJzU3RhcnRJbnNpZGUgPSAwIDw9IGYxeDEgJiYgZjF4MSA8PSBjb250YWluZXJXaWR0aCAmJiAwIDw9IGYyeDEgJiYgZjJ4MSA8PSBjb250YWluZXJXaWR0aCAmJiAwIDw9IGYxeTEgJiYgZjF5MSA8PSBjb250YWluZXJIZWlnaHQgJiYgMCA8PSBmMnkxICYmIGYyeTEgPD0gY29udGFpbmVySGVpZ2h0O1xuICAgICAgICB2YXIgcGFuID0gY3kucGFuKCk7XG4gICAgICAgIHZhciB6b29tID0gY3kuem9vbSgpO1xuICAgICAgICBkaXN0YW5jZTEgPSBkaXN0YW5jZShmMXgxLCBmMXkxLCBmMngxLCBmMnkxKTtcbiAgICAgICAgZGlzdGFuY2UxU3EgPSBkaXN0YW5jZVNxKGYxeDEsIGYxeTEsIGYyeDEsIGYyeTEpO1xuICAgICAgICBjZW50ZXIxID0gWyhmMXgxICsgZjJ4MSkgLyAyLCAoZjF5MSArIGYyeTEpIC8gMl07XG4gICAgICAgIG1vZGVsQ2VudGVyMSA9IFsoY2VudGVyMVswXSAtIHBhbi54KSAvIHpvb20sIChjZW50ZXIxWzFdIC0gcGFuLnkpIC8gem9vbV07IC8vIGNvbnNpZGVyIGNvbnRleHQgdGFwXG5cbiAgICAgICAgdmFyIGN4dERpc3RUaHJlc2hvbGQgPSAyMDA7XG4gICAgICAgIHZhciBjeHREaXN0VGhyZXNob2xkU3EgPSBjeHREaXN0VGhyZXNob2xkICogY3h0RGlzdFRocmVzaG9sZDtcblxuICAgICAgICBpZiAoZGlzdGFuY2UxU3EgPCBjeHREaXN0VGhyZXNob2xkU3EgJiYgIWUudG91Y2hlc1syXSkge1xuICAgICAgICAgIHZhciBuZWFyMSA9IHIuZmluZE5lYXJlc3RFbGVtZW50KG5vd1swXSwgbm93WzFdLCB0cnVlLCB0cnVlKTtcbiAgICAgICAgICB2YXIgbmVhcjIgPSByLmZpbmROZWFyZXN0RWxlbWVudChub3dbMl0sIG5vd1szXSwgdHJ1ZSwgdHJ1ZSk7XG5cbiAgICAgICAgICBpZiAobmVhcjEgJiYgbmVhcjEuaXNOb2RlKCkpIHtcbiAgICAgICAgICAgIG5lYXIxLmFjdGl2YXRlKCkuZW1pdCh7XG4gICAgICAgICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgICAgICAgIHR5cGU6ICdjeHR0YXBzdGFydCcsXG4gICAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgICAgeDogbm93WzBdLFxuICAgICAgICAgICAgICAgIHk6IG5vd1sxXVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHIudG91Y2hEYXRhLnN0YXJ0ID0gbmVhcjE7XG4gICAgICAgICAgfSBlbHNlIGlmIChuZWFyMiAmJiBuZWFyMi5pc05vZGUoKSkge1xuICAgICAgICAgICAgbmVhcjIuYWN0aXZhdGUoKS5lbWl0KHtcbiAgICAgICAgICAgICAgb3JpZ2luYWxFdmVudDogZSxcbiAgICAgICAgICAgICAgdHlwZTogJ2N4dHRhcHN0YXJ0JyxcbiAgICAgICAgICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgICAgICAgeTogbm93WzFdXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgci50b3VjaERhdGEuc3RhcnQgPSBuZWFyMjtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY3kuZW1pdCh7XG4gICAgICAgICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgICAgICAgIHR5cGU6ICdjeHR0YXBzdGFydCcsXG4gICAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgICAgeDogbm93WzBdLFxuICAgICAgICAgICAgICAgIHk6IG5vd1sxXVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoci50b3VjaERhdGEuc3RhcnQpIHtcbiAgICAgICAgICAgIHIudG91Y2hEYXRhLnN0YXJ0Ll9wcml2YXRlLmdyYWJiZWQgPSBmYWxzZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByLnRvdWNoRGF0YS5jeHQgPSB0cnVlO1xuICAgICAgICAgIHIudG91Y2hEYXRhLmN4dERyYWdnZWQgPSBmYWxzZTtcbiAgICAgICAgICByLmRhdGEuYmdBY3RpdmVQb3Npc3Rpb24gPSB1bmRlZmluZWQ7XG4gICAgICAgICAgci5yZWRyYXcoKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGUudG91Y2hlc1syXSkge1xuICAgICAgICAvLyBpZ25vcmVcbiAgICAgICAgLy8gc2FmYXJpIG9uIGlvcyBwYW5zIHRoZSBwYWdlIG90aGVyd2lzZSAobm9ybWFsbHkgeW91IHNob3VsZCBiZSBhYmxlIHRvIHByZXZlbnRkZWZhdWx0IG9uIHRvdWNobW92ZS4uLilcbiAgICAgICAgaWYgKGN5LmJveFNlbGVjdGlvbkVuYWJsZWQoKSkge1xuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChlLnRvdWNoZXNbMV0pIDsgZWxzZSBpZiAoZS50b3VjaGVzWzBdKSB7XG4gICAgICAgIHZhciBuZWFycyA9IHIuZmluZE5lYXJlc3RFbGVtZW50cyhub3dbMF0sIG5vd1sxXSwgdHJ1ZSwgdHJ1ZSk7XG4gICAgICAgIHZhciBuZWFyID0gbmVhcnNbMF07XG5cbiAgICAgICAgaWYgKG5lYXIgIT0gbnVsbCkge1xuICAgICAgICAgIG5lYXIuYWN0aXZhdGUoKTtcbiAgICAgICAgICByLnRvdWNoRGF0YS5zdGFydCA9IG5lYXI7XG4gICAgICAgICAgci50b3VjaERhdGEuc3RhcnRzID0gbmVhcnM7XG5cbiAgICAgICAgICBpZiAoci5ub2RlSXNHcmFiYmFibGUobmVhcikpIHtcbiAgICAgICAgICAgIHZhciBkcmFnZ2VkRWxlcyA9IHIuZHJhZ0RhdGEudG91Y2hEcmFnRWxlcyA9IGN5LmNvbGxlY3Rpb24oKTtcbiAgICAgICAgICAgIHZhciBzZWxlY3RlZE5vZGVzID0gbnVsbDtcbiAgICAgICAgICAgIHIucmVkcmF3SGludCgnZWxlcycsIHRydWUpO1xuICAgICAgICAgICAgci5yZWRyYXdIaW50KCdkcmFnJywgdHJ1ZSk7XG5cbiAgICAgICAgICAgIGlmIChuZWFyLnNlbGVjdGVkKCkpIHtcbiAgICAgICAgICAgICAgLy8gcmVzZXQgZHJhZyBlbGVtZW50cywgc2luY2UgbmVhciB3aWxsIGJlIGFkZGVkIGFnYWluXG4gICAgICAgICAgICAgIHNlbGVjdGVkTm9kZXMgPSBjeS4kKGZ1bmN0aW9uIChlbGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZWxlLnNlbGVjdGVkKCkgJiYgci5ub2RlSXNHcmFiYmFibGUoZWxlKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIGFkZE5vZGVzVG9EcmFnKHNlbGVjdGVkTm9kZXMsIHtcbiAgICAgICAgICAgICAgICBhZGRUb0xpc3Q6IGRyYWdnZWRFbGVzXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgYWRkTm9kZVRvRHJhZyhuZWFyLCB7XG4gICAgICAgICAgICAgICAgYWRkVG9MaXN0OiBkcmFnZ2VkRWxlc1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0R3JhYlRhcmdldChuZWFyKTtcblxuICAgICAgICAgICAgdmFyIG1ha2VFdmVudCA9IGZ1bmN0aW9uIG1ha2VFdmVudCh0eXBlKSB7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgb3JpZ2luYWxFdmVudDogZSxcbiAgICAgICAgICAgICAgICB0eXBlOiB0eXBlLFxuICAgICAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgICAgICAgICB5OiBub3dbMV1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBuZWFyLmVtaXQobWFrZUV2ZW50KCdncmFib24nKSk7XG5cbiAgICAgICAgICAgIGlmIChzZWxlY3RlZE5vZGVzKSB7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTm9kZXMuZm9yRWFjaChmdW5jdGlvbiAobikge1xuICAgICAgICAgICAgICAgIG4uZW1pdChtYWtlRXZlbnQoJ2dyYWInKSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgbmVhci5lbWl0KG1ha2VFdmVudCgnZ3JhYicpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0cmlnZ2VyRXZlbnRzKG5lYXIsIFsndG91Y2hzdGFydCcsICd0YXBzdGFydCcsICd2bW91c2Vkb3duJ10sIGUsIHtcbiAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgeTogbm93WzFdXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChuZWFyID09IG51bGwpIHtcbiAgICAgICAgICByLmRhdGEuYmdBY3RpdmVQb3Npc3Rpb24gPSB7XG4gICAgICAgICAgICB4OiBwb3NbMF0sXG4gICAgICAgICAgICB5OiBwb3NbMV1cbiAgICAgICAgICB9O1xuICAgICAgICAgIHIucmVkcmF3SGludCgnc2VsZWN0JywgdHJ1ZSk7XG4gICAgICAgICAgci5yZWRyYXcoKTtcbiAgICAgICAgfSAvLyBUYXAsIHRhcGhvbGRcbiAgICAgICAgLy8gLS0tLS1cblxuXG4gICAgICAgIHIudG91Y2hEYXRhLnNpbmdsZVRvdWNoTW92ZWQgPSBmYWxzZTtcbiAgICAgICAgci50b3VjaERhdGEuc2luZ2xlVG91Y2hTdGFydFRpbWUgPSArbmV3IERhdGUoKTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHIudG91Y2hEYXRhLnRhcGhvbGRUaW1lb3V0KTtcbiAgICAgICAgci50b3VjaERhdGEudGFwaG9sZFRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBpZiAoci50b3VjaERhdGEuc2luZ2xlVG91Y2hNb3ZlZCA9PT0gZmFsc2UgJiYgIXIucGluY2hpbmcgLy8gaWYgcGluY2hpbmcsIHRoZW4gdGFwaG9sZCB1bnNlbGVjdCBzaG91bGRuJ3QgdGFrZSBlZmZlY3RcbiAgICAgICAgICAmJiAhci50b3VjaERhdGEuc2VsZWN0aW5nIC8vIGJveCBzZWxlY3Rpb24gc2hvdWxkbid0IGFsbG93IHRhcGhvbGQgdGhyb3VnaFxuICAgICAgICAgICkge1xuICAgICAgICAgICAgdHJpZ2dlckV2ZW50cyhyLnRvdWNoRGF0YS5zdGFydCwgWyd0YXBob2xkJ10sIGUsIHtcbiAgICAgICAgICAgICAgeDogbm93WzBdLFxuICAgICAgICAgICAgICB5OiBub3dbMV1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgci50YXBob2xkRHVyYXRpb24pO1xuICAgICAgfVxuXG4gICAgICBpZiAoZS50b3VjaGVzLmxlbmd0aCA+PSAxKSB7XG4gICAgICAgIHZhciBzUG9zID0gci50b3VjaERhdGEuc3RhcnRQb3NpdGlvbiA9IFtudWxsLCBudWxsLCBudWxsLCBudWxsLCBudWxsLCBudWxsXTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5vdy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHNQb3NbaV0gPSBlYXJsaWVyW2ldID0gbm93W2ldO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHRvdWNoMCA9IGUudG91Y2hlc1swXTtcbiAgICAgICAgci50b3VjaERhdGEuc3RhcnRHUG9zaXRpb24gPSBbdG91Y2gwLmNsaWVudFgsIHRvdWNoMC5jbGllbnRZXTtcbiAgICAgIH1cbiAgICB9LCBmYWxzZSk7XG4gICAgdmFyIHRvdWNobW92ZUhhbmRsZXI7XG4gICAgci5yZWdpc3RlckJpbmRpbmcod2luZG93LCAndG91Y2htb3ZlJywgdG91Y2htb3ZlSGFuZGxlciA9IGZ1bmN0aW9uIHRvdWNobW92ZUhhbmRsZXIoZSkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuICAgICAgdmFyIGNhcHR1cmUgPSByLnRvdWNoRGF0YS5jYXB0dXJlO1xuXG4gICAgICBpZiAoIWNhcHR1cmUgJiYgIWV2ZW50SW5Db250YWluZXIoZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgc2VsZWN0ID0gci5zZWxlY3Rpb247XG4gICAgICB2YXIgY3kgPSByLmN5O1xuICAgICAgdmFyIG5vdyA9IHIudG91Y2hEYXRhLm5vdztcbiAgICAgIHZhciBlYXJsaWVyID0gci50b3VjaERhdGEuZWFybGllcjtcbiAgICAgIHZhciB6b29tID0gY3kuem9vbSgpO1xuXG4gICAgICBpZiAoZS50b3VjaGVzWzBdKSB7XG4gICAgICAgIHZhciBwb3MgPSByLnByb2plY3RJbnRvVmlld3BvcnQoZS50b3VjaGVzWzBdLmNsaWVudFgsIGUudG91Y2hlc1swXS5jbGllbnRZKTtcbiAgICAgICAgbm93WzBdID0gcG9zWzBdO1xuICAgICAgICBub3dbMV0gPSBwb3NbMV07XG4gICAgICB9XG5cbiAgICAgIGlmIChlLnRvdWNoZXNbMV0pIHtcbiAgICAgICAgdmFyIHBvcyA9IHIucHJvamVjdEludG9WaWV3cG9ydChlLnRvdWNoZXNbMV0uY2xpZW50WCwgZS50b3VjaGVzWzFdLmNsaWVudFkpO1xuICAgICAgICBub3dbMl0gPSBwb3NbMF07XG4gICAgICAgIG5vd1szXSA9IHBvc1sxXTtcbiAgICAgIH1cblxuICAgICAgaWYgKGUudG91Y2hlc1syXSkge1xuICAgICAgICB2YXIgcG9zID0gci5wcm9qZWN0SW50b1ZpZXdwb3J0KGUudG91Y2hlc1syXS5jbGllbnRYLCBlLnRvdWNoZXNbMl0uY2xpZW50WSk7XG4gICAgICAgIG5vd1s0XSA9IHBvc1swXTtcbiAgICAgICAgbm93WzVdID0gcG9zWzFdO1xuICAgICAgfVxuXG4gICAgICB2YXIgc3RhcnRHUG9zID0gci50b3VjaERhdGEuc3RhcnRHUG9zaXRpb247XG4gICAgICB2YXIgaXNPdmVyVGhyZXNob2xkRHJhZztcblxuICAgICAgaWYgKGNhcHR1cmUgJiYgZS50b3VjaGVzWzBdICYmIHN0YXJ0R1Bvcykge1xuICAgICAgICB2YXIgZGlzcCA9IFtdO1xuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbm93Lmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgZGlzcFtqXSA9IG5vd1tqXSAtIGVhcmxpZXJbal07XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZHggPSBlLnRvdWNoZXNbMF0uY2xpZW50WCAtIHN0YXJ0R1Bvc1swXTtcbiAgICAgICAgdmFyIGR4MiA9IGR4ICogZHg7XG4gICAgICAgIHZhciBkeSA9IGUudG91Y2hlc1swXS5jbGllbnRZIC0gc3RhcnRHUG9zWzFdO1xuICAgICAgICB2YXIgZHkyID0gZHkgKiBkeTtcbiAgICAgICAgdmFyIGRpc3QyID0gZHgyICsgZHkyO1xuICAgICAgICBpc092ZXJUaHJlc2hvbGREcmFnID0gZGlzdDIgPj0gci50b3VjaFRhcFRocmVzaG9sZDI7XG4gICAgICB9IC8vIGNvbnRleHQgc3dpcGUgY2FuY2VsbGluZ1xuXG5cbiAgICAgIGlmIChjYXB0dXJlICYmIHIudG91Y2hEYXRhLmN4dCkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHZhciBmMXgyID0gZS50b3VjaGVzWzBdLmNsaWVudFggLSBvZmZzZXRMZWZ0LFxuICAgICAgICAgICAgZjF5MiA9IGUudG91Y2hlc1swXS5jbGllbnRZIC0gb2Zmc2V0VG9wO1xuICAgICAgICB2YXIgZjJ4MiA9IGUudG91Y2hlc1sxXS5jbGllbnRYIC0gb2Zmc2V0TGVmdCxcbiAgICAgICAgICAgIGYyeTIgPSBlLnRvdWNoZXNbMV0uY2xpZW50WSAtIG9mZnNldFRvcDsgLy8gdmFyIGRpc3RhbmNlMiA9IGRpc3RhbmNlKCBmMXgyLCBmMXkyLCBmMngyLCBmMnkyICk7XG5cbiAgICAgICAgdmFyIGRpc3RhbmNlMlNxID0gZGlzdGFuY2VTcShmMXgyLCBmMXkyLCBmMngyLCBmMnkyKTtcbiAgICAgICAgdmFyIGZhY3RvclNxID0gZGlzdGFuY2UyU3EgLyBkaXN0YW5jZTFTcTtcbiAgICAgICAgdmFyIGRpc3RUaHJlc2hvbGQgPSAxNTA7XG4gICAgICAgIHZhciBkaXN0VGhyZXNob2xkU3EgPSBkaXN0VGhyZXNob2xkICogZGlzdFRocmVzaG9sZDtcbiAgICAgICAgdmFyIGZhY3RvclRocmVzaG9sZCA9IDEuNTtcbiAgICAgICAgdmFyIGZhY3RvclRocmVzaG9sZFNxID0gZmFjdG9yVGhyZXNob2xkICogZmFjdG9yVGhyZXNob2xkOyAvLyBjYW5jZWwgY3R4IGdlc3R1cmVzIGlmIHRoZSBkaXN0YW5jZSBiL3QgdGhlIGZpbmdlcnMgaW5jcmVhc2VzXG5cbiAgICAgICAgaWYgKGZhY3RvclNxID49IGZhY3RvclRocmVzaG9sZFNxIHx8IGRpc3RhbmNlMlNxID49IGRpc3RUaHJlc2hvbGRTcSkge1xuICAgICAgICAgIHIudG91Y2hEYXRhLmN4dCA9IGZhbHNlO1xuICAgICAgICAgIHIuZGF0YS5iZ0FjdGl2ZVBvc2lzdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgICByLnJlZHJhd0hpbnQoJ3NlbGVjdCcsIHRydWUpO1xuICAgICAgICAgIHZhciBjeHRFdnQgPSB7XG4gICAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgICAgdHlwZTogJ2N4dHRhcGVuZCcsXG4gICAgICAgICAgICBwb3NpdGlvbjoge1xuICAgICAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgICAgIHk6IG5vd1sxXVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH07XG5cbiAgICAgICAgICBpZiAoci50b3VjaERhdGEuc3RhcnQpIHtcbiAgICAgICAgICAgIHIudG91Y2hEYXRhLnN0YXJ0LnVuYWN0aXZhdGUoKS5lbWl0KGN4dEV2dCk7XG4gICAgICAgICAgICByLnRvdWNoRGF0YS5zdGFydCA9IG51bGw7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGN5LmVtaXQoY3h0RXZ0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gLy8gY29udGV4dCBzd2lwZVxuXG5cbiAgICAgIGlmIChjYXB0dXJlICYmIHIudG91Y2hEYXRhLmN4dCkge1xuICAgICAgICB2YXIgY3h0RXZ0ID0ge1xuICAgICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgICAgdHlwZTogJ2N4dGRyYWcnLFxuICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgICB5OiBub3dbMV1cbiAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHIuZGF0YS5iZ0FjdGl2ZVBvc2lzdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgci5yZWRyYXdIaW50KCdzZWxlY3QnLCB0cnVlKTtcblxuICAgICAgICBpZiAoci50b3VjaERhdGEuc3RhcnQpIHtcbiAgICAgICAgICByLnRvdWNoRGF0YS5zdGFydC5lbWl0KGN4dEV2dCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY3kuZW1pdChjeHRFdnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHIudG91Y2hEYXRhLnN0YXJ0KSB7XG4gICAgICAgICAgci50b3VjaERhdGEuc3RhcnQuX3ByaXZhdGUuZ3JhYmJlZCA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgci50b3VjaERhdGEuY3h0RHJhZ2dlZCA9IHRydWU7XG4gICAgICAgIHZhciBuZWFyID0gci5maW5kTmVhcmVzdEVsZW1lbnQobm93WzBdLCBub3dbMV0sIHRydWUsIHRydWUpO1xuXG4gICAgICAgIGlmICghci50b3VjaERhdGEuY3h0T3ZlciB8fCBuZWFyICE9PSByLnRvdWNoRGF0YS5jeHRPdmVyKSB7XG4gICAgICAgICAgaWYgKHIudG91Y2hEYXRhLmN4dE92ZXIpIHtcbiAgICAgICAgICAgIHIudG91Y2hEYXRhLmN4dE92ZXIuZW1pdCh7XG4gICAgICAgICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgICAgICAgIHR5cGU6ICdjeHRkcmFnb3V0JyxcbiAgICAgICAgICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgICAgICAgeTogbm93WzFdXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHIudG91Y2hEYXRhLmN4dE92ZXIgPSBuZWFyO1xuXG4gICAgICAgICAgaWYgKG5lYXIpIHtcbiAgICAgICAgICAgIG5lYXIuZW1pdCh7XG4gICAgICAgICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgICAgICAgIHR5cGU6ICdjeHRkcmFnb3ZlcicsXG4gICAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgICAgeDogbm93WzBdLFxuICAgICAgICAgICAgICAgIHk6IG5vd1sxXVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gLy8gYm94IHNlbGVjdGlvblxuXG4gICAgICB9IGVsc2UgaWYgKGNhcHR1cmUgJiYgZS50b3VjaGVzWzJdICYmIGN5LmJveFNlbGVjdGlvbkVuYWJsZWQoKSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHIuZGF0YS5iZ0FjdGl2ZVBvc2lzdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5sYXN0VGhyZWVUb3VjaCA9ICtuZXcgRGF0ZSgpO1xuXG4gICAgICAgIGlmICghci50b3VjaERhdGEuc2VsZWN0aW5nKSB7XG4gICAgICAgICAgY3kuZW1pdCh7XG4gICAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgICAgdHlwZTogJ2JveHN0YXJ0JyxcbiAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgIHg6IG5vd1swXSxcbiAgICAgICAgICAgICAgeTogbm93WzFdXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByLnRvdWNoRGF0YS5zZWxlY3RpbmcgPSB0cnVlO1xuICAgICAgICByLnRvdWNoRGF0YS5kaWRTZWxlY3QgPSB0cnVlO1xuICAgICAgICBzZWxlY3RbNF0gPSAxO1xuXG4gICAgICAgIGlmICghc2VsZWN0IHx8IHNlbGVjdC5sZW5ndGggPT09IDAgfHwgc2VsZWN0WzBdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBzZWxlY3RbMF0gPSAobm93WzBdICsgbm93WzJdICsgbm93WzRdKSAvIDM7XG4gICAgICAgICAgc2VsZWN0WzFdID0gKG5vd1sxXSArIG5vd1szXSArIG5vd1s1XSkgLyAzO1xuICAgICAgICAgIHNlbGVjdFsyXSA9IChub3dbMF0gKyBub3dbMl0gKyBub3dbNF0pIC8gMyArIDE7XG4gICAgICAgICAgc2VsZWN0WzNdID0gKG5vd1sxXSArIG5vd1szXSArIG5vd1s1XSkgLyAzICsgMTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZWxlY3RbMl0gPSAobm93WzBdICsgbm93WzJdICsgbm93WzRdKSAvIDM7XG4gICAgICAgICAgc2VsZWN0WzNdID0gKG5vd1sxXSArIG5vd1szXSArIG5vd1s1XSkgLyAzO1xuICAgICAgICB9XG5cbiAgICAgICAgci5yZWRyYXdIaW50KCdzZWxlY3QnLCB0cnVlKTtcbiAgICAgICAgci5yZWRyYXcoKTsgLy8gcGluY2ggdG8gem9vbVxuICAgICAgfSBlbHNlIGlmIChjYXB0dXJlICYmIGUudG91Y2hlc1sxXSAmJiAhci50b3VjaERhdGEuZGlkU2VsZWN0IC8vIGRvbid0IGFsbG93IGJveCBzZWxlY3Rpb24gdG8gZGVncmFkZSB0byBwaW5jaC10by16b29tXG4gICAgICAmJiBjeS56b29taW5nRW5hYmxlZCgpICYmIGN5LnBhbm5pbmdFbmFibGVkKCkgJiYgY3kudXNlclpvb21pbmdFbmFibGVkKCkgJiYgY3kudXNlclBhbm5pbmdFbmFibGVkKCkpIHtcbiAgICAgICAgLy8gdHdvIGZpbmdlcnMgPT4gcGluY2ggdG8gem9vbVxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHIuZGF0YS5iZ0FjdGl2ZVBvc2lzdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgci5yZWRyYXdIaW50KCdzZWxlY3QnLCB0cnVlKTtcbiAgICAgICAgdmFyIGRyYWdnZWRFbGVzID0gci5kcmFnRGF0YS50b3VjaERyYWdFbGVzO1xuXG4gICAgICAgIGlmIChkcmFnZ2VkRWxlcykge1xuICAgICAgICAgIHIucmVkcmF3SGludCgnZHJhZycsIHRydWUpO1xuXG4gICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkcmFnZ2VkRWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGRlX3AgPSBkcmFnZ2VkRWxlc1tpXS5fcHJpdmF0ZTtcbiAgICAgICAgICAgIGRlX3AuZ3JhYmJlZCA9IGZhbHNlO1xuICAgICAgICAgICAgZGVfcC5yc2NyYXRjaC5pbkRyYWdMYXllciA9IGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBfc3RhcnQgPSByLnRvdWNoRGF0YS5zdGFydDsgLy8gKHgyLCB5MikgZm9yIGZpbmdlcnMgMSBhbmQgMlxuXG4gICAgICAgIHZhciBmMXgyID0gZS50b3VjaGVzWzBdLmNsaWVudFggLSBvZmZzZXRMZWZ0LFxuICAgICAgICAgICAgZjF5MiA9IGUudG91Y2hlc1swXS5jbGllbnRZIC0gb2Zmc2V0VG9wO1xuICAgICAgICB2YXIgZjJ4MiA9IGUudG91Y2hlc1sxXS5jbGllbnRYIC0gb2Zmc2V0TGVmdCxcbiAgICAgICAgICAgIGYyeTIgPSBlLnRvdWNoZXNbMV0uY2xpZW50WSAtIG9mZnNldFRvcDtcbiAgICAgICAgdmFyIGRpc3RhbmNlMiA9IGRpc3RhbmNlKGYxeDIsIGYxeTIsIGYyeDIsIGYyeTIpOyAvLyB2YXIgZGlzdGFuY2UyU3EgPSBkaXN0YW5jZVNxKCBmMXgyLCBmMXkyLCBmMngyLCBmMnkyICk7XG4gICAgICAgIC8vIHZhciBmYWN0b3IgPSBNYXRoLnNxcnQoIGRpc3RhbmNlMlNxICkgLyBNYXRoLnNxcnQoIGRpc3RhbmNlMVNxICk7XG5cbiAgICAgICAgdmFyIGZhY3RvciA9IGRpc3RhbmNlMiAvIGRpc3RhbmNlMTtcblxuICAgICAgICBpZiAodHdvRmluZ2Vyc1N0YXJ0SW5zaWRlKSB7XG4gICAgICAgICAgLy8gZGVsdGEgZmluZ2VyMVxuICAgICAgICAgIHZhciBkZjF4ID0gZjF4MiAtIGYxeDE7XG4gICAgICAgICAgdmFyIGRmMXkgPSBmMXkyIC0gZjF5MTsgLy8gZGVsdGEgZmluZ2VyIDJcblxuICAgICAgICAgIHZhciBkZjJ4ID0gZjJ4MiAtIGYyeDE7XG4gICAgICAgICAgdmFyIGRmMnkgPSBmMnkyIC0gZjJ5MTsgLy8gdHJhbnNsYXRpb24gaXMgdGhlIG5vcm1hbGlzZWQgdmVjdG9yIG9mIHRoZSB0d28gZmluZ2VycyBtb3ZlbWVudFxuICAgICAgICAgIC8vIGkuZS4gc28gcGluY2hpbmcgY2FuY2VscyBvdXQgYW5kIG1vdmluZyB0b2dldGhlciBwYW5zXG5cbiAgICAgICAgICB2YXIgdHggPSAoZGYxeCArIGRmMngpIC8gMjtcbiAgICAgICAgICB2YXIgdHkgPSAoZGYxeSArIGRmMnkpIC8gMjsgLy8gbm93IGNhbGN1bGF0ZSB0aGUgem9vbVxuXG4gICAgICAgICAgdmFyIHpvb20xID0gY3kuem9vbSgpO1xuICAgICAgICAgIHZhciB6b29tMiA9IHpvb20xICogZmFjdG9yO1xuICAgICAgICAgIHZhciBwYW4xID0gY3kucGFuKCk7IC8vIHRoZSBtb2RlbCBjZW50ZXIgcG9pbnQgY29udmVydGVkIHRvIHRoZSBjdXJyZW50IHJlbmRlcmVkIHBvc1xuXG4gICAgICAgICAgdmFyIGN0cnggPSBtb2RlbENlbnRlcjFbMF0gKiB6b29tMSArIHBhbjEueDtcbiAgICAgICAgICB2YXIgY3RyeSA9IG1vZGVsQ2VudGVyMVsxXSAqIHpvb20xICsgcGFuMS55O1xuICAgICAgICAgIHZhciBwYW4yID0ge1xuICAgICAgICAgICAgeDogLXpvb20yIC8gem9vbTEgKiAoY3RyeCAtIHBhbjEueCAtIHR4KSArIGN0cngsXG4gICAgICAgICAgICB5OiAtem9vbTIgLyB6b29tMSAqIChjdHJ5IC0gcGFuMS55IC0gdHkpICsgY3RyeVxuICAgICAgICAgIH07IC8vIHJlbW92ZSBkcmFnZ2VkIGVsZXNcblxuICAgICAgICAgIGlmIChfc3RhcnQgJiYgX3N0YXJ0LmFjdGl2ZSgpKSB7XG4gICAgICAgICAgICB2YXIgZHJhZ2dlZEVsZXMgPSByLmRyYWdEYXRhLnRvdWNoRHJhZ0VsZXM7XG4gICAgICAgICAgICBmcmVlRHJhZ2dlZEVsZW1lbnRzKGRyYWdnZWRFbGVzKTtcbiAgICAgICAgICAgIHIucmVkcmF3SGludCgnZHJhZycsIHRydWUpO1xuICAgICAgICAgICAgci5yZWRyYXdIaW50KCdlbGVzJywgdHJ1ZSk7XG5cbiAgICAgICAgICAgIF9zdGFydC51bmFjdGl2YXRlKCkuZW1pdCgnZnJlZW9uJyk7XG5cbiAgICAgICAgICAgIGRyYWdnZWRFbGVzLmVtaXQoJ2ZyZWUnKTtcblxuICAgICAgICAgICAgaWYgKHIuZHJhZ0RhdGEuZGlkRHJhZykge1xuICAgICAgICAgICAgICBfc3RhcnQuZW1pdCgnZHJhZ2ZyZWVvbicpO1xuXG4gICAgICAgICAgICAgIGRyYWdnZWRFbGVzLmVtaXQoJ2RyYWdmcmVlJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY3kudmlld3BvcnQoe1xuICAgICAgICAgICAgem9vbTogem9vbTIsXG4gICAgICAgICAgICBwYW46IHBhbjIsXG4gICAgICAgICAgICBjYW5jZWxPbkZhaWxlZFpvb206IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBjeS5lbWl0KCdwaW5jaHpvb20nKTtcbiAgICAgICAgICBkaXN0YW5jZTEgPSBkaXN0YW5jZTI7XG4gICAgICAgICAgZjF4MSA9IGYxeDI7XG4gICAgICAgICAgZjF5MSA9IGYxeTI7XG4gICAgICAgICAgZjJ4MSA9IGYyeDI7XG4gICAgICAgICAgZjJ5MSA9IGYyeTI7XG4gICAgICAgICAgci5waW5jaGluZyA9IHRydWU7XG4gICAgICAgIH0gLy8gUmUtcHJvamVjdFxuXG5cbiAgICAgICAgaWYgKGUudG91Y2hlc1swXSkge1xuICAgICAgICAgIHZhciBwb3MgPSByLnByb2plY3RJbnRvVmlld3BvcnQoZS50b3VjaGVzWzBdLmNsaWVudFgsIGUudG91Y2hlc1swXS5jbGllbnRZKTtcbiAgICAgICAgICBub3dbMF0gPSBwb3NbMF07XG4gICAgICAgICAgbm93WzFdID0gcG9zWzFdO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGUudG91Y2hlc1sxXSkge1xuICAgICAgICAgIHZhciBwb3MgPSByLnByb2plY3RJbnRvVmlld3BvcnQoZS50b3VjaGVzWzFdLmNsaWVudFgsIGUudG91Y2hlc1sxXS5jbGllbnRZKTtcbiAgICAgICAgICBub3dbMl0gPSBwb3NbMF07XG4gICAgICAgICAgbm93WzNdID0gcG9zWzFdO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGUudG91Y2hlc1syXSkge1xuICAgICAgICAgIHZhciBwb3MgPSByLnByb2plY3RJbnRvVmlld3BvcnQoZS50b3VjaGVzWzJdLmNsaWVudFgsIGUudG91Y2hlc1syXS5jbGllbnRZKTtcbiAgICAgICAgICBub3dbNF0gPSBwb3NbMF07XG4gICAgICAgICAgbm93WzVdID0gcG9zWzFdO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGUudG91Y2hlc1swXSAmJiAhci50b3VjaERhdGEuZGlkU2VsZWN0IC8vIGRvbid0IGFsbG93IGJveCBzZWxlY3Rpb24gdG8gZGVncmFkZSB0byBzaW5nbGUgZmluZ2VyIGV2ZW50cyBsaWtlIHBhbm5pbmdcbiAgICAgICkge1xuICAgICAgICB2YXIgc3RhcnQgPSByLnRvdWNoRGF0YS5zdGFydDtcbiAgICAgICAgdmFyIGxhc3QgPSByLnRvdWNoRGF0YS5sYXN0O1xuICAgICAgICB2YXIgbmVhcjtcblxuICAgICAgICBpZiAoIXIuaG92ZXJEYXRhLmRyYWdnaW5nRWxlcyAmJiAhci5zd2lwZVBhbm5pbmcpIHtcbiAgICAgICAgICBuZWFyID0gci5maW5kTmVhcmVzdEVsZW1lbnQobm93WzBdLCBub3dbMV0sIHRydWUsIHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNhcHR1cmUgJiYgc3RhcnQgIT0gbnVsbCkge1xuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfSAvLyBkcmFnZ2luZyBub2Rlc1xuXG5cbiAgICAgICAgaWYgKGNhcHR1cmUgJiYgc3RhcnQgIT0gbnVsbCAmJiByLm5vZGVJc0RyYWdnYWJsZShzdGFydCkpIHtcbiAgICAgICAgICBpZiAoaXNPdmVyVGhyZXNob2xkRHJhZykge1xuICAgICAgICAgICAgLy8gdGhlbiBkcmFnZ2luZyBjYW4gaGFwcGVuXG4gICAgICAgICAgICB2YXIgZHJhZ2dlZEVsZXMgPSByLmRyYWdEYXRhLnRvdWNoRHJhZ0VsZXM7XG4gICAgICAgICAgICB2YXIganVzdFN0YXJ0ZWREcmFnID0gIXIuZHJhZ0RhdGEuZGlkRHJhZztcblxuICAgICAgICAgICAgaWYgKGp1c3RTdGFydGVkRHJhZykge1xuICAgICAgICAgICAgICBhZGROb2Rlc1RvRHJhZyhkcmFnZ2VkRWxlcywge1xuICAgICAgICAgICAgICAgIGluRHJhZ0xheWVyOiB0cnVlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByLmRyYWdEYXRhLmRpZERyYWcgPSB0cnVlO1xuICAgICAgICAgICAgdmFyIHRvdGFsU2hpZnQgPSB7XG4gICAgICAgICAgICAgIHg6IDAsXG4gICAgICAgICAgICAgIHk6IDBcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmIChudW1iZXIkMShkaXNwWzBdKSAmJiBudW1iZXIkMShkaXNwWzFdKSkge1xuICAgICAgICAgICAgICB0b3RhbFNoaWZ0LnggKz0gZGlzcFswXTtcbiAgICAgICAgICAgICAgdG90YWxTaGlmdC55ICs9IGRpc3BbMV07XG5cbiAgICAgICAgICAgICAgaWYgKGp1c3RTdGFydGVkRHJhZykge1xuICAgICAgICAgICAgICAgIHIucmVkcmF3SGludCgnZWxlcycsIHRydWUpO1xuICAgICAgICAgICAgICAgIHZhciBkcmFnRGVsdGEgPSByLnRvdWNoRGF0YS5kcmFnRGVsdGE7XG5cbiAgICAgICAgICAgICAgICBpZiAoZHJhZ0RlbHRhICYmIG51bWJlciQxKGRyYWdEZWx0YVswXSkgJiYgbnVtYmVyJDEoZHJhZ0RlbHRhWzFdKSkge1xuICAgICAgICAgICAgICAgICAgdG90YWxTaGlmdC54ICs9IGRyYWdEZWx0YVswXTtcbiAgICAgICAgICAgICAgICAgIHRvdGFsU2hpZnQueSArPSBkcmFnRGVsdGFbMV07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHIuaG92ZXJEYXRhLmRyYWdnaW5nRWxlcyA9IHRydWU7XG4gICAgICAgICAgICBkcmFnZ2VkRWxlcy5zaWxlbnRTaGlmdCh0b3RhbFNoaWZ0KS5lbWl0KCdwb3NpdGlvbiBkcmFnJyk7XG4gICAgICAgICAgICByLnJlZHJhd0hpbnQoJ2RyYWcnLCB0cnVlKTtcblxuICAgICAgICAgICAgaWYgKHIudG91Y2hEYXRhLnN0YXJ0UG9zaXRpb25bMF0gPT0gZWFybGllclswXSAmJiByLnRvdWNoRGF0YS5zdGFydFBvc2l0aW9uWzFdID09IGVhcmxpZXJbMV0pIHtcbiAgICAgICAgICAgICAgci5yZWRyYXdIaW50KCdlbGVzJywgdHJ1ZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHIucmVkcmF3KCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSBrZWVwIHRyYWNrIG9mIGRyYWcgZGVsdGEgZm9yIGxhdGVyXG4gICAgICAgICAgICB2YXIgZHJhZ0RlbHRhID0gci50b3VjaERhdGEuZHJhZ0RlbHRhID0gci50b3VjaERhdGEuZHJhZ0RlbHRhIHx8IFtdO1xuXG4gICAgICAgICAgICBpZiAoZHJhZ0RlbHRhLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICBkcmFnRGVsdGEucHVzaChkaXNwWzBdKTtcbiAgICAgICAgICAgICAgZHJhZ0RlbHRhLnB1c2goZGlzcFsxXSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBkcmFnRGVsdGFbMF0gKz0gZGlzcFswXTtcbiAgICAgICAgICAgICAgZHJhZ0RlbHRhWzFdICs9IGRpc3BbMV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IC8vIHRvdWNobW92ZVxuXG5cbiAgICAgICAge1xuICAgICAgICAgIHRyaWdnZXJFdmVudHMoc3RhcnQgfHwgbmVhciwgWyd0b3VjaG1vdmUnLCAndGFwZHJhZycsICd2bW91c2Vtb3ZlJ10sIGUsIHtcbiAgICAgICAgICAgIHg6IG5vd1swXSxcbiAgICAgICAgICAgIHk6IG5vd1sxXVxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKCghc3RhcnQgfHwgIXN0YXJ0LmdyYWJiZWQoKSkgJiYgbmVhciAhPSBsYXN0KSB7XG4gICAgICAgICAgICBpZiAobGFzdCkge1xuICAgICAgICAgICAgICBsYXN0LmVtaXQoe1xuICAgICAgICAgICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgICAgICAgICAgdHlwZTogJ3RhcGRyYWdvdXQnLFxuICAgICAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgICAgICAgICB5OiBub3dbMV1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAobmVhcikge1xuICAgICAgICAgICAgICBuZWFyLmVtaXQoe1xuICAgICAgICAgICAgICAgIG9yaWdpbmFsRXZlbnQ6IGUsXG4gICAgICAgICAgICAgICAgdHlwZTogJ3RhcGRyYWdvdmVyJyxcbiAgICAgICAgICAgICAgICBwb3NpdGlvbjoge1xuICAgICAgICAgICAgICAgICAgeDogbm93WzBdLFxuICAgICAgICAgICAgICAgICAgeTogbm93WzFdXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICByLnRvdWNoRGF0YS5sYXN0ID0gbmVhcjtcbiAgICAgICAgfSAvLyBjaGVjayB0byBjYW5jZWwgdGFwaG9sZFxuXG4gICAgICAgIGlmIChjYXB0dXJlKSB7XG4gICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub3cubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChub3dbaV0gJiYgci50b3VjaERhdGEuc3RhcnRQb3NpdGlvbltpXSAmJiBpc092ZXJUaHJlc2hvbGREcmFnKSB7XG4gICAgICAgICAgICAgIHIudG91Y2hEYXRhLnNpbmdsZVRvdWNoTW92ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSAvLyBwYW5uaW5nXG5cblxuICAgICAgICBpZiAoY2FwdHVyZSAmJiAoc3RhcnQgPT0gbnVsbCB8fCBzdGFydC5wYW5uYWJsZSgpKSAmJiBjeS5wYW5uaW5nRW5hYmxlZCgpICYmIGN5LnVzZXJQYW5uaW5nRW5hYmxlZCgpKSB7XG4gICAgICAgICAgdmFyIGFsbG93UGFzc3Rocm91Z2ggPSBhbGxvd1Bhbm5pbmdQYXNzdGhyb3VnaChzdGFydCwgci50b3VjaERhdGEuc3RhcnRzKTtcblxuICAgICAgICAgIGlmIChhbGxvd1Bhc3N0aHJvdWdoKSB7XG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgICAgIGlmICghci5kYXRhLmJnQWN0aXZlUG9zaXN0aW9uKSB7XG4gICAgICAgICAgICAgIHIuZGF0YS5iZ0FjdGl2ZVBvc2lzdGlvbiA9IGFycmF5MnBvaW50KHIudG91Y2hEYXRhLnN0YXJ0UG9zaXRpb24pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoci5zd2lwZVBhbm5pbmcpIHtcbiAgICAgICAgICAgICAgY3kucGFuQnkoe1xuICAgICAgICAgICAgICAgIHg6IGRpc3BbMF0gKiB6b29tLFxuICAgICAgICAgICAgICAgIHk6IGRpc3BbMV0gKiB6b29tXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICBjeS5lbWl0KCdkcmFncGFuJyk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGlzT3ZlclRocmVzaG9sZERyYWcpIHtcbiAgICAgICAgICAgICAgci5zd2lwZVBhbm5pbmcgPSB0cnVlO1xuICAgICAgICAgICAgICBjeS5wYW5CeSh7XG4gICAgICAgICAgICAgICAgeDogZHggKiB6b29tLFxuICAgICAgICAgICAgICAgIHk6IGR5ICogem9vbVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgY3kuZW1pdCgnZHJhZ3BhbicpO1xuXG4gICAgICAgICAgICAgIGlmIChzdGFydCkge1xuICAgICAgICAgICAgICAgIHN0YXJ0LnVuYWN0aXZhdGUoKTtcbiAgICAgICAgICAgICAgICByLnJlZHJhd0hpbnQoJ3NlbGVjdCcsIHRydWUpO1xuICAgICAgICAgICAgICAgIHIudG91Y2hEYXRhLnN0YXJ0ID0gbnVsbDtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gUmUtcHJvamVjdFxuXG5cbiAgICAgICAgICB2YXIgcG9zID0gci5wcm9qZWN0SW50b1ZpZXdwb3J0KGUudG91Y2hlc1swXS5jbGllbnRYLCBlLnRvdWNoZXNbMF0uY2xpZW50WSk7XG4gICAgICAgICAgbm93WzBdID0gcG9zWzBdO1xuICAgICAgICAgIG5vd1sxXSA9IHBvc1sxXTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IG5vdy5sZW5ndGg7IGorKykge1xuICAgICAgICBlYXJsaWVyW2pdID0gbm93W2pdO1xuICAgICAgfSAvLyB0aGUgYWN0aXZlIGJnIGluZGljYXRvciBzaG91bGQgYmUgcmVtb3ZlZCB3aGVuIG1ha2luZyBhIHN3aXBlIHRoYXQgaXMgbmVpdGhlciBmb3IgZHJhZ2dpbmcgbm9kZXMgb3IgcGFubmluZ1xuXG5cbiAgICAgIGlmIChjYXB0dXJlICYmIGUudG91Y2hlcy5sZW5ndGggPiAwICYmICFyLmhvdmVyRGF0YS5kcmFnZ2luZ0VsZXMgJiYgIXIuc3dpcGVQYW5uaW5nICYmIHIuZGF0YS5iZ0FjdGl2ZVBvc2lzdGlvbiAhPSBudWxsKSB7XG4gICAgICAgIHIuZGF0YS5iZ0FjdGl2ZVBvc2lzdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgci5yZWRyYXdIaW50KCdzZWxlY3QnLCB0cnVlKTtcbiAgICAgICAgci5yZWRyYXcoKTtcbiAgICAgIH1cbiAgICB9LCBmYWxzZSk7XG4gICAgdmFyIHRvdWNoY2FuY2VsSGFuZGxlcjtcbiAgICByLnJlZ2lzdGVyQmluZGluZyhjb250YWluZXJXaW5kb3csICd0b3VjaGNhbmNlbCcsIHRvdWNoY2FuY2VsSGFuZGxlciA9IGZ1bmN0aW9uIHRvdWNoY2FuY2VsSGFuZGxlcihlKSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gICAgICB2YXIgc3RhcnQgPSByLnRvdWNoRGF0YS5zdGFydDtcbiAgICAgIHIudG91Y2hEYXRhLmNhcHR1cmUgPSBmYWxzZTtcblxuICAgICAgaWYgKHN0YXJ0KSB7XG4gICAgICAgIHN0YXJ0LnVuYWN0aXZhdGUoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB2YXIgdG91Y2hlbmRIYW5kbGVyLCBkaWREb3VibGVUb3VjaCwgdG91Y2hUaW1lb3V0LCBwcmV2VG91Y2hUaW1lU3RhbXA7XG4gICAgci5yZWdpc3RlckJpbmRpbmcoY29udGFpbmVyV2luZG93LCAndG91Y2hlbmQnLCB0b3VjaGVuZEhhbmRsZXIgPSBmdW5jdGlvbiB0b3VjaGVuZEhhbmRsZXIoZSkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICAgICAgdmFyIHN0YXJ0ID0gci50b3VjaERhdGEuc3RhcnQ7XG4gICAgICB2YXIgY2FwdHVyZSA9IHIudG91Y2hEYXRhLmNhcHR1cmU7XG5cbiAgICAgIGlmIChjYXB0dXJlKSB7XG4gICAgICAgIGlmIChlLnRvdWNoZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgci50b3VjaERhdGEuY2FwdHVyZSA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgc2VsZWN0ID0gci5zZWxlY3Rpb247XG4gICAgICByLnN3aXBlUGFubmluZyA9IGZhbHNlO1xuICAgICAgci5ob3ZlckRhdGEuZHJhZ2dpbmdFbGVzID0gZmFsc2U7XG4gICAgICB2YXIgY3kgPSByLmN5O1xuICAgICAgdmFyIHpvb20gPSBjeS56b29tKCk7XG4gICAgICB2YXIgbm93ID0gci50b3VjaERhdGEubm93O1xuICAgICAgdmFyIGVhcmxpZXIgPSByLnRvdWNoRGF0YS5lYXJsaWVyO1xuXG4gICAgICBpZiAoZS50b3VjaGVzWzBdKSB7XG4gICAgICAgIHZhciBwb3MgPSByLnByb2plY3RJbnRvVmlld3BvcnQoZS50b3VjaGVzWzBdLmNsaWVudFgsIGUudG91Y2hlc1swXS5jbGllbnRZKTtcbiAgICAgICAgbm93WzBdID0gcG9zWzBdO1xuICAgICAgICBub3dbMV0gPSBwb3NbMV07XG4gICAgICB9XG5cbiAgICAgIGlmIChlLnRvdWNoZXNbMV0pIHtcbiAgICAgICAgdmFyIHBvcyA9IHIucHJvamVjdEludG9WaWV3cG9ydChlLnRvdWNoZXNbMV0uY2xpZW50WCwgZS50b3VjaGVzWzFdLmNsaWVudFkpO1xuICAgICAgICBub3dbMl0gPSBwb3NbMF07XG4gICAgICAgIG5vd1szXSA9IHBvc1sxXTtcbiAgICAgIH1cblxuICAgICAgaWYgKGUudG91Y2hlc1syXSkge1xuICAgICAgICB2YXIgcG9zID0gci5wcm9qZWN0SW50b1ZpZXdwb3J0KGUudG91Y2hlc1syXS5jbGllbnRYLCBlLnRvdWNoZXNbMl0uY2xpZW50WSk7XG4gICAgICAgIG5vd1s0XSA9IHBvc1swXTtcbiAgICAgICAgbm93WzVdID0gcG9zWzFdO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3RhcnQpIHtcbiAgICAgICAgc3RhcnQudW5hY3RpdmF0ZSgpO1xuICAgICAgfVxuXG4gICAgICB2YXIgY3R4VGFwZW5kO1xuXG4gICAgICBpZiAoci50b3VjaERhdGEuY3h0KSB7XG4gICAgICAgIGN0eFRhcGVuZCA9IHtcbiAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgIHR5cGU6ICdjeHR0YXBlbmQnLFxuICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgICB5OiBub3dbMV1cbiAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKHN0YXJ0KSB7XG4gICAgICAgICAgc3RhcnQuZW1pdChjdHhUYXBlbmQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGN5LmVtaXQoY3R4VGFwZW5kKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghci50b3VjaERhdGEuY3h0RHJhZ2dlZCkge1xuICAgICAgICAgIHZhciBjdHhUYXAgPSB7XG4gICAgICAgICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgICAgICAgICAgdHlwZTogJ2N4dHRhcCcsXG4gICAgICAgICAgICBwb3NpdGlvbjoge1xuICAgICAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgICAgIHk6IG5vd1sxXVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH07XG5cbiAgICAgICAgICBpZiAoc3RhcnQpIHtcbiAgICAgICAgICAgIHN0YXJ0LmVtaXQoY3R4VGFwKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY3kuZW1pdChjdHhUYXApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyLnRvdWNoRGF0YS5zdGFydCkge1xuICAgICAgICAgIHIudG91Y2hEYXRhLnN0YXJ0Ll9wcml2YXRlLmdyYWJiZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHIudG91Y2hEYXRhLmN4dCA9IGZhbHNlO1xuICAgICAgICByLnRvdWNoRGF0YS5zdGFydCA9IG51bGw7XG4gICAgICAgIHIucmVkcmF3KCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gbm8gbW9yZSBib3ggc2VsZWN0aW9uIGlmIHdlIGRvbid0IGhhdmUgdGhyZWUgZmluZ2Vyc1xuXG5cbiAgICAgIGlmICghZS50b3VjaGVzWzJdICYmIGN5LmJveFNlbGVjdGlvbkVuYWJsZWQoKSAmJiByLnRvdWNoRGF0YS5zZWxlY3RpbmcpIHtcbiAgICAgICAgci50b3VjaERhdGEuc2VsZWN0aW5nID0gZmFsc2U7XG4gICAgICAgIHZhciBib3ggPSBjeS5jb2xsZWN0aW9uKHIuZ2V0QWxsSW5Cb3goc2VsZWN0WzBdLCBzZWxlY3RbMV0sIHNlbGVjdFsyXSwgc2VsZWN0WzNdKSk7XG4gICAgICAgIHNlbGVjdFswXSA9IHVuZGVmaW5lZDtcbiAgICAgICAgc2VsZWN0WzFdID0gdW5kZWZpbmVkO1xuICAgICAgICBzZWxlY3RbMl0gPSB1bmRlZmluZWQ7XG4gICAgICAgIHNlbGVjdFszXSA9IHVuZGVmaW5lZDtcbiAgICAgICAgc2VsZWN0WzRdID0gMDtcbiAgICAgICAgci5yZWRyYXdIaW50KCdzZWxlY3QnLCB0cnVlKTtcbiAgICAgICAgY3kuZW1pdCh7XG4gICAgICAgICAgdHlwZTogJ2JveGVuZCcsXG4gICAgICAgICAgb3JpZ2luYWxFdmVudDogZSxcbiAgICAgICAgICBwb3NpdGlvbjoge1xuICAgICAgICAgICAgeDogbm93WzBdLFxuICAgICAgICAgICAgeTogbm93WzFdXG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICB2YXIgZWxlV291bGRCZVNlbGVjdGVkID0gZnVuY3Rpb24gZWxlV291bGRCZVNlbGVjdGVkKGVsZSkge1xuICAgICAgICAgIHJldHVybiBlbGUuc2VsZWN0YWJsZSgpICYmICFlbGUuc2VsZWN0ZWQoKTtcbiAgICAgICAgfTtcblxuICAgICAgICBib3guZW1pdCgnYm94Jykuc3RkRmlsdGVyKGVsZVdvdWxkQmVTZWxlY3RlZCkuc2VsZWN0KCkuZW1pdCgnYm94c2VsZWN0Jyk7XG5cbiAgICAgICAgaWYgKGJveC5ub25lbXB0eSgpKSB7XG4gICAgICAgICAgci5yZWRyYXdIaW50KCdlbGVzJywgdHJ1ZSk7XG4gICAgICAgIH1cblxuICAgICAgICByLnJlZHJhdygpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3RhcnQgIT0gbnVsbCkge1xuICAgICAgICBzdGFydC51bmFjdGl2YXRlKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlLnRvdWNoZXNbMl0pIHtcbiAgICAgICAgci5kYXRhLmJnQWN0aXZlUG9zaXN0aW9uID0gdW5kZWZpbmVkO1xuICAgICAgICByLnJlZHJhd0hpbnQoJ3NlbGVjdCcsIHRydWUpO1xuICAgICAgfSBlbHNlIGlmIChlLnRvdWNoZXNbMV0pIDsgZWxzZSBpZiAoZS50b3VjaGVzWzBdKSA7IGVsc2UgaWYgKCFlLnRvdWNoZXNbMF0pIHtcbiAgICAgICAgci5kYXRhLmJnQWN0aXZlUG9zaXN0aW9uID0gdW5kZWZpbmVkO1xuICAgICAgICByLnJlZHJhd0hpbnQoJ3NlbGVjdCcsIHRydWUpO1xuICAgICAgICB2YXIgZHJhZ2dlZEVsZXMgPSByLmRyYWdEYXRhLnRvdWNoRHJhZ0VsZXM7XG5cbiAgICAgICAgaWYgKHN0YXJ0ICE9IG51bGwpIHtcbiAgICAgICAgICB2YXIgc3RhcnRXYXNHcmFiYmVkID0gc3RhcnQuX3ByaXZhdGUuZ3JhYmJlZDtcbiAgICAgICAgICBmcmVlRHJhZ2dlZEVsZW1lbnRzKGRyYWdnZWRFbGVzKTtcbiAgICAgICAgICByLnJlZHJhd0hpbnQoJ2RyYWcnLCB0cnVlKTtcbiAgICAgICAgICByLnJlZHJhd0hpbnQoJ2VsZXMnLCB0cnVlKTtcblxuICAgICAgICAgIGlmIChzdGFydFdhc0dyYWJiZWQpIHtcbiAgICAgICAgICAgIHN0YXJ0LmVtaXQoJ2ZyZWVvbicpO1xuICAgICAgICAgICAgZHJhZ2dlZEVsZXMuZW1pdCgnZnJlZScpO1xuXG4gICAgICAgICAgICBpZiAoci5kcmFnRGF0YS5kaWREcmFnKSB7XG4gICAgICAgICAgICAgIHN0YXJ0LmVtaXQoJ2RyYWdmcmVlb24nKTtcbiAgICAgICAgICAgICAgZHJhZ2dlZEVsZXMuZW1pdCgnZHJhZ2ZyZWUnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0cmlnZ2VyRXZlbnRzKHN0YXJ0LCBbJ3RvdWNoZW5kJywgJ3RhcGVuZCcsICd2bW91c2V1cCcsICd0YXBkcmFnb3V0J10sIGUsIHtcbiAgICAgICAgICAgIHg6IG5vd1swXSxcbiAgICAgICAgICAgIHk6IG5vd1sxXVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHN0YXJ0LnVuYWN0aXZhdGUoKTtcbiAgICAgICAgICByLnRvdWNoRGF0YS5zdGFydCA9IG51bGw7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmFyIG5lYXIgPSByLmZpbmROZWFyZXN0RWxlbWVudChub3dbMF0sIG5vd1sxXSwgdHJ1ZSwgdHJ1ZSk7XG4gICAgICAgICAgdHJpZ2dlckV2ZW50cyhuZWFyLCBbJ3RvdWNoZW5kJywgJ3RhcGVuZCcsICd2bW91c2V1cCcsICd0YXBkcmFnb3V0J10sIGUsIHtcbiAgICAgICAgICAgIHg6IG5vd1swXSxcbiAgICAgICAgICAgIHk6IG5vd1sxXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGR4ID0gci50b3VjaERhdGEuc3RhcnRQb3NpdGlvblswXSAtIG5vd1swXTtcbiAgICAgICAgdmFyIGR4MiA9IGR4ICogZHg7XG4gICAgICAgIHZhciBkeSA9IHIudG91Y2hEYXRhLnN0YXJ0UG9zaXRpb25bMV0gLSBub3dbMV07XG4gICAgICAgIHZhciBkeTIgPSBkeSAqIGR5O1xuICAgICAgICB2YXIgZGlzdDIgPSBkeDIgKyBkeTI7XG4gICAgICAgIHZhciByZGlzdDIgPSBkaXN0MiAqIHpvb20gKiB6b29tOyAvLyBUYXAgZXZlbnQsIHJvdWdobHkgc2FtZSBhcyBtb3VzZSBjbGljayBldmVudCBmb3IgdG91Y2hcblxuICAgICAgICBpZiAoIXIudG91Y2hEYXRhLnNpbmdsZVRvdWNoTW92ZWQpIHtcbiAgICAgICAgICBpZiAoIXN0YXJ0KSB7XG4gICAgICAgICAgICBjeS4kKCc6c2VsZWN0ZWQnKS51bnNlbGVjdChbJ3RhcHVuc2VsZWN0J10pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRyaWdnZXJFdmVudHMoc3RhcnQsIFsndGFwJywgJ3ZjbGljayddLCBlLCB7XG4gICAgICAgICAgICB4OiBub3dbMF0sXG4gICAgICAgICAgICB5OiBub3dbMV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICBkaWREb3VibGVUb3VjaCA9IGZhbHNlO1xuXG4gICAgICAgICAgaWYgKGUudGltZVN0YW1wIC0gcHJldlRvdWNoVGltZVN0YW1wIDw9IGN5Lm11bHRpQ2xpY2tEZWJvdW5jZVRpbWUoKSkge1xuICAgICAgICAgICAgdG91Y2hUaW1lb3V0ICYmIGNsZWFyVGltZW91dCh0b3VjaFRpbWVvdXQpO1xuICAgICAgICAgICAgZGlkRG91YmxlVG91Y2ggPSB0cnVlO1xuICAgICAgICAgICAgcHJldlRvdWNoVGltZVN0YW1wID0gbnVsbDtcbiAgICAgICAgICAgIHRyaWdnZXJFdmVudHMoc3RhcnQsIFsnZGJsdGFwJywgJ3ZkYmxjbGljayddLCBlLCB7XG4gICAgICAgICAgICAgIHg6IG5vd1swXSxcbiAgICAgICAgICAgICAgeTogbm93WzFdXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdG91Y2hUaW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgIGlmIChkaWREb3VibGVUb3VjaCkgcmV0dXJuO1xuICAgICAgICAgICAgICB0cmlnZ2VyRXZlbnRzKHN0YXJ0LCBbJ29uZXRhcCcsICd2b25lY2xpY2snXSwgZSwge1xuICAgICAgICAgICAgICAgIHg6IG5vd1swXSxcbiAgICAgICAgICAgICAgICB5OiBub3dbMV1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LCBjeS5tdWx0aUNsaWNrRGVib3VuY2VUaW1lKCkpO1xuICAgICAgICAgICAgcHJldlRvdWNoVGltZVN0YW1wID0gZS50aW1lU3RhbXA7XG4gICAgICAgICAgfVxuICAgICAgICB9IC8vIFByZXBhcmUgdG8gc2VsZWN0IHRoZSBjdXJyZW50bHkgdG91Y2hlZCBub2RlLCBvbmx5IGlmIGl0IGhhc24ndCBiZWVuIGRyYWdnZWQgcGFzdCBhIGNlcnRhaW4gZGlzdGFuY2VcblxuXG4gICAgICAgIGlmIChzdGFydCAhPSBudWxsICYmICFyLmRyYWdEYXRhLmRpZERyYWcgLy8gZGlkbid0IGRyYWcgbm9kZXMgYXJvdW5kXG4gICAgICAgICYmIHN0YXJ0Ll9wcml2YXRlLnNlbGVjdGFibGUgJiYgcmRpc3QyIDwgci50b3VjaFRhcFRocmVzaG9sZDIgJiYgIXIucGluY2hpbmcgLy8gcGluY2ggdG8gem9vbSBzaG91bGQgbm90IGFmZmVjdCBzZWxlY3Rpb25cbiAgICAgICAgKSB7XG4gICAgICAgICAgaWYgKGN5LnNlbGVjdGlvblR5cGUoKSA9PT0gJ3NpbmdsZScpIHtcbiAgICAgICAgICAgIGN5LiQoaXNTZWxlY3RlZCkudW5tZXJnZShzdGFydCkudW5zZWxlY3QoWyd0YXB1bnNlbGVjdCddKTtcbiAgICAgICAgICAgIHN0YXJ0LnNlbGVjdChbJ3RhcHNlbGVjdCddKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKHN0YXJ0LnNlbGVjdGVkKCkpIHtcbiAgICAgICAgICAgICAgc3RhcnQudW5zZWxlY3QoWyd0YXB1bnNlbGVjdCddKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHN0YXJ0LnNlbGVjdChbJ3RhcHNlbGVjdCddKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICByLnJlZHJhd0hpbnQoJ2VsZXMnLCB0cnVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHIudG91Y2hEYXRhLnNpbmdsZVRvdWNoTW92ZWQgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IG5vdy5sZW5ndGg7IGorKykge1xuICAgICAgICBlYXJsaWVyW2pdID0gbm93W2pdO1xuICAgICAgfVxuXG4gICAgICByLmRyYWdEYXRhLmRpZERyYWcgPSBmYWxzZTsgLy8gcmVzZXQgZm9yIG5leHQgdG91Y2hzdGFydFxuXG4gICAgICBpZiAoZS50b3VjaGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByLnRvdWNoRGF0YS5kcmFnRGVsdGEgPSBbXTtcbiAgICAgICAgci50b3VjaERhdGEuc3RhcnRQb3NpdGlvbiA9IFtudWxsLCBudWxsLCBudWxsLCBudWxsLCBudWxsLCBudWxsXTtcbiAgICAgICAgci50b3VjaERhdGEuc3RhcnRHUG9zaXRpb24gPSBudWxsO1xuICAgICAgICByLnRvdWNoRGF0YS5kaWRTZWxlY3QgPSBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGUudG91Y2hlcy5sZW5ndGggPCAyKSB7XG4gICAgICAgIGlmIChlLnRvdWNoZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgLy8gdGhlIG9sZCBzdGFydCBnbG9iYWwgcG9zJ24gbWF5IG5vdCBiZSB0aGUgc2FtZSBmaW5nZXIgdGhhdCByZW1haW5zXG4gICAgICAgICAgci50b3VjaERhdGEuc3RhcnRHUG9zaXRpb24gPSBbZS50b3VjaGVzWzBdLmNsaWVudFgsIGUudG91Y2hlc1swXS5jbGllbnRZXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHIucGluY2hpbmcgPSBmYWxzZTtcbiAgICAgICAgci5yZWRyYXdIaW50KCdlbGVzJywgdHJ1ZSk7XG4gICAgICAgIHIucmVkcmF3KCk7XG4gICAgICB9IC8vci5yZWRyYXcoKTtcblxuICAgIH0sIGZhbHNlKTsgLy8gZmFsbGJhY2sgY29tcGF0aWJpbGl0eSBsYXllciBmb3IgbXMgcG9pbnRlciBldmVudHNcblxuICAgIGlmICh0eXBlb2YgVG91Y2hFdmVudCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHZhciBwb2ludGVycyA9IFtdO1xuXG4gICAgICB2YXIgbWFrZVRvdWNoID0gZnVuY3Rpb24gbWFrZVRvdWNoKGUpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBjbGllbnRYOiBlLmNsaWVudFgsXG4gICAgICAgICAgY2xpZW50WTogZS5jbGllbnRZLFxuICAgICAgICAgIGZvcmNlOiAxLFxuICAgICAgICAgIGlkZW50aWZpZXI6IGUucG9pbnRlcklkLFxuICAgICAgICAgIHBhZ2VYOiBlLnBhZ2VYLFxuICAgICAgICAgIHBhZ2VZOiBlLnBhZ2VZLFxuICAgICAgICAgIHJhZGl1c1g6IGUud2lkdGggLyAyLFxuICAgICAgICAgIHJhZGl1c1k6IGUuaGVpZ2h0IC8gMixcbiAgICAgICAgICBzY3JlZW5YOiBlLnNjcmVlblgsXG4gICAgICAgICAgc2NyZWVuWTogZS5zY3JlZW5ZLFxuICAgICAgICAgIHRhcmdldDogZS50YXJnZXRcbiAgICAgICAgfTtcbiAgICAgIH07XG5cbiAgICAgIHZhciBtYWtlUG9pbnRlciA9IGZ1bmN0aW9uIG1ha2VQb2ludGVyKGUpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBldmVudDogZSxcbiAgICAgICAgICB0b3VjaDogbWFrZVRvdWNoKGUpXG4gICAgICAgIH07XG4gICAgICB9O1xuXG4gICAgICB2YXIgYWRkUG9pbnRlciA9IGZ1bmN0aW9uIGFkZFBvaW50ZXIoZSkge1xuICAgICAgICBwb2ludGVycy5wdXNoKG1ha2VQb2ludGVyKGUpKTtcbiAgICAgIH07XG5cbiAgICAgIHZhciByZW1vdmVQb2ludGVyID0gZnVuY3Rpb24gcmVtb3ZlUG9pbnRlcihlKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgcCA9IHBvaW50ZXJzW2ldO1xuXG4gICAgICAgICAgaWYgKHAuZXZlbnQucG9pbnRlcklkID09PSBlLnBvaW50ZXJJZCkge1xuICAgICAgICAgICAgcG9pbnRlcnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgdmFyIHVwZGF0ZVBvaW50ZXIgPSBmdW5jdGlvbiB1cGRhdGVQb2ludGVyKGUpIHtcbiAgICAgICAgdmFyIHAgPSBwb2ludGVycy5maWx0ZXIoZnVuY3Rpb24gKHApIHtcbiAgICAgICAgICByZXR1cm4gcC5ldmVudC5wb2ludGVySWQgPT09IGUucG9pbnRlcklkO1xuICAgICAgICB9KVswXTtcbiAgICAgICAgcC5ldmVudCA9IGU7XG4gICAgICAgIHAudG91Y2ggPSBtYWtlVG91Y2goZSk7XG4gICAgICB9O1xuXG4gICAgICB2YXIgYWRkVG91Y2hlc1RvRXZlbnQgPSBmdW5jdGlvbiBhZGRUb3VjaGVzVG9FdmVudChlKSB7XG4gICAgICAgIGUudG91Y2hlcyA9IHBvaW50ZXJzLm1hcChmdW5jdGlvbiAocCkge1xuICAgICAgICAgIHJldHVybiBwLnRvdWNoO1xuICAgICAgICB9KTtcbiAgICAgIH07XG5cbiAgICAgIHZhciBwb2ludGVySXNNb3VzZSA9IGZ1bmN0aW9uIHBvaW50ZXJJc01vdXNlKGUpIHtcbiAgICAgICAgcmV0dXJuIGUucG9pbnRlclR5cGUgPT09ICdtb3VzZScgfHwgZS5wb2ludGVyVHlwZSA9PT0gNDtcbiAgICAgIH07XG5cbiAgICAgIHIucmVnaXN0ZXJCaW5kaW5nKHIuY29udGFpbmVyLCAncG9pbnRlcmRvd24nLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICBpZiAocG9pbnRlcklzTW91c2UoZSkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gLy8gbW91c2UgYWxyZWFkeSBoYW5kbGVkXG5cblxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGFkZFBvaW50ZXIoZSk7XG4gICAgICAgIGFkZFRvdWNoZXNUb0V2ZW50KGUpO1xuICAgICAgICB0b3VjaHN0YXJ0SGFuZGxlcihlKTtcbiAgICAgIH0pO1xuICAgICAgci5yZWdpc3RlckJpbmRpbmcoci5jb250YWluZXIsICdwb2ludGVydXAnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICBpZiAocG9pbnRlcklzTW91c2UoZSkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gLy8gbW91c2UgYWxyZWFkeSBoYW5kbGVkXG5cblxuICAgICAgICByZW1vdmVQb2ludGVyKGUpO1xuICAgICAgICBhZGRUb3VjaGVzVG9FdmVudChlKTtcbiAgICAgICAgdG91Y2hlbmRIYW5kbGVyKGUpO1xuICAgICAgfSk7XG4gICAgICByLnJlZ2lzdGVyQmluZGluZyhyLmNvbnRhaW5lciwgJ3BvaW50ZXJjYW5jZWwnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICBpZiAocG9pbnRlcklzTW91c2UoZSkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gLy8gbW91c2UgYWxyZWFkeSBoYW5kbGVkXG5cblxuICAgICAgICByZW1vdmVQb2ludGVyKGUpO1xuICAgICAgICBhZGRUb3VjaGVzVG9FdmVudChlKTtcbiAgICAgICAgdG91Y2hjYW5jZWxIYW5kbGVyKGUpO1xuICAgICAgfSk7XG4gICAgICByLnJlZ2lzdGVyQmluZGluZyhyLmNvbnRhaW5lciwgJ3BvaW50ZXJtb3ZlJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgaWYgKHBvaW50ZXJJc01vdXNlKGUpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IC8vIG1vdXNlIGFscmVhZHkgaGFuZGxlZFxuXG5cbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB1cGRhdGVQb2ludGVyKGUpO1xuICAgICAgICBhZGRUb3VjaGVzVG9FdmVudChlKTtcbiAgICAgICAgdG91Y2htb3ZlSGFuZGxlcihlKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfTtcblxuICB2YXIgQlJwJDIgPSB7fTtcblxuICBCUnAkMi5nZW5lcmF0ZVBvbHlnb24gPSBmdW5jdGlvbiAobmFtZSwgcG9pbnRzKSB7XG4gICAgcmV0dXJuIHRoaXMubm9kZVNoYXBlc1tuYW1lXSA9IHtcbiAgICAgIHJlbmRlcmVyOiB0aGlzLFxuICAgICAgbmFtZTogbmFtZSxcbiAgICAgIHBvaW50czogcG9pbnRzLFxuICAgICAgZHJhdzogZnVuY3Rpb24gZHJhdyhjb250ZXh0LCBjZW50ZXJYLCBjZW50ZXJZLCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgICAgIHRoaXMucmVuZGVyZXIubm9kZVNoYXBlSW1wbCgncG9seWdvbicsIGNvbnRleHQsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQsIHRoaXMucG9pbnRzKTtcbiAgICAgIH0sXG4gICAgICBpbnRlcnNlY3RMaW5lOiBmdW5jdGlvbiBpbnRlcnNlY3RMaW5lKG5vZGVYLCBub2RlWSwgd2lkdGgsIGhlaWdodCwgeCwgeSwgcGFkZGluZykge1xuICAgICAgICByZXR1cm4gcG9seWdvbkludGVyc2VjdExpbmUoeCwgeSwgdGhpcy5wb2ludHMsIG5vZGVYLCBub2RlWSwgd2lkdGggLyAyLCBoZWlnaHQgLyAyLCBwYWRkaW5nKTtcbiAgICAgIH0sXG4gICAgICBjaGVja1BvaW50OiBmdW5jdGlvbiBjaGVja1BvaW50KHgsIHksIHBhZGRpbmcsIHdpZHRoLCBoZWlnaHQsIGNlbnRlclgsIGNlbnRlclkpIHtcbiAgICAgICAgcmV0dXJuIHBvaW50SW5zaWRlUG9seWdvbih4LCB5LCB0aGlzLnBvaW50cywgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCwgWzAsIC0xXSwgcGFkZGluZyk7XG4gICAgICB9XG4gICAgfTtcbiAgfTtcblxuICBCUnAkMi5nZW5lcmF0ZUVsbGlwc2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMubm9kZVNoYXBlc1snZWxsaXBzZSddID0ge1xuICAgICAgcmVuZGVyZXI6IHRoaXMsXG4gICAgICBuYW1lOiAnZWxsaXBzZScsXG4gICAgICBkcmF3OiBmdW5jdGlvbiBkcmF3KGNvbnRleHQsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQpIHtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5ub2RlU2hhcGVJbXBsKHRoaXMubmFtZSwgY29udGV4dCwgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCk7XG4gICAgICB9LFxuICAgICAgaW50ZXJzZWN0TGluZTogZnVuY3Rpb24gaW50ZXJzZWN0TGluZShub2RlWCwgbm9kZVksIHdpZHRoLCBoZWlnaHQsIHgsIHksIHBhZGRpbmcpIHtcbiAgICAgICAgcmV0dXJuIGludGVyc2VjdExpbmVFbGxpcHNlKHgsIHksIG5vZGVYLCBub2RlWSwgd2lkdGggLyAyICsgcGFkZGluZywgaGVpZ2h0IC8gMiArIHBhZGRpbmcpO1xuICAgICAgfSxcbiAgICAgIGNoZWNrUG9pbnQ6IGZ1bmN0aW9uIGNoZWNrUG9pbnQoeCwgeSwgcGFkZGluZywgd2lkdGgsIGhlaWdodCwgY2VudGVyWCwgY2VudGVyWSkge1xuICAgICAgICByZXR1cm4gY2hlY2tJbkVsbGlwc2UoeCwgeSwgd2lkdGgsIGhlaWdodCwgY2VudGVyWCwgY2VudGVyWSwgcGFkZGluZyk7XG4gICAgICB9XG4gICAgfTtcbiAgfTtcblxuICBCUnAkMi5nZW5lcmF0ZVJvdW5kUG9seWdvbiA9IGZ1bmN0aW9uIChuYW1lLCBwb2ludHMpIHtcbiAgICAvLyBQcmUtY29tcHV0ZSBjb250cm9sIHBvaW50c1xuICAgIC8vIFNpbmNlIHRoZXNlIHBvaW50cyBkZXBlbmQgb24gdGhlIHJhZGl1cyBsZW5ndGggKHdoaWNoIGluIHR1cm5zIGRlcGVuZCBvbiB0aGUgd2lkdGgvaGVpZ2h0IG9mIHRoZSBub2RlKSB3ZSB3aWxsIG9ubHkgcHJlLWNvbXB1dGVcbiAgICAvLyB0aGUgdW5pdCB2ZWN0b3JzLlxuICAgIC8vIEZvciBzaW1wbGljaXR5IHRoZSBsYXlvdXQgd2lsbCBiZTpcbiAgICAvLyBbIHAwLCBVbml0VmVjdG9yUDBQMSwgcDEsIFVuaVZlY3RvclAxUDIsIC4uLiwgcG4sIFVuaXRWZWN0b3JQblAwIF1cbiAgICB2YXIgYWxsUG9pbnRzID0gbmV3IEFycmF5KHBvaW50cy5sZW5ndGggKiAyKTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aCAvIDI7IGkrKykge1xuICAgICAgdmFyIHNvdXJjZUluZGV4ID0gaSAqIDI7XG4gICAgICB2YXIgZGVzdEluZGV4ID0gdm9pZCAwO1xuXG4gICAgICBpZiAoaSA8IHBvaW50cy5sZW5ndGggLyAyIC0gMSkge1xuICAgICAgICBkZXN0SW5kZXggPSAoaSArIDEpICogMjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRlc3RJbmRleCA9IDA7XG4gICAgICB9XG5cbiAgICAgIGFsbFBvaW50c1tpICogNF0gPSBwb2ludHNbc291cmNlSW5kZXhdO1xuICAgICAgYWxsUG9pbnRzW2kgKiA0ICsgMV0gPSBwb2ludHNbc291cmNlSW5kZXggKyAxXTtcbiAgICAgIHZhciB4RGVzdCA9IHBvaW50c1tkZXN0SW5kZXhdIC0gcG9pbnRzW3NvdXJjZUluZGV4XTtcbiAgICAgIHZhciB5RGVzdCA9IHBvaW50c1tkZXN0SW5kZXggKyAxXSAtIHBvaW50c1tzb3VyY2VJbmRleCArIDFdO1xuICAgICAgdmFyIG5vcm0gPSBNYXRoLnNxcnQoeERlc3QgKiB4RGVzdCArIHlEZXN0ICogeURlc3QpO1xuICAgICAgYWxsUG9pbnRzW2kgKiA0ICsgMl0gPSB4RGVzdCAvIG5vcm07XG4gICAgICBhbGxQb2ludHNbaSAqIDQgKyAzXSA9IHlEZXN0IC8gbm9ybTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5ub2RlU2hhcGVzW25hbWVdID0ge1xuICAgICAgcmVuZGVyZXI6IHRoaXMsXG4gICAgICBuYW1lOiBuYW1lLFxuICAgICAgcG9pbnRzOiBhbGxQb2ludHMsXG4gICAgICBkcmF3OiBmdW5jdGlvbiBkcmF3KGNvbnRleHQsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQpIHtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5ub2RlU2hhcGVJbXBsKCdyb3VuZC1wb2x5Z29uJywgY29udGV4dCwgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCwgdGhpcy5wb2ludHMpO1xuICAgICAgfSxcbiAgICAgIGludGVyc2VjdExpbmU6IGZ1bmN0aW9uIGludGVyc2VjdExpbmUobm9kZVgsIG5vZGVZLCB3aWR0aCwgaGVpZ2h0LCB4LCB5LCBwYWRkaW5nKSB7XG4gICAgICAgIHJldHVybiByb3VuZFBvbHlnb25JbnRlcnNlY3RMaW5lKHgsIHksIHRoaXMucG9pbnRzLCBub2RlWCwgbm9kZVksIHdpZHRoLCBoZWlnaHQpO1xuICAgICAgfSxcbiAgICAgIGNoZWNrUG9pbnQ6IGZ1bmN0aW9uIGNoZWNrUG9pbnQoeCwgeSwgcGFkZGluZywgd2lkdGgsIGhlaWdodCwgY2VudGVyWCwgY2VudGVyWSkge1xuICAgICAgICByZXR1cm4gcG9pbnRJbnNpZGVSb3VuZFBvbHlnb24oeCwgeSwgdGhpcy5wb2ludHMsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQpO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgQlJwJDIuZ2VuZXJhdGVSb3VuZFJlY3RhbmdsZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5ub2RlU2hhcGVzWydyb3VuZC1yZWN0YW5nbGUnXSA9IHRoaXMubm9kZVNoYXBlc1sncm91bmRyZWN0YW5nbGUnXSA9IHtcbiAgICAgIHJlbmRlcmVyOiB0aGlzLFxuICAgICAgbmFtZTogJ3JvdW5kLXJlY3RhbmdsZScsXG4gICAgICBwb2ludHM6IGdlbmVyYXRlVW5pdE5nb25Qb2ludHNGaXRUb1NxdWFyZSg0LCAwKSxcbiAgICAgIGRyYXc6IGZ1bmN0aW9uIGRyYXcoY29udGV4dCwgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCkge1xuICAgICAgICB0aGlzLnJlbmRlcmVyLm5vZGVTaGFwZUltcGwodGhpcy5uYW1lLCBjb250ZXh0LCBjZW50ZXJYLCBjZW50ZXJZLCB3aWR0aCwgaGVpZ2h0KTtcbiAgICAgIH0sXG4gICAgICBpbnRlcnNlY3RMaW5lOiBmdW5jdGlvbiBpbnRlcnNlY3RMaW5lKG5vZGVYLCBub2RlWSwgd2lkdGgsIGhlaWdodCwgeCwgeSwgcGFkZGluZykge1xuICAgICAgICByZXR1cm4gcm91bmRSZWN0YW5nbGVJbnRlcnNlY3RMaW5lKHgsIHksIG5vZGVYLCBub2RlWSwgd2lkdGgsIGhlaWdodCwgcGFkZGluZyk7XG4gICAgICB9LFxuICAgICAgY2hlY2tQb2ludDogZnVuY3Rpb24gY2hlY2tQb2ludCh4LCB5LCBwYWRkaW5nLCB3aWR0aCwgaGVpZ2h0LCBjZW50ZXJYLCBjZW50ZXJZKSB7XG4gICAgICAgIHZhciBjb3JuZXJSYWRpdXMgPSBnZXRSb3VuZFJlY3RhbmdsZVJhZGl1cyh3aWR0aCwgaGVpZ2h0KTtcbiAgICAgICAgdmFyIGRpYW0gPSBjb3JuZXJSYWRpdXMgKiAyOyAvLyBDaGVjayBoQm94XG5cbiAgICAgICAgaWYgKHBvaW50SW5zaWRlUG9seWdvbih4LCB5LCB0aGlzLnBvaW50cywgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCAtIGRpYW0sIFswLCAtMV0sIHBhZGRpbmcpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gLy8gQ2hlY2sgdkJveFxuXG5cbiAgICAgICAgaWYgKHBvaW50SW5zaWRlUG9seWdvbih4LCB5LCB0aGlzLnBvaW50cywgY2VudGVyWCwgY2VudGVyWSwgd2lkdGggLSBkaWFtLCBoZWlnaHQsIFswLCAtMV0sIHBhZGRpbmcpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gLy8gQ2hlY2sgdG9wIGxlZnQgcXVhcnRlciBjaXJjbGVcblxuXG4gICAgICAgIGlmIChjaGVja0luRWxsaXBzZSh4LCB5LCBkaWFtLCBkaWFtLCBjZW50ZXJYIC0gd2lkdGggLyAyICsgY29ybmVyUmFkaXVzLCBjZW50ZXJZIC0gaGVpZ2h0IC8gMiArIGNvcm5lclJhZGl1cywgcGFkZGluZykpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSAvLyBDaGVjayB0b3AgcmlnaHQgcXVhcnRlciBjaXJjbGVcblxuXG4gICAgICAgIGlmIChjaGVja0luRWxsaXBzZSh4LCB5LCBkaWFtLCBkaWFtLCBjZW50ZXJYICsgd2lkdGggLyAyIC0gY29ybmVyUmFkaXVzLCBjZW50ZXJZIC0gaGVpZ2h0IC8gMiArIGNvcm5lclJhZGl1cywgcGFkZGluZykpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSAvLyBDaGVjayBib3R0b20gcmlnaHQgcXVhcnRlciBjaXJjbGVcblxuXG4gICAgICAgIGlmIChjaGVja0luRWxsaXBzZSh4LCB5LCBkaWFtLCBkaWFtLCBjZW50ZXJYICsgd2lkdGggLyAyIC0gY29ybmVyUmFkaXVzLCBjZW50ZXJZICsgaGVpZ2h0IC8gMiAtIGNvcm5lclJhZGl1cywgcGFkZGluZykpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSAvLyBDaGVjayBib3R0b20gbGVmdCBxdWFydGVyIGNpcmNsZVxuXG5cbiAgICAgICAgaWYgKGNoZWNrSW5FbGxpcHNlKHgsIHksIGRpYW0sIGRpYW0sIGNlbnRlclggLSB3aWR0aCAvIDIgKyBjb3JuZXJSYWRpdXMsIGNlbnRlclkgKyBoZWlnaHQgLyAyIC0gY29ybmVyUmFkaXVzLCBwYWRkaW5nKSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgQlJwJDIuZ2VuZXJhdGVDdXRSZWN0YW5nbGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMubm9kZVNoYXBlc1snY3V0LXJlY3RhbmdsZSddID0gdGhpcy5ub2RlU2hhcGVzWydjdXRyZWN0YW5nbGUnXSA9IHtcbiAgICAgIHJlbmRlcmVyOiB0aGlzLFxuICAgICAgbmFtZTogJ2N1dC1yZWN0YW5nbGUnLFxuICAgICAgY29ybmVyTGVuZ3RoOiBnZXRDdXRSZWN0YW5nbGVDb3JuZXJMZW5ndGgoKSxcbiAgICAgIHBvaW50czogZ2VuZXJhdGVVbml0TmdvblBvaW50c0ZpdFRvU3F1YXJlKDQsIDApLFxuICAgICAgZHJhdzogZnVuY3Rpb24gZHJhdyhjb250ZXh0LCBjZW50ZXJYLCBjZW50ZXJZLCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgICAgIHRoaXMucmVuZGVyZXIubm9kZVNoYXBlSW1wbCh0aGlzLm5hbWUsIGNvbnRleHQsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQpO1xuICAgICAgfSxcbiAgICAgIGdlbmVyYXRlQ3V0VHJpYW5nbGVQdHM6IGZ1bmN0aW9uIGdlbmVyYXRlQ3V0VHJpYW5nbGVQdHMod2lkdGgsIGhlaWdodCwgY2VudGVyWCwgY2VudGVyWSkge1xuICAgICAgICB2YXIgY2wgPSB0aGlzLmNvcm5lckxlbmd0aDtcbiAgICAgICAgdmFyIGhoID0gaGVpZ2h0IC8gMjtcbiAgICAgICAgdmFyIGh3ID0gd2lkdGggLyAyO1xuICAgICAgICB2YXIgeEJlZ2luID0gY2VudGVyWCAtIGh3O1xuICAgICAgICB2YXIgeEVuZCA9IGNlbnRlclggKyBodztcbiAgICAgICAgdmFyIHlCZWdpbiA9IGNlbnRlclkgLSBoaDtcbiAgICAgICAgdmFyIHlFbmQgPSBjZW50ZXJZICsgaGg7IC8vIHBvaW50cyBhcmUgaW4gY2xvY2t3aXNlIG9yZGVyLCBpbm5lciAoaW1hZ2luYXJ5KSB0cmlhbmdsZSBwdCBvbiBbNCwgNV1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHRvcExlZnQ6IFt4QmVnaW4sIHlCZWdpbiArIGNsLCB4QmVnaW4gKyBjbCwgeUJlZ2luLCB4QmVnaW4gKyBjbCwgeUJlZ2luICsgY2xdLFxuICAgICAgICAgIHRvcFJpZ2h0OiBbeEVuZCAtIGNsLCB5QmVnaW4sIHhFbmQsIHlCZWdpbiArIGNsLCB4RW5kIC0gY2wsIHlCZWdpbiArIGNsXSxcbiAgICAgICAgICBib3R0b21SaWdodDogW3hFbmQsIHlFbmQgLSBjbCwgeEVuZCAtIGNsLCB5RW5kLCB4RW5kIC0gY2wsIHlFbmQgLSBjbF0sXG4gICAgICAgICAgYm90dG9tTGVmdDogW3hCZWdpbiArIGNsLCB5RW5kLCB4QmVnaW4sIHlFbmQgLSBjbCwgeEJlZ2luICsgY2wsIHlFbmQgLSBjbF1cbiAgICAgICAgfTtcbiAgICAgIH0sXG4gICAgICBpbnRlcnNlY3RMaW5lOiBmdW5jdGlvbiBpbnRlcnNlY3RMaW5lKG5vZGVYLCBub2RlWSwgd2lkdGgsIGhlaWdodCwgeCwgeSwgcGFkZGluZykge1xuICAgICAgICB2YXIgY1B0cyA9IHRoaXMuZ2VuZXJhdGVDdXRUcmlhbmdsZVB0cyh3aWR0aCArIDIgKiBwYWRkaW5nLCBoZWlnaHQgKyAyICogcGFkZGluZywgbm9kZVgsIG5vZGVZKTtcbiAgICAgICAgdmFyIHB0cyA9IFtdLmNvbmNhdC5hcHBseShbXSwgW2NQdHMudG9wTGVmdC5zcGxpY2UoMCwgNCksIGNQdHMudG9wUmlnaHQuc3BsaWNlKDAsIDQpLCBjUHRzLmJvdHRvbVJpZ2h0LnNwbGljZSgwLCA0KSwgY1B0cy5ib3R0b21MZWZ0LnNwbGljZSgwLCA0KV0pO1xuICAgICAgICByZXR1cm4gcG9seWdvbkludGVyc2VjdExpbmUoeCwgeSwgcHRzLCBub2RlWCwgbm9kZVkpO1xuICAgICAgfSxcbiAgICAgIGNoZWNrUG9pbnQ6IGZ1bmN0aW9uIGNoZWNrUG9pbnQoeCwgeSwgcGFkZGluZywgd2lkdGgsIGhlaWdodCwgY2VudGVyWCwgY2VudGVyWSkge1xuICAgICAgICAvLyBDaGVjayBoQm94XG4gICAgICAgIGlmIChwb2ludEluc2lkZVBvbHlnb24oeCwgeSwgdGhpcy5wb2ludHMsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQgLSAyICogdGhpcy5jb3JuZXJMZW5ndGgsIFswLCAtMV0sIHBhZGRpbmcpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gLy8gQ2hlY2sgdkJveFxuXG5cbiAgICAgICAgaWYgKHBvaW50SW5zaWRlUG9seWdvbih4LCB5LCB0aGlzLnBvaW50cywgY2VudGVyWCwgY2VudGVyWSwgd2lkdGggLSAyICogdGhpcy5jb3JuZXJMZW5ndGgsIGhlaWdodCwgWzAsIC0xXSwgcGFkZGluZykpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBjdXRUcmlhbmdsZVB0cyA9IHRoaXMuZ2VuZXJhdGVDdXRUcmlhbmdsZVB0cyh3aWR0aCwgaGVpZ2h0LCBjZW50ZXJYLCBjZW50ZXJZKTtcbiAgICAgICAgcmV0dXJuIHBvaW50SW5zaWRlUG9seWdvblBvaW50cyh4LCB5LCBjdXRUcmlhbmdsZVB0cy50b3BMZWZ0KSB8fCBwb2ludEluc2lkZVBvbHlnb25Qb2ludHMoeCwgeSwgY3V0VHJpYW5nbGVQdHMudG9wUmlnaHQpIHx8IHBvaW50SW5zaWRlUG9seWdvblBvaW50cyh4LCB5LCBjdXRUcmlhbmdsZVB0cy5ib3R0b21SaWdodCkgfHwgcG9pbnRJbnNpZGVQb2x5Z29uUG9pbnRzKHgsIHksIGN1dFRyaWFuZ2xlUHRzLmJvdHRvbUxlZnQpO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgQlJwJDIuZ2VuZXJhdGVCYXJyZWwgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMubm9kZVNoYXBlc1snYmFycmVsJ10gPSB7XG4gICAgICByZW5kZXJlcjogdGhpcyxcbiAgICAgIG5hbWU6ICdiYXJyZWwnLFxuICAgICAgcG9pbnRzOiBnZW5lcmF0ZVVuaXROZ29uUG9pbnRzRml0VG9TcXVhcmUoNCwgMCksXG4gICAgICBkcmF3OiBmdW5jdGlvbiBkcmF3KGNvbnRleHQsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQpIHtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5ub2RlU2hhcGVJbXBsKHRoaXMubmFtZSwgY29udGV4dCwgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCk7XG4gICAgICB9LFxuICAgICAgaW50ZXJzZWN0TGluZTogZnVuY3Rpb24gaW50ZXJzZWN0TGluZShub2RlWCwgbm9kZVksIHdpZHRoLCBoZWlnaHQsIHgsIHksIHBhZGRpbmcpIHtcbiAgICAgICAgLy8gdXNlIHR3byBmaXhlZCB0IHZhbHVlcyBmb3IgdGhlIGJlemllciBjdXJ2ZSBhcHByb3hpbWF0aW9uXG4gICAgICAgIHZhciB0MCA9IDAuMTU7XG4gICAgICAgIHZhciB0MSA9IDAuNTtcbiAgICAgICAgdmFyIHQyID0gMC44NTtcbiAgICAgICAgdmFyIGJQdHMgPSB0aGlzLmdlbmVyYXRlQmFycmVsQmV6aWVyUHRzKHdpZHRoICsgMiAqIHBhZGRpbmcsIGhlaWdodCArIDIgKiBwYWRkaW5nLCBub2RlWCwgbm9kZVkpO1xuXG4gICAgICAgIHZhciBhcHByb3hpbWF0ZUJhcnJlbEN1cnZlUHRzID0gZnVuY3Rpb24gYXBwcm94aW1hdGVCYXJyZWxDdXJ2ZVB0cyhwdHMpIHtcbiAgICAgICAgICAvLyBhcHByb3hpbWF0ZSBjdXJ2ZSBwdHMgYmFzZWQgb24gdGhlIHR3byB0IHZhbHVlc1xuICAgICAgICAgIHZhciBtMCA9IHFiZXppZXJQdEF0KHtcbiAgICAgICAgICAgIHg6IHB0c1swXSxcbiAgICAgICAgICAgIHk6IHB0c1sxXVxuICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgIHg6IHB0c1syXSxcbiAgICAgICAgICAgIHk6IHB0c1szXVxuICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgIHg6IHB0c1s0XSxcbiAgICAgICAgICAgIHk6IHB0c1s1XVxuICAgICAgICAgIH0sIHQwKTtcbiAgICAgICAgICB2YXIgbTEgPSBxYmV6aWVyUHRBdCh7XG4gICAgICAgICAgICB4OiBwdHNbMF0sXG4gICAgICAgICAgICB5OiBwdHNbMV1cbiAgICAgICAgICB9LCB7XG4gICAgICAgICAgICB4OiBwdHNbMl0sXG4gICAgICAgICAgICB5OiBwdHNbM11cbiAgICAgICAgICB9LCB7XG4gICAgICAgICAgICB4OiBwdHNbNF0sXG4gICAgICAgICAgICB5OiBwdHNbNV1cbiAgICAgICAgICB9LCB0MSk7XG4gICAgICAgICAgdmFyIG0yID0gcWJlemllclB0QXQoe1xuICAgICAgICAgICAgeDogcHRzWzBdLFxuICAgICAgICAgICAgeTogcHRzWzFdXG4gICAgICAgICAgfSwge1xuICAgICAgICAgICAgeDogcHRzWzJdLFxuICAgICAgICAgICAgeTogcHRzWzNdXG4gICAgICAgICAgfSwge1xuICAgICAgICAgICAgeDogcHRzWzRdLFxuICAgICAgICAgICAgeTogcHRzWzVdXG4gICAgICAgICAgfSwgdDIpO1xuICAgICAgICAgIHJldHVybiBbcHRzWzBdLCBwdHNbMV0sIG0wLngsIG0wLnksIG0xLngsIG0xLnksIG0yLngsIG0yLnksIHB0c1s0XSwgcHRzWzVdXTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgcHRzID0gW10uY29uY2F0KGFwcHJveGltYXRlQmFycmVsQ3VydmVQdHMoYlB0cy50b3BMZWZ0KSwgYXBwcm94aW1hdGVCYXJyZWxDdXJ2ZVB0cyhiUHRzLnRvcFJpZ2h0KSwgYXBwcm94aW1hdGVCYXJyZWxDdXJ2ZVB0cyhiUHRzLmJvdHRvbVJpZ2h0KSwgYXBwcm94aW1hdGVCYXJyZWxDdXJ2ZVB0cyhiUHRzLmJvdHRvbUxlZnQpKTtcbiAgICAgICAgcmV0dXJuIHBvbHlnb25JbnRlcnNlY3RMaW5lKHgsIHksIHB0cywgbm9kZVgsIG5vZGVZKTtcbiAgICAgIH0sXG4gICAgICBnZW5lcmF0ZUJhcnJlbEJlemllclB0czogZnVuY3Rpb24gZ2VuZXJhdGVCYXJyZWxCZXppZXJQdHMod2lkdGgsIGhlaWdodCwgY2VudGVyWCwgY2VudGVyWSkge1xuICAgICAgICB2YXIgaGggPSBoZWlnaHQgLyAyO1xuICAgICAgICB2YXIgaHcgPSB3aWR0aCAvIDI7XG4gICAgICAgIHZhciB4QmVnaW4gPSBjZW50ZXJYIC0gaHc7XG4gICAgICAgIHZhciB4RW5kID0gY2VudGVyWCArIGh3O1xuICAgICAgICB2YXIgeUJlZ2luID0gY2VudGVyWSAtIGhoO1xuICAgICAgICB2YXIgeUVuZCA9IGNlbnRlclkgKyBoaDtcbiAgICAgICAgdmFyIGN1cnZlQ29uc3RhbnRzID0gZ2V0QmFycmVsQ3VydmVDb25zdGFudHMod2lkdGgsIGhlaWdodCk7XG4gICAgICAgIHZhciBoT2Zmc2V0ID0gY3VydmVDb25zdGFudHMuaGVpZ2h0T2Zmc2V0O1xuICAgICAgICB2YXIgd09mZnNldCA9IGN1cnZlQ29uc3RhbnRzLndpZHRoT2Zmc2V0O1xuICAgICAgICB2YXIgY3RybFB0WE9mZnNldCA9IGN1cnZlQ29uc3RhbnRzLmN0cmxQdE9mZnNldFBjdCAqIHdpZHRoOyAvLyBwb2ludHMgYXJlIGluIGNsb2Nrd2lzZSBvcmRlciwgaW5uZXIgKGltYWdpbmFyeSkgY29udHJvbCBwdCBvbiBbNCwgNV1cblxuICAgICAgICB2YXIgcHRzID0ge1xuICAgICAgICAgIHRvcExlZnQ6IFt4QmVnaW4sIHlCZWdpbiArIGhPZmZzZXQsIHhCZWdpbiArIGN0cmxQdFhPZmZzZXQsIHlCZWdpbiwgeEJlZ2luICsgd09mZnNldCwgeUJlZ2luXSxcbiAgICAgICAgICB0b3BSaWdodDogW3hFbmQgLSB3T2Zmc2V0LCB5QmVnaW4sIHhFbmQgLSBjdHJsUHRYT2Zmc2V0LCB5QmVnaW4sIHhFbmQsIHlCZWdpbiArIGhPZmZzZXRdLFxuICAgICAgICAgIGJvdHRvbVJpZ2h0OiBbeEVuZCwgeUVuZCAtIGhPZmZzZXQsIHhFbmQgLSBjdHJsUHRYT2Zmc2V0LCB5RW5kLCB4RW5kIC0gd09mZnNldCwgeUVuZF0sXG4gICAgICAgICAgYm90dG9tTGVmdDogW3hCZWdpbiArIHdPZmZzZXQsIHlFbmQsIHhCZWdpbiArIGN0cmxQdFhPZmZzZXQsIHlFbmQsIHhCZWdpbiwgeUVuZCAtIGhPZmZzZXRdXG4gICAgICAgIH07XG4gICAgICAgIHB0cy50b3BMZWZ0LmlzVG9wID0gdHJ1ZTtcbiAgICAgICAgcHRzLnRvcFJpZ2h0LmlzVG9wID0gdHJ1ZTtcbiAgICAgICAgcHRzLmJvdHRvbUxlZnQuaXNCb3R0b20gPSB0cnVlO1xuICAgICAgICBwdHMuYm90dG9tUmlnaHQuaXNCb3R0b20gPSB0cnVlO1xuICAgICAgICByZXR1cm4gcHRzO1xuICAgICAgfSxcbiAgICAgIGNoZWNrUG9pbnQ6IGZ1bmN0aW9uIGNoZWNrUG9pbnQoeCwgeSwgcGFkZGluZywgd2lkdGgsIGhlaWdodCwgY2VudGVyWCwgY2VudGVyWSkge1xuICAgICAgICB2YXIgY3VydmVDb25zdGFudHMgPSBnZXRCYXJyZWxDdXJ2ZUNvbnN0YW50cyh3aWR0aCwgaGVpZ2h0KTtcbiAgICAgICAgdmFyIGhPZmZzZXQgPSBjdXJ2ZUNvbnN0YW50cy5oZWlnaHRPZmZzZXQ7XG4gICAgICAgIHZhciB3T2Zmc2V0ID0gY3VydmVDb25zdGFudHMud2lkdGhPZmZzZXQ7IC8vIENoZWNrIGhCb3hcblxuICAgICAgICBpZiAocG9pbnRJbnNpZGVQb2x5Z29uKHgsIHksIHRoaXMucG9pbnRzLCBjZW50ZXJYLCBjZW50ZXJZLCB3aWR0aCwgaGVpZ2h0IC0gMiAqIGhPZmZzZXQsIFswLCAtMV0sIHBhZGRpbmcpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gLy8gQ2hlY2sgdkJveFxuXG5cbiAgICAgICAgaWYgKHBvaW50SW5zaWRlUG9seWdvbih4LCB5LCB0aGlzLnBvaW50cywgY2VudGVyWCwgY2VudGVyWSwgd2lkdGggLSAyICogd09mZnNldCwgaGVpZ2h0LCBbMCwgLTFdLCBwYWRkaW5nKSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJhcnJlbEN1cnZlUHRzID0gdGhpcy5nZW5lcmF0ZUJhcnJlbEJlemllclB0cyh3aWR0aCwgaGVpZ2h0LCBjZW50ZXJYLCBjZW50ZXJZKTtcblxuICAgICAgICB2YXIgZ2V0Q3VydmVUID0gZnVuY3Rpb24gZ2V0Q3VydmVUKHgsIHksIGN1cnZlUHRzKSB7XG4gICAgICAgICAgdmFyIHgwID0gY3VydmVQdHNbNF07XG4gICAgICAgICAgdmFyIHgxID0gY3VydmVQdHNbMl07XG4gICAgICAgICAgdmFyIHgyID0gY3VydmVQdHNbMF07XG4gICAgICAgICAgdmFyIHkwID0gY3VydmVQdHNbNV07IC8vIHZhciB5MSA9IGN1cnZlUHRzWyAzIF07XG5cbiAgICAgICAgICB2YXIgeTIgPSBjdXJ2ZVB0c1sxXTtcbiAgICAgICAgICB2YXIgeE1pbiA9IE1hdGgubWluKHgwLCB4Mik7XG4gICAgICAgICAgdmFyIHhNYXggPSBNYXRoLm1heCh4MCwgeDIpO1xuICAgICAgICAgIHZhciB5TWluID0gTWF0aC5taW4oeTAsIHkyKTtcbiAgICAgICAgICB2YXIgeU1heCA9IE1hdGgubWF4KHkwLCB5Mik7XG5cbiAgICAgICAgICBpZiAoeE1pbiA8PSB4ICYmIHggPD0geE1heCAmJiB5TWluIDw9IHkgJiYgeSA8PSB5TWF4KSB7XG4gICAgICAgICAgICB2YXIgY29lZmYgPSBiZXppZXJQdHNUb1F1YWRDb2VmZih4MCwgeDEsIHgyKTtcbiAgICAgICAgICAgIHZhciByb290cyA9IHNvbHZlUXVhZHJhdGljKGNvZWZmWzBdLCBjb2VmZlsxXSwgY29lZmZbMl0sIHgpO1xuICAgICAgICAgICAgdmFyIHZhbGlkUm9vdHMgPSByb290cy5maWx0ZXIoZnVuY3Rpb24gKHIpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIDAgPD0gciAmJiByIDw9IDE7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKHZhbGlkUm9vdHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICByZXR1cm4gdmFsaWRSb290c1swXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgY3VydmVSZWdpb25zID0gT2JqZWN0LmtleXMoYmFycmVsQ3VydmVQdHMpO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY3VydmVSZWdpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgdmFyIGNvcm5lciA9IGN1cnZlUmVnaW9uc1tpXTtcbiAgICAgICAgICB2YXIgY29ybmVyUHRzID0gYmFycmVsQ3VydmVQdHNbY29ybmVyXTtcbiAgICAgICAgICB2YXIgdCA9IGdldEN1cnZlVCh4LCB5LCBjb3JuZXJQdHMpO1xuXG4gICAgICAgICAgaWYgKHQgPT0gbnVsbCkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdmFyIHkwID0gY29ybmVyUHRzWzVdO1xuICAgICAgICAgIHZhciB5MSA9IGNvcm5lclB0c1szXTtcbiAgICAgICAgICB2YXIgeTIgPSBjb3JuZXJQdHNbMV07XG4gICAgICAgICAgdmFyIGJlelkgPSBxYmV6aWVyQXQoeTAsIHkxLCB5MiwgdCk7XG5cbiAgICAgICAgICBpZiAoY29ybmVyUHRzLmlzVG9wICYmIGJlelkgPD0geSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGNvcm5lclB0cy5pc0JvdHRvbSAmJiB5IDw9IGJlelkpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9O1xuICB9O1xuXG4gIEJScCQyLmdlbmVyYXRlQm90dG9tUm91bmRyZWN0YW5nbGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMubm9kZVNoYXBlc1snYm90dG9tLXJvdW5kLXJlY3RhbmdsZSddID0gdGhpcy5ub2RlU2hhcGVzWydib3R0b21yb3VuZHJlY3RhbmdsZSddID0ge1xuICAgICAgcmVuZGVyZXI6IHRoaXMsXG4gICAgICBuYW1lOiAnYm90dG9tLXJvdW5kLXJlY3RhbmdsZScsXG4gICAgICBwb2ludHM6IGdlbmVyYXRlVW5pdE5nb25Qb2ludHNGaXRUb1NxdWFyZSg0LCAwKSxcbiAgICAgIGRyYXc6IGZ1bmN0aW9uIGRyYXcoY29udGV4dCwgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCkge1xuICAgICAgICB0aGlzLnJlbmRlcmVyLm5vZGVTaGFwZUltcGwodGhpcy5uYW1lLCBjb250ZXh0LCBjZW50ZXJYLCBjZW50ZXJZLCB3aWR0aCwgaGVpZ2h0KTtcbiAgICAgIH0sXG4gICAgICBpbnRlcnNlY3RMaW5lOiBmdW5jdGlvbiBpbnRlcnNlY3RMaW5lKG5vZGVYLCBub2RlWSwgd2lkdGgsIGhlaWdodCwgeCwgeSwgcGFkZGluZykge1xuICAgICAgICB2YXIgdG9wU3RhcnRYID0gbm9kZVggLSAod2lkdGggLyAyICsgcGFkZGluZyk7XG4gICAgICAgIHZhciB0b3BTdGFydFkgPSBub2RlWSAtIChoZWlnaHQgLyAyICsgcGFkZGluZyk7XG4gICAgICAgIHZhciB0b3BFbmRZID0gdG9wU3RhcnRZO1xuICAgICAgICB2YXIgdG9wRW5kWCA9IG5vZGVYICsgKHdpZHRoIC8gMiArIHBhZGRpbmcpO1xuICAgICAgICB2YXIgdG9wSW50ZXJzZWN0aW9ucyA9IGZpbml0ZUxpbmVzSW50ZXJzZWN0KHgsIHksIG5vZGVYLCBub2RlWSwgdG9wU3RhcnRYLCB0b3BTdGFydFksIHRvcEVuZFgsIHRvcEVuZFksIGZhbHNlKTtcblxuICAgICAgICBpZiAodG9wSW50ZXJzZWN0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgcmV0dXJuIHRvcEludGVyc2VjdGlvbnM7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcm91bmRSZWN0YW5nbGVJbnRlcnNlY3RMaW5lKHgsIHksIG5vZGVYLCBub2RlWSwgd2lkdGgsIGhlaWdodCwgcGFkZGluZyk7XG4gICAgICB9LFxuICAgICAgY2hlY2tQb2ludDogZnVuY3Rpb24gY2hlY2tQb2ludCh4LCB5LCBwYWRkaW5nLCB3aWR0aCwgaGVpZ2h0LCBjZW50ZXJYLCBjZW50ZXJZKSB7XG4gICAgICAgIHZhciBjb3JuZXJSYWRpdXMgPSBnZXRSb3VuZFJlY3RhbmdsZVJhZGl1cyh3aWR0aCwgaGVpZ2h0KTtcbiAgICAgICAgdmFyIGRpYW0gPSAyICogY29ybmVyUmFkaXVzOyAvLyBDaGVjayBoQm94XG5cbiAgICAgICAgaWYgKHBvaW50SW5zaWRlUG9seWdvbih4LCB5LCB0aGlzLnBvaW50cywgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCAtIGRpYW0sIFswLCAtMV0sIHBhZGRpbmcpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gLy8gQ2hlY2sgdkJveFxuXG5cbiAgICAgICAgaWYgKHBvaW50SW5zaWRlUG9seWdvbih4LCB5LCB0aGlzLnBvaW50cywgY2VudGVyWCwgY2VudGVyWSwgd2lkdGggLSBkaWFtLCBoZWlnaHQsIFswLCAtMV0sIHBhZGRpbmcpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gLy8gY2hlY2sgbm9uLXJvdW5kZWQgdG9wIHNpZGVcblxuXG4gICAgICAgIHZhciBvdXRlcldpZHRoID0gd2lkdGggLyAyICsgMiAqIHBhZGRpbmc7XG4gICAgICAgIHZhciBvdXRlckhlaWdodCA9IGhlaWdodCAvIDIgKyAyICogcGFkZGluZztcbiAgICAgICAgdmFyIHBvaW50cyA9IFtjZW50ZXJYIC0gb3V0ZXJXaWR0aCwgY2VudGVyWSAtIG91dGVySGVpZ2h0LCBjZW50ZXJYIC0gb3V0ZXJXaWR0aCwgY2VudGVyWSwgY2VudGVyWCArIG91dGVyV2lkdGgsIGNlbnRlclksIGNlbnRlclggKyBvdXRlcldpZHRoLCBjZW50ZXJZIC0gb3V0ZXJIZWlnaHRdO1xuXG4gICAgICAgIGlmIChwb2ludEluc2lkZVBvbHlnb25Qb2ludHMoeCwgeSwgcG9pbnRzKSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9IC8vIENoZWNrIGJvdHRvbSByaWdodCBxdWFydGVyIGNpcmNsZVxuXG5cbiAgICAgICAgaWYgKGNoZWNrSW5FbGxpcHNlKHgsIHksIGRpYW0sIGRpYW0sIGNlbnRlclggKyB3aWR0aCAvIDIgLSBjb3JuZXJSYWRpdXMsIGNlbnRlclkgKyBoZWlnaHQgLyAyIC0gY29ybmVyUmFkaXVzLCBwYWRkaW5nKSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9IC8vIENoZWNrIGJvdHRvbSBsZWZ0IHF1YXJ0ZXIgY2lyY2xlXG5cblxuICAgICAgICBpZiAoY2hlY2tJbkVsbGlwc2UoeCwgeSwgZGlhbSwgZGlhbSwgY2VudGVyWCAtIHdpZHRoIC8gMiArIGNvcm5lclJhZGl1cywgY2VudGVyWSArIGhlaWdodCAvIDIgLSBjb3JuZXJSYWRpdXMsIHBhZGRpbmcpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfTtcbiAgfTtcblxuICBCUnAkMi5yZWdpc3Rlck5vZGVTaGFwZXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIG5vZGVTaGFwZXMgPSB0aGlzLm5vZGVTaGFwZXMgPSB7fTtcbiAgICB2YXIgcmVuZGVyZXIgPSB0aGlzO1xuICAgIHRoaXMuZ2VuZXJhdGVFbGxpcHNlKCk7XG4gICAgdGhpcy5nZW5lcmF0ZVBvbHlnb24oJ3RyaWFuZ2xlJywgZ2VuZXJhdGVVbml0TmdvblBvaW50c0ZpdFRvU3F1YXJlKDMsIDApKTtcbiAgICB0aGlzLmdlbmVyYXRlUm91bmRQb2x5Z29uKCdyb3VuZC10cmlhbmdsZScsIGdlbmVyYXRlVW5pdE5nb25Qb2ludHNGaXRUb1NxdWFyZSgzLCAwKSk7XG4gICAgdGhpcy5nZW5lcmF0ZVBvbHlnb24oJ3JlY3RhbmdsZScsIGdlbmVyYXRlVW5pdE5nb25Qb2ludHNGaXRUb1NxdWFyZSg0LCAwKSk7XG4gICAgbm9kZVNoYXBlc1snc3F1YXJlJ10gPSBub2RlU2hhcGVzWydyZWN0YW5nbGUnXTtcbiAgICB0aGlzLmdlbmVyYXRlUm91bmRSZWN0YW5nbGUoKTtcbiAgICB0aGlzLmdlbmVyYXRlQ3V0UmVjdGFuZ2xlKCk7XG4gICAgdGhpcy5nZW5lcmF0ZUJhcnJlbCgpO1xuICAgIHRoaXMuZ2VuZXJhdGVCb3R0b21Sb3VuZHJlY3RhbmdsZSgpO1xuICAgIHtcbiAgICAgIHZhciBkaWFtb25kUG9pbnRzID0gWzAsIDEsIDEsIDAsIDAsIC0xLCAtMSwgMF07XG4gICAgICB0aGlzLmdlbmVyYXRlUG9seWdvbignZGlhbW9uZCcsIGRpYW1vbmRQb2ludHMpO1xuICAgICAgdGhpcy5nZW5lcmF0ZVJvdW5kUG9seWdvbigncm91bmQtZGlhbW9uZCcsIGRpYW1vbmRQb2ludHMpO1xuICAgIH1cbiAgICB0aGlzLmdlbmVyYXRlUG9seWdvbigncGVudGFnb24nLCBnZW5lcmF0ZVVuaXROZ29uUG9pbnRzRml0VG9TcXVhcmUoNSwgMCkpO1xuICAgIHRoaXMuZ2VuZXJhdGVSb3VuZFBvbHlnb24oJ3JvdW5kLXBlbnRhZ29uJywgZ2VuZXJhdGVVbml0TmdvblBvaW50c0ZpdFRvU3F1YXJlKDUsIDApKTtcbiAgICB0aGlzLmdlbmVyYXRlUG9seWdvbignaGV4YWdvbicsIGdlbmVyYXRlVW5pdE5nb25Qb2ludHNGaXRUb1NxdWFyZSg2LCAwKSk7XG4gICAgdGhpcy5nZW5lcmF0ZVJvdW5kUG9seWdvbigncm91bmQtaGV4YWdvbicsIGdlbmVyYXRlVW5pdE5nb25Qb2ludHNGaXRUb1NxdWFyZSg2LCAwKSk7XG4gICAgdGhpcy5nZW5lcmF0ZVBvbHlnb24oJ2hlcHRhZ29uJywgZ2VuZXJhdGVVbml0TmdvblBvaW50c0ZpdFRvU3F1YXJlKDcsIDApKTtcbiAgICB0aGlzLmdlbmVyYXRlUm91bmRQb2x5Z29uKCdyb3VuZC1oZXB0YWdvbicsIGdlbmVyYXRlVW5pdE5nb25Qb2ludHNGaXRUb1NxdWFyZSg3LCAwKSk7XG4gICAgdGhpcy5nZW5lcmF0ZVBvbHlnb24oJ29jdGFnb24nLCBnZW5lcmF0ZVVuaXROZ29uUG9pbnRzRml0VG9TcXVhcmUoOCwgMCkpO1xuICAgIHRoaXMuZ2VuZXJhdGVSb3VuZFBvbHlnb24oJ3JvdW5kLW9jdGFnb24nLCBnZW5lcmF0ZVVuaXROZ29uUG9pbnRzRml0VG9TcXVhcmUoOCwgMCkpO1xuICAgIHZhciBzdGFyNVBvaW50cyA9IG5ldyBBcnJheSgyMCk7XG4gICAge1xuICAgICAgdmFyIG91dGVyUG9pbnRzID0gZ2VuZXJhdGVVbml0TmdvblBvaW50cyg1LCAwKTtcbiAgICAgIHZhciBpbm5lclBvaW50cyA9IGdlbmVyYXRlVW5pdE5nb25Qb2ludHMoNSwgTWF0aC5QSSAvIDUpOyAvLyBPdXRlciByYWRpdXMgaXMgMTsgaW5uZXIgcmFkaXVzIG9mIHN0YXIgaXMgc21hbGxlclxuXG4gICAgICB2YXIgaW5uZXJSYWRpdXMgPSAwLjUgKiAoMyAtIE1hdGguc3FydCg1KSk7XG4gICAgICBpbm5lclJhZGl1cyAqPSAxLjU3O1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGlubmVyUG9pbnRzLmxlbmd0aCAvIDI7IGkrKykge1xuICAgICAgICBpbm5lclBvaW50c1tpICogMl0gKj0gaW5uZXJSYWRpdXM7XG4gICAgICAgIGlubmVyUG9pbnRzW2kgKiAyICsgMV0gKj0gaW5uZXJSYWRpdXM7XG4gICAgICB9XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgMjAgLyA0OyBpKyspIHtcbiAgICAgICAgc3RhcjVQb2ludHNbaSAqIDRdID0gb3V0ZXJQb2ludHNbaSAqIDJdO1xuICAgICAgICBzdGFyNVBvaW50c1tpICogNCArIDFdID0gb3V0ZXJQb2ludHNbaSAqIDIgKyAxXTtcbiAgICAgICAgc3RhcjVQb2ludHNbaSAqIDQgKyAyXSA9IGlubmVyUG9pbnRzW2kgKiAyXTtcbiAgICAgICAgc3RhcjVQb2ludHNbaSAqIDQgKyAzXSA9IGlubmVyUG9pbnRzW2kgKiAyICsgMV07XG4gICAgICB9XG4gICAgfVxuICAgIHN0YXI1UG9pbnRzID0gZml0UG9seWdvblRvU3F1YXJlKHN0YXI1UG9pbnRzKTtcbiAgICB0aGlzLmdlbmVyYXRlUG9seWdvbignc3RhcicsIHN0YXI1UG9pbnRzKTtcbiAgICB0aGlzLmdlbmVyYXRlUG9seWdvbigndmVlJywgWy0xLCAtMSwgMCwgLTAuMzMzLCAxLCAtMSwgMCwgMV0pO1xuICAgIHRoaXMuZ2VuZXJhdGVQb2x5Z29uKCdyaG9tYm9pZCcsIFstMSwgLTEsIDAuMzMzLCAtMSwgMSwgMSwgLTAuMzMzLCAxXSk7XG4gICAgdGhpcy5nZW5lcmF0ZVBvbHlnb24oJ3JpZ2h0LXJob21ib2lkJywgWy0wLjMzMywgLTEsIDEsIC0xLCAwLjMzMywgMSwgLTEsIDFdKTtcbiAgICB0aGlzLm5vZGVTaGFwZXNbJ2NvbmNhdmVoZXhhZ29uJ10gPSB0aGlzLmdlbmVyYXRlUG9seWdvbignY29uY2F2ZS1oZXhhZ29uJywgWy0xLCAtMC45NSwgLTAuNzUsIDAsIC0xLCAwLjk1LCAxLCAwLjk1LCAwLjc1LCAwLCAxLCAtMC45NV0pO1xuICAgIHtcbiAgICAgIHZhciB0YWdQb2ludHMgPSBbLTEsIC0xLCAwLjI1LCAtMSwgMSwgMCwgMC4yNSwgMSwgLTEsIDFdO1xuICAgICAgdGhpcy5nZW5lcmF0ZVBvbHlnb24oJ3RhZycsIHRhZ1BvaW50cyk7XG4gICAgICB0aGlzLmdlbmVyYXRlUm91bmRQb2x5Z29uKCdyb3VuZC10YWcnLCB0YWdQb2ludHMpO1xuICAgIH1cblxuICAgIG5vZGVTaGFwZXMubWFrZVBvbHlnb24gPSBmdW5jdGlvbiAocG9pbnRzKSB7XG4gICAgICAvLyB1c2UgY2FjaGluZyBvbiB1c2VyLXNwZWNpZmllZCBwb2x5Z29ucyBzbyB0aGV5IGFyZSBhcyBmYXN0IGFzIG5hdGl2ZSBzaGFwZXNcbiAgICAgIHZhciBrZXkgPSBwb2ludHMuam9pbignJCcpO1xuICAgICAgdmFyIG5hbWUgPSAncG9seWdvbi0nICsga2V5O1xuICAgICAgdmFyIHNoYXBlO1xuXG4gICAgICBpZiAoc2hhcGUgPSB0aGlzW25hbWVdKSB7XG4gICAgICAgIC8vIGdvdCBjYWNoZWQgc2hhcGVcbiAgICAgICAgcmV0dXJuIHNoYXBlO1xuICAgICAgfSAvLyBjcmVhdGUgYW5kIGNhY2hlIG5ldyBzaGFwZVxuXG5cbiAgICAgIHJldHVybiByZW5kZXJlci5nZW5lcmF0ZVBvbHlnb24obmFtZSwgcG9pbnRzKTtcbiAgICB9O1xuICB9O1xuXG4gIHZhciBCUnAkMSA9IHt9O1xuXG4gIEJScCQxLnRpbWVUb1JlbmRlciA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRyYXdUb3RhbFRpbWUgLyB0aGlzLnJlZHJhd0NvdW50O1xuICB9O1xuXG4gIEJScCQxLnJlZHJhdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwgc3RhdGljRW1wdHlPYmplY3QoKTtcbiAgICB2YXIgciA9IHRoaXM7XG5cbiAgICBpZiAoci5hdmVyYWdlUmVkcmF3VGltZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByLmF2ZXJhZ2VSZWRyYXdUaW1lID0gMDtcbiAgICB9XG5cbiAgICBpZiAoci5sYXN0UmVkcmF3VGltZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByLmxhc3RSZWRyYXdUaW1lID0gMDtcbiAgICB9XG5cbiAgICBpZiAoci5sYXN0RHJhd1RpbWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgci5sYXN0RHJhd1RpbWUgPSAwO1xuICAgIH1cblxuICAgIHIucmVxdWVzdGVkRnJhbWUgPSB0cnVlO1xuICAgIHIucmVuZGVyT3B0aW9ucyA9IG9wdGlvbnM7XG4gIH07XG5cbiAgQlJwJDEuYmVmb3JlUmVuZGVyID0gZnVuY3Rpb24gKGZuLCBwcmlvcml0eSkge1xuICAgIC8vIHRoZSByZW5kZXJlciBjYW4ndCBhZGQgdGljayBjYWxsYmFja3Mgd2hlbiBkZXN0cm95ZWRcbiAgICBpZiAodGhpcy5kZXN0cm95ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAocHJpb3JpdHkgPT0gbnVsbCkge1xuICAgICAgZXJyb3IoJ1ByaW9yaXR5IGlzIG5vdCBvcHRpb25hbCBmb3IgYmVmb3JlUmVuZGVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGNicyA9IHRoaXMuYmVmb3JlUmVuZGVyQ2FsbGJhY2tzO1xuICAgIGNicy5wdXNoKHtcbiAgICAgIGZuOiBmbixcbiAgICAgIHByaW9yaXR5OiBwcmlvcml0eVxuICAgIH0pOyAvLyBoaWdoZXIgcHJpb3JpdHkgY2FsbGJhY2tzIGV4ZWN1dGVkIGZpcnN0XG5cbiAgICBjYnMuc29ydChmdW5jdGlvbiAoYSwgYikge1xuICAgICAgcmV0dXJuIGIucHJpb3JpdHkgLSBhLnByaW9yaXR5O1xuICAgIH0pO1xuICB9O1xuXG4gIHZhciBiZWZvcmVSZW5kZXJDYWxsYmFja3MgPSBmdW5jdGlvbiBiZWZvcmVSZW5kZXJDYWxsYmFja3Mociwgd2lsbERyYXcsIHN0YXJ0VGltZSkge1xuICAgIHZhciBjYnMgPSByLmJlZm9yZVJlbmRlckNhbGxiYWNrcztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2JzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjYnNbaV0uZm4od2lsbERyYXcsIHN0YXJ0VGltZSk7XG4gICAgfVxuICB9O1xuXG4gIEJScCQxLnN0YXJ0UmVuZGVyTG9vcCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgciA9IHRoaXM7XG4gICAgdmFyIGN5ID0gci5jeTtcblxuICAgIGlmIChyLnJlbmRlckxvb3BTdGFydGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfSBlbHNlIHtcbiAgICAgIHIucmVuZGVyTG9vcFN0YXJ0ZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciByZW5kZXJGbiA9IGZ1bmN0aW9uIHJlbmRlckZuKHJlcXVlc3RUaW1lKSB7XG4gICAgICBpZiAoci5kZXN0cm95ZWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoY3kuYmF0Y2hpbmcoKSkgOyBlbHNlIGlmIChyLnJlcXVlc3RlZEZyYW1lICYmICFyLnNraXBGcmFtZSkge1xuICAgICAgICBiZWZvcmVSZW5kZXJDYWxsYmFja3MociwgdHJ1ZSwgcmVxdWVzdFRpbWUpO1xuICAgICAgICB2YXIgc3RhcnRUaW1lID0gcGVyZm9ybWFuY2VOb3coKTtcbiAgICAgICAgci5yZW5kZXIoci5yZW5kZXJPcHRpb25zKTtcbiAgICAgICAgdmFyIGVuZFRpbWUgPSByLmxhc3REcmF3VGltZSA9IHBlcmZvcm1hbmNlTm93KCk7XG5cbiAgICAgICAgaWYgKHIuYXZlcmFnZVJlZHJhd1RpbWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHIuYXZlcmFnZVJlZHJhd1RpbWUgPSBlbmRUaW1lIC0gc3RhcnRUaW1lO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHIucmVkcmF3Q291bnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHIucmVkcmF3Q291bnQgPSAwO1xuICAgICAgICB9XG5cbiAgICAgICAgci5yZWRyYXdDb3VudCsrO1xuXG4gICAgICAgIGlmIChyLnJlZHJhd1RvdGFsVGltZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgci5yZWRyYXdUb3RhbFRpbWUgPSAwO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGR1cmF0aW9uID0gZW5kVGltZSAtIHN0YXJ0VGltZTtcbiAgICAgICAgci5yZWRyYXdUb3RhbFRpbWUgKz0gZHVyYXRpb247XG4gICAgICAgIHIubGFzdFJlZHJhd1RpbWUgPSBkdXJhdGlvbjsgLy8gdXNlIGEgd2VpZ2h0ZWQgYXZlcmFnZSB3aXRoIGEgYmlhcyBmcm9tIHRoZSBwcmV2aW91cyBhdmVyYWdlIHNvIHdlIGRvbid0IHNwaWtlIHNvIGVhc2lseVxuXG4gICAgICAgIHIuYXZlcmFnZVJlZHJhd1RpbWUgPSByLmF2ZXJhZ2VSZWRyYXdUaW1lIC8gMiArIGR1cmF0aW9uIC8gMjtcbiAgICAgICAgci5yZXF1ZXN0ZWRGcmFtZSA9IGZhbHNlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYmVmb3JlUmVuZGVyQ2FsbGJhY2tzKHIsIGZhbHNlLCByZXF1ZXN0VGltZSk7XG4gICAgICB9XG5cbiAgICAgIHIuc2tpcEZyYW1lID0gZmFsc2U7XG4gICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUocmVuZGVyRm4pO1xuICAgIH07XG5cbiAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUocmVuZGVyRm4pO1xuICB9O1xuXG4gIHZhciBCYXNlUmVuZGVyZXIgPSBmdW5jdGlvbiBCYXNlUmVuZGVyZXIob3B0aW9ucykge1xuICAgIHRoaXMuaW5pdChvcHRpb25zKTtcbiAgfTtcblxuICB2YXIgQlIgPSBCYXNlUmVuZGVyZXI7XG4gIHZhciBCUnAgPSBCUi5wcm90b3R5cGU7XG4gIEJScC5jbGllbnRGdW5jdGlvbnMgPSBbJ3JlZHJhd0hpbnQnLCAncmVuZGVyJywgJ3JlbmRlclRvJywgJ21hdGNoQ2FudmFzU2l6ZScsICdub2RlU2hhcGVJbXBsJywgJ2Fycm93U2hhcGVJbXBsJ107XG5cbiAgQlJwLmluaXQgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHZhciByID0gdGhpcztcbiAgICByLm9wdGlvbnMgPSBvcHRpb25zO1xuICAgIHIuY3kgPSBvcHRpb25zLmN5O1xuICAgIHZhciBjdHIgPSByLmNvbnRhaW5lciA9IG9wdGlvbnMuY3kuY29udGFpbmVyKCk7XG4gICAgdmFyIGNvbnRhaW5lcldpbmRvdyA9IHIuY3kud2luZG93KCk7IC8vIHByZXBlbmQgYSBzdHlsZXNoZWV0IGluIHRoZSBoZWFkIHN1Y2ggdGhhdFxuXG4gICAgaWYgKGNvbnRhaW5lcldpbmRvdykge1xuICAgICAgdmFyIGRvY3VtZW50ID0gY29udGFpbmVyV2luZG93LmRvY3VtZW50O1xuICAgICAgdmFyIGhlYWQgPSBkb2N1bWVudC5oZWFkO1xuICAgICAgdmFyIHN0eWxlc2hlZXRJZCA9ICdfX19fX19fX19fY3l0b3NjYXBlX3N0eWxlc2hlZXQnO1xuICAgICAgdmFyIGNsYXNzTmFtZSA9ICdfX19fX19fX19fY3l0b3NjYXBlX2NvbnRhaW5lcic7XG4gICAgICB2YXIgc3R5bGVzaGVldEFscmVhZHlFeGlzdHMgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChzdHlsZXNoZWV0SWQpICE9IG51bGw7XG5cbiAgICAgIGlmIChjdHIuY2xhc3NOYW1lLmluZGV4T2YoY2xhc3NOYW1lKSA8IDApIHtcbiAgICAgICAgY3RyLmNsYXNzTmFtZSA9IChjdHIuY2xhc3NOYW1lIHx8ICcnKSArICcgJyArIGNsYXNzTmFtZTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFzdHlsZXNoZWV0QWxyZWFkeUV4aXN0cykge1xuICAgICAgICB2YXIgc3R5bGVzaGVldCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3N0eWxlJyk7XG4gICAgICAgIHN0eWxlc2hlZXQuaWQgPSBzdHlsZXNoZWV0SWQ7XG4gICAgICAgIHN0eWxlc2hlZXQudGV4dENvbnRlbnQgPSAnLicgKyBjbGFzc05hbWUgKyAnIHsgcG9zaXRpb246IHJlbGF0aXZlOyB9JztcbiAgICAgICAgaGVhZC5pbnNlcnRCZWZvcmUoc3R5bGVzaGVldCwgaGVhZC5jaGlsZHJlblswXSk7IC8vIGZpcnN0IHNvIGxvd2VzdCBwcmlvcml0eVxuICAgICAgfVxuXG4gICAgICB2YXIgY29tcHV0ZWRTdHlsZSA9IGNvbnRhaW5lcldpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGN0cik7XG4gICAgICB2YXIgcG9zaXRpb24gPSBjb21wdXRlZFN0eWxlLmdldFByb3BlcnR5VmFsdWUoJ3Bvc2l0aW9uJyk7XG5cbiAgICAgIGlmIChwb3NpdGlvbiA9PT0gJ3N0YXRpYycpIHtcbiAgICAgICAgd2FybignQSBDeXRvc2NhcGUgY29udGFpbmVyIGhhcyBzdHlsZSBwb3NpdGlvbjpzdGF0aWMgYW5kIHNvIGNhbiBub3QgdXNlIFVJIGV4dGVuc2lvbnMgcHJvcGVybHknKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByLnNlbGVjdGlvbiA9IFt1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIDBdOyAvLyBDb29yZGluYXRlcyBmb3Igc2VsZWN0aW9uIGJveCwgcGx1cyBlbmFibGVkIGZsYWdcblxuICAgIHIuYmV6aWVyUHJvalBjdHMgPSBbMC4wNSwgMC4yMjUsIDAuNCwgMC41LCAwLjYsIDAuNzc1LCAwLjk1XTsgLy8tLVBvaW50ZXItcmVsYXRlZCBkYXRhXG5cbiAgICByLmhvdmVyRGF0YSA9IHtcbiAgICAgIGRvd246IG51bGwsXG4gICAgICBsYXN0OiBudWxsLFxuICAgICAgZG93blRpbWU6IG51bGwsXG4gICAgICB0cmlnZ2VyTW9kZTogbnVsbCxcbiAgICAgIGRyYWdnaW5nOiBmYWxzZSxcbiAgICAgIGluaXRpYWxQYW46IFtudWxsLCBudWxsXSxcbiAgICAgIGNhcHR1cmU6IGZhbHNlXG4gICAgfTtcbiAgICByLmRyYWdEYXRhID0ge1xuICAgICAgcG9zc2libGVEcmFnRWxlbWVudHM6IFtdXG4gICAgfTtcbiAgICByLnRvdWNoRGF0YSA9IHtcbiAgICAgIHN0YXJ0OiBudWxsLFxuICAgICAgY2FwdHVyZTogZmFsc2UsXG4gICAgICAvLyBUaGVzZSAzIGZpZWxkcyByZWxhdGVkIHRvIHRhcCwgdGFwaG9sZCBldmVudHNcbiAgICAgIHN0YXJ0UG9zaXRpb246IFtudWxsLCBudWxsLCBudWxsLCBudWxsLCBudWxsLCBudWxsXSxcbiAgICAgIHNpbmdsZVRvdWNoU3RhcnRUaW1lOiBudWxsLFxuICAgICAgc2luZ2xlVG91Y2hNb3ZlZDogdHJ1ZSxcbiAgICAgIG5vdzogW251bGwsIG51bGwsIG51bGwsIG51bGwsIG51bGwsIG51bGxdLFxuICAgICAgZWFybGllcjogW251bGwsIG51bGwsIG51bGwsIG51bGwsIG51bGwsIG51bGxdXG4gICAgfTtcbiAgICByLnJlZHJhd3MgPSAwO1xuICAgIHIuc2hvd0ZwcyA9IG9wdGlvbnMuc2hvd0ZwcztcbiAgICByLmRlYnVnID0gb3B0aW9ucy5kZWJ1ZztcbiAgICByLmhpZGVFZGdlc09uVmlld3BvcnQgPSBvcHRpb25zLmhpZGVFZGdlc09uVmlld3BvcnQ7XG4gICAgci50ZXh0dXJlT25WaWV3cG9ydCA9IG9wdGlvbnMudGV4dHVyZU9uVmlld3BvcnQ7XG4gICAgci53aGVlbFNlbnNpdGl2aXR5ID0gb3B0aW9ucy53aGVlbFNlbnNpdGl2aXR5O1xuICAgIHIubW90aW9uQmx1ckVuYWJsZWQgPSBvcHRpb25zLm1vdGlvbkJsdXI7IC8vIG9uIGJ5IGRlZmF1bHRcblxuICAgIHIuZm9yY2VkUGl4ZWxSYXRpbyA9IG51bWJlciQxKG9wdGlvbnMucGl4ZWxSYXRpbykgPyBvcHRpb25zLnBpeGVsUmF0aW8gOiBudWxsO1xuICAgIHIubW90aW9uQmx1ciA9IG9wdGlvbnMubW90aW9uQmx1cjsgLy8gZm9yIGluaXRpYWwga2ljayBvZmZcblxuICAgIHIubW90aW9uQmx1ck9wYWNpdHkgPSBvcHRpb25zLm1vdGlvbkJsdXJPcGFjaXR5O1xuICAgIHIubW90aW9uQmx1clRyYW5zcGFyZW5jeSA9IDEgLSByLm1vdGlvbkJsdXJPcGFjaXR5O1xuICAgIHIubW90aW9uQmx1clB4UmF0aW8gPSAxO1xuICAgIHIubWJQeFJCbHVycnkgPSAxOyAvLzAuODtcblxuICAgIHIubWluTWJMb3dRdWFsRnJhbWVzID0gNDtcbiAgICByLmZ1bGxRdWFsaXR5TWIgPSBmYWxzZTtcbiAgICByLmNsZWFyZWRGb3JNb3Rpb25CbHVyID0gW107XG4gICAgci5kZXNrdG9wVGFwVGhyZXNob2xkID0gb3B0aW9ucy5kZXNrdG9wVGFwVGhyZXNob2xkO1xuICAgIHIuZGVza3RvcFRhcFRocmVzaG9sZDIgPSBvcHRpb25zLmRlc2t0b3BUYXBUaHJlc2hvbGQgKiBvcHRpb25zLmRlc2t0b3BUYXBUaHJlc2hvbGQ7XG4gICAgci50b3VjaFRhcFRocmVzaG9sZCA9IG9wdGlvbnMudG91Y2hUYXBUaHJlc2hvbGQ7XG4gICAgci50b3VjaFRhcFRocmVzaG9sZDIgPSBvcHRpb25zLnRvdWNoVGFwVGhyZXNob2xkICogb3B0aW9ucy50b3VjaFRhcFRocmVzaG9sZDtcbiAgICByLnRhcGhvbGREdXJhdGlvbiA9IDUwMDtcbiAgICByLmJpbmRpbmdzID0gW107XG4gICAgci5iZWZvcmVSZW5kZXJDYWxsYmFja3MgPSBbXTtcbiAgICByLmJlZm9yZVJlbmRlclByaW9yaXRpZXMgPSB7XG4gICAgICAvLyBoaWdoZXIgcHJpb3JpdHkgZXhlY3MgYmVmb3JlIGxvd2VyIG9uZVxuICAgICAgYW5pbWF0aW9uczogNDAwLFxuICAgICAgZWxlQ2FsY3M6IDMwMCxcbiAgICAgIGVsZVR4ckRlcTogMjAwLFxuICAgICAgbHlyVHhyRGVxOiAxNTAsXG4gICAgICBseXJUeHJTa2lwOiAxMDBcbiAgICB9O1xuICAgIHIucmVnaXN0ZXJOb2RlU2hhcGVzKCk7XG4gICAgci5yZWdpc3RlckFycm93U2hhcGVzKCk7XG4gICAgci5yZWdpc3RlckNhbGN1bGF0aW9uTGlzdGVuZXJzKCk7XG4gIH07XG5cbiAgQlJwLm5vdGlmeSA9IGZ1bmN0aW9uIChldmVudE5hbWUsIGVsZXMpIHtcbiAgICB2YXIgciA9IHRoaXM7XG4gICAgdmFyIGN5ID0gci5jeTsgLy8gdGhlIHJlbmRlcmVyIGNhbid0IGJlIG5vdGlmaWVkIGFmdGVyIGl0J3MgZGVzdHJveWVkXG5cbiAgICBpZiAodGhpcy5kZXN0cm95ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoZXZlbnROYW1lID09PSAnaW5pdCcpIHtcbiAgICAgIHIubG9hZCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChldmVudE5hbWUgPT09ICdkZXN0cm95Jykge1xuICAgICAgci5kZXN0cm95KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGV2ZW50TmFtZSA9PT0gJ2FkZCcgfHwgZXZlbnROYW1lID09PSAncmVtb3ZlJyB8fCBldmVudE5hbWUgPT09ICdtb3ZlJyAmJiBjeS5oYXNDb21wb3VuZE5vZGVzKCkgfHwgZXZlbnROYW1lID09PSAnbG9hZCcgfHwgZXZlbnROYW1lID09PSAnem9yZGVyJyB8fCBldmVudE5hbWUgPT09ICdtb3VudCcpIHtcbiAgICAgIHIuaW52YWxpZGF0ZUNhY2hlZFpTb3J0ZWRFbGVzKCk7XG4gICAgfVxuXG4gICAgaWYgKGV2ZW50TmFtZSA9PT0gJ3ZpZXdwb3J0Jykge1xuICAgICAgci5yZWRyYXdIaW50KCdzZWxlY3QnLCB0cnVlKTtcbiAgICB9XG5cbiAgICBpZiAoZXZlbnROYW1lID09PSAnbG9hZCcgfHwgZXZlbnROYW1lID09PSAncmVzaXplJyB8fCBldmVudE5hbWUgPT09ICdtb3VudCcpIHtcbiAgICAgIHIuaW52YWxpZGF0ZUNvbnRhaW5lckNsaWVudENvb3Jkc0NhY2hlKCk7XG4gICAgICByLm1hdGNoQ2FudmFzU2l6ZShyLmNvbnRhaW5lcik7XG4gICAgfVxuXG4gICAgci5yZWRyYXdIaW50KCdlbGVzJywgdHJ1ZSk7XG4gICAgci5yZWRyYXdIaW50KCdkcmFnJywgdHJ1ZSk7XG4gICAgdGhpcy5zdGFydFJlbmRlckxvb3AoKTtcbiAgICB0aGlzLnJlZHJhdygpO1xuICB9O1xuXG4gIEJScC5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciByID0gdGhpcztcbiAgICByLmRlc3Ryb3llZCA9IHRydWU7XG4gICAgci5jeS5zdG9wQW5pbWF0aW9uTG9vcCgpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCByLmJpbmRpbmdzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgYmluZGluZyA9IHIuYmluZGluZ3NbaV07XG4gICAgICB2YXIgYiA9IGJpbmRpbmc7XG4gICAgICB2YXIgdGd0ID0gYi50YXJnZXQ7XG4gICAgICAodGd0Lm9mZiB8fCB0Z3QucmVtb3ZlRXZlbnRMaXN0ZW5lcikuYXBwbHkodGd0LCBiLmFyZ3MpO1xuICAgIH1cblxuICAgIHIuYmluZGluZ3MgPSBbXTtcbiAgICByLmJlZm9yZVJlbmRlckNhbGxiYWNrcyA9IFtdO1xuICAgIHIub25VcGRhdGVFbGVDYWxjc0ZucyA9IFtdO1xuXG4gICAgaWYgKHIucmVtb3ZlT2JzZXJ2ZXIpIHtcbiAgICAgIHIucmVtb3ZlT2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xuICAgIH1cblxuICAgIGlmIChyLnN0eWxlT2JzZXJ2ZXIpIHtcbiAgICAgIHIuc3R5bGVPYnNlcnZlci5kaXNjb25uZWN0KCk7XG4gICAgfVxuXG4gICAgaWYgKHIucmVzaXplT2JzZXJ2ZXIpIHtcbiAgICAgIHIucmVzaXplT2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xuICAgIH1cblxuICAgIGlmIChyLmxhYmVsQ2FsY0Rpdikge1xuICAgICAgdHJ5IHtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChyLmxhYmVsQ2FsY0Rpdik7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbiAgICAgIH0gY2F0Y2ggKGUpIHsvLyBpZTEwIGlzc3VlICMxMDE0XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIEJScC5pc0hlYWRsZXNzID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfTtcblxuICBbQlJwJGYsIEJScCQ1LCBCUnAkNCwgQlJwJDMsIEJScCQyLCBCUnAkMV0uZm9yRWFjaChmdW5jdGlvbiAocHJvcHMpIHtcbiAgICBleHRlbmQoQlJwLCBwcm9wcyk7XG4gIH0pO1xuXG4gIHZhciBmdWxsRnBzVGltZSA9IDEwMDAgLyA2MDsgLy8gYXNzdW1lIDYwIGZyYW1lcyBwZXIgc2Vjb25kXG5cbiAgdmFyIGRlZnMgPSB7XG4gICAgc2V0dXBEZXF1ZXVlaW5nOiBmdW5jdGlvbiBzZXR1cERlcXVldWVpbmcob3B0cykge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uIHNldHVwRGVxdWV1ZWluZ0ltcGwoKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgdmFyIHIgPSB0aGlzLnJlbmRlcmVyO1xuXG4gICAgICAgIGlmIChzZWxmLmRlcXVldWVpbmdTZXR1cCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZWxmLmRlcXVldWVpbmdTZXR1cCA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcXVldWVSZWRyYXcgPSBkZWJvdW5jZV8xKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByLnJlZHJhd0hpbnQoJ2VsZXMnLCB0cnVlKTtcbiAgICAgICAgICByLnJlZHJhd0hpbnQoJ2RyYWcnLCB0cnVlKTtcbiAgICAgICAgICByLnJlZHJhdygpO1xuICAgICAgICB9LCBvcHRzLmRlcVJlZHJhd1RocmVzaG9sZCk7XG5cbiAgICAgICAgdmFyIGRlcXVldWUgPSBmdW5jdGlvbiBkZXF1ZXVlKHdpbGxEcmF3LCBmcmFtZVN0YXJ0VGltZSkge1xuICAgICAgICAgIHZhciBzdGFydFRpbWUgPSBwZXJmb3JtYW5jZU5vdygpO1xuICAgICAgICAgIHZhciBhdmdSZW5kZXJUaW1lID0gci5hdmVyYWdlUmVkcmF3VGltZTtcbiAgICAgICAgICB2YXIgcmVuZGVyVGltZSA9IHIubGFzdFJlZHJhd1RpbWU7XG4gICAgICAgICAgdmFyIGRlcWQgPSBbXTtcbiAgICAgICAgICB2YXIgZXh0ZW50ID0gci5jeS5leHRlbnQoKTtcbiAgICAgICAgICB2YXIgcGl4ZWxSYXRpbyA9IHIuZ2V0UGl4ZWxSYXRpbygpOyAvLyBpZiB3ZSBhcmVuJ3QgaW4gYSB0aWNrIHRoYXQgY2F1c2VzIGEgZHJhdywgdGhlbiB0aGUgcmVuZGVyZWQgc3R5bGVcbiAgICAgICAgICAvLyBxdWV1ZSB3b24ndCBhdXRvbWF0aWNhbGx5IGJlIGZsdXNoZWQgYmVmb3JlIGRlcXVldWVpbmcgc3RhcnRzXG5cbiAgICAgICAgICBpZiAoIXdpbGxEcmF3KSB7XG4gICAgICAgICAgICByLmZsdXNoUmVuZGVyZWRTdHlsZVF1ZXVlKCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tY29uc3RhbnQtY29uZGl0aW9uXG4gICAgICAgICAgICB2YXIgbm93ID0gcGVyZm9ybWFuY2VOb3coKTtcbiAgICAgICAgICAgIHZhciBkdXJhdGlvbiA9IG5vdyAtIHN0YXJ0VGltZTtcbiAgICAgICAgICAgIHZhciBmcmFtZUR1cmF0aW9uID0gbm93IC0gZnJhbWVTdGFydFRpbWU7XG5cbiAgICAgICAgICAgIGlmIChyZW5kZXJUaW1lIDwgZnVsbEZwc1RpbWUpIHtcbiAgICAgICAgICAgICAgLy8gaWYgd2UncmUgcmVuZGVyaW5nIGZhc3RlciB0aGFuIHRoZSBpZGVhbCBmcHMsIHRoZW4gZG8gZGVxdWV1ZWluZ1xuICAgICAgICAgICAgICAvLyBkdXJpbmcgYWxsIG9mIHRoZSByZW1haW5pbmcgZnJhbWUgdGltZVxuICAgICAgICAgICAgICB2YXIgdGltZUF2YWlsYWJsZSA9IGZ1bGxGcHNUaW1lIC0gKHdpbGxEcmF3ID8gYXZnUmVuZGVyVGltZSA6IDApO1xuXG4gICAgICAgICAgICAgIGlmIChmcmFtZUR1cmF0aW9uID49IG9wdHMuZGVxRmFzdENvc3QgKiB0aW1lQXZhaWxhYmxlKSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGlmICh3aWxsRHJhdykge1xuICAgICAgICAgICAgICAgIGlmIChkdXJhdGlvbiA+PSBvcHRzLmRlcUNvc3QgKiByZW5kZXJUaW1lIHx8IGR1cmF0aW9uID49IG9wdHMuZGVxQXZnQ29zdCAqIGF2Z1JlbmRlclRpbWUpIHtcbiAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSBlbHNlIGlmIChmcmFtZUR1cmF0aW9uID49IG9wdHMuZGVxTm9EcmF3Q29zdCAqIGZ1bGxGcHNUaW1lKSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHRoaXNEZXFkID0gb3B0cy5kZXEoc2VsZiwgcGl4ZWxSYXRpbywgZXh0ZW50KTtcblxuICAgICAgICAgICAgaWYgKHRoaXNEZXFkLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzRGVxZC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGRlcWQucHVzaCh0aGlzRGVxZFtpXSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gY2FsbGJhY2tzIG9uIGRlcXVldWVcblxuXG4gICAgICAgICAgaWYgKGRlcWQubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgb3B0cy5vbkRlcWQoc2VsZiwgZGVxZCk7XG5cbiAgICAgICAgICAgIGlmICghd2lsbERyYXcgJiYgb3B0cy5zaG91bGRSZWRyYXcoc2VsZiwgZGVxZCwgcGl4ZWxSYXRpbywgZXh0ZW50KSkge1xuICAgICAgICAgICAgICBxdWV1ZVJlZHJhdygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgcHJpb3JpdHkgPSBvcHRzLnByaW9yaXR5IHx8IG5vb3AkMTtcbiAgICAgICAgci5iZWZvcmVSZW5kZXIoZGVxdWV1ZSwgcHJpb3JpdHkoc2VsZikpO1xuICAgICAgfTtcbiAgICB9XG4gIH07XG5cbiAgLy8gVXNlcyBrZXlzIHNvIGVsZW1lbnRzIG1heSBzaGFyZSB0aGUgc2FtZSBjYWNoZS5cblxuICB2YXIgRWxlbWVudFRleHR1cmVDYWNoZUxvb2t1cCA9IC8qI19fUFVSRV9fKi9mdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gRWxlbWVudFRleHR1cmVDYWNoZUxvb2t1cChnZXRLZXkpIHtcbiAgICAgIHZhciBkb2VzRWxlSW52YWxpZGF0ZUtleSA9IGFyZ3VtZW50cy5sZW5ndGggPiAxICYmIGFyZ3VtZW50c1sxXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzFdIDogZmFsc2lmeTtcblxuICAgICAgX2NsYXNzQ2FsbENoZWNrKHRoaXMsIEVsZW1lbnRUZXh0dXJlQ2FjaGVMb29rdXApO1xuXG4gICAgICB0aGlzLmlkc0J5S2V5ID0gbmV3IE1hcCQyKCk7XG4gICAgICB0aGlzLmtleUZvcklkID0gbmV3IE1hcCQyKCk7XG4gICAgICB0aGlzLmNhY2hlc0J5THZsID0gbmV3IE1hcCQyKCk7XG4gICAgICB0aGlzLmx2bHMgPSBbXTtcbiAgICAgIHRoaXMuZ2V0S2V5ID0gZ2V0S2V5O1xuICAgICAgdGhpcy5kb2VzRWxlSW52YWxpZGF0ZUtleSA9IGRvZXNFbGVJbnZhbGlkYXRlS2V5O1xuICAgIH1cblxuICAgIF9jcmVhdGVDbGFzcyhFbGVtZW50VGV4dHVyZUNhY2hlTG9va3VwLCBbe1xuICAgICAga2V5OiBcImdldElkc0ZvclwiLFxuICAgICAgdmFsdWU6IGZ1bmN0aW9uIGdldElkc0ZvcihrZXkpIHtcbiAgICAgICAgaWYgKGtleSA9PSBudWxsKSB7XG4gICAgICAgICAgZXJyb3IoXCJDYW4gbm90IGdldCBpZCBsaXN0IGZvciBudWxsIGtleVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBpZHNCeUtleSA9IHRoaXMuaWRzQnlLZXk7XG4gICAgICAgIHZhciBpZHMgPSB0aGlzLmlkc0J5S2V5LmdldChrZXkpO1xuXG4gICAgICAgIGlmICghaWRzKSB7XG4gICAgICAgICAgaWRzID0gbmV3IFNldCQxKCk7XG4gICAgICAgICAgaWRzQnlLZXkuc2V0KGtleSwgaWRzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBpZHM7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcImFkZElkRm9yS2V5XCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gYWRkSWRGb3JLZXkoa2V5LCBpZCkge1xuICAgICAgICBpZiAoa2V5ICE9IG51bGwpIHtcbiAgICAgICAgICB0aGlzLmdldElkc0ZvcihrZXkpLmFkZChpZCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiZGVsZXRlSWRGb3JLZXlcIixcbiAgICAgIHZhbHVlOiBmdW5jdGlvbiBkZWxldGVJZEZvcktleShrZXksIGlkKSB7XG4gICAgICAgIGlmIChrZXkgIT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMuZ2V0SWRzRm9yKGtleSlbXCJkZWxldGVcIl0oaWQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcImdldE51bWJlck9mSWRzRm9yS2V5XCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gZ2V0TnVtYmVyT2ZJZHNGb3JLZXkoa2V5KSB7XG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiB0aGlzLmdldElkc0ZvcihrZXkpLnNpemU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwidXBkYXRlS2V5TWFwcGluZ0ZvclwiLFxuICAgICAgdmFsdWU6IGZ1bmN0aW9uIHVwZGF0ZUtleU1hcHBpbmdGb3IoZWxlKSB7XG4gICAgICAgIHZhciBpZCA9IGVsZS5pZCgpO1xuICAgICAgICB2YXIgcHJldktleSA9IHRoaXMua2V5Rm9ySWQuZ2V0KGlkKTtcbiAgICAgICAgdmFyIGN1cnJLZXkgPSB0aGlzLmdldEtleShlbGUpO1xuICAgICAgICB0aGlzLmRlbGV0ZUlkRm9yS2V5KHByZXZLZXksIGlkKTtcbiAgICAgICAgdGhpcy5hZGRJZEZvcktleShjdXJyS2V5LCBpZCk7XG4gICAgICAgIHRoaXMua2V5Rm9ySWQuc2V0KGlkLCBjdXJyS2V5KTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiZGVsZXRlS2V5TWFwcGluZ0ZvclwiLFxuICAgICAgdmFsdWU6IGZ1bmN0aW9uIGRlbGV0ZUtleU1hcHBpbmdGb3IoZWxlKSB7XG4gICAgICAgIHZhciBpZCA9IGVsZS5pZCgpO1xuICAgICAgICB2YXIgcHJldktleSA9IHRoaXMua2V5Rm9ySWQuZ2V0KGlkKTtcbiAgICAgICAgdGhpcy5kZWxldGVJZEZvcktleShwcmV2S2V5LCBpZCk7XG4gICAgICAgIHRoaXMua2V5Rm9ySWRbXCJkZWxldGVcIl0oaWQpO1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJrZXlIYXNDaGFuZ2VkRm9yXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24ga2V5SGFzQ2hhbmdlZEZvcihlbGUpIHtcbiAgICAgICAgdmFyIGlkID0gZWxlLmlkKCk7XG4gICAgICAgIHZhciBwcmV2S2V5ID0gdGhpcy5rZXlGb3JJZC5nZXQoaWQpO1xuICAgICAgICB2YXIgbmV3S2V5ID0gdGhpcy5nZXRLZXkoZWxlKTtcbiAgICAgICAgcmV0dXJuIHByZXZLZXkgIT09IG5ld0tleTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiaXNJbnZhbGlkXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gaXNJbnZhbGlkKGVsZSkge1xuICAgICAgICByZXR1cm4gdGhpcy5rZXlIYXNDaGFuZ2VkRm9yKGVsZSkgfHwgdGhpcy5kb2VzRWxlSW52YWxpZGF0ZUtleShlbGUpO1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJnZXRDYWNoZXNBdFwiLFxuICAgICAgdmFsdWU6IGZ1bmN0aW9uIGdldENhY2hlc0F0KGx2bCkge1xuICAgICAgICB2YXIgY2FjaGVzQnlMdmwgPSB0aGlzLmNhY2hlc0J5THZsLFxuICAgICAgICAgICAgbHZscyA9IHRoaXMubHZscztcbiAgICAgICAgdmFyIGNhY2hlcyA9IGNhY2hlc0J5THZsLmdldChsdmwpO1xuXG4gICAgICAgIGlmICghY2FjaGVzKSB7XG4gICAgICAgICAgY2FjaGVzID0gbmV3IE1hcCQyKCk7XG4gICAgICAgICAgY2FjaGVzQnlMdmwuc2V0KGx2bCwgY2FjaGVzKTtcbiAgICAgICAgICBsdmxzLnB1c2gobHZsKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBjYWNoZXM7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcImdldENhY2hlXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gZ2V0Q2FjaGUoa2V5LCBsdmwpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0Q2FjaGVzQXQobHZsKS5nZXQoa2V5KTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiZ2V0XCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gZ2V0KGVsZSwgbHZsKSB7XG4gICAgICAgIHZhciBrZXkgPSB0aGlzLmdldEtleShlbGUpO1xuICAgICAgICB2YXIgY2FjaGUgPSB0aGlzLmdldENhY2hlKGtleSwgbHZsKTsgLy8gZ2V0dGluZyBmb3IgYW4gZWxlbWVudCBtYXkgbmVlZCB0byBhZGQgdG8gdGhlIGlkIGxpc3QgYi9jIGVsZXMgY2FuIHNoYXJlIGtleXNcblxuICAgICAgICBpZiAoY2FjaGUgIT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMudXBkYXRlS2V5TWFwcGluZ0ZvcihlbGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlO1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJnZXRGb3JDYWNoZWRLZXlcIixcbiAgICAgIHZhbHVlOiBmdW5jdGlvbiBnZXRGb3JDYWNoZWRLZXkoZWxlLCBsdmwpIHtcbiAgICAgICAgdmFyIGtleSA9IHRoaXMua2V5Rm9ySWQuZ2V0KGVsZS5pZCgpKTsgLy8gbi5iLiB1c2UgY2FjaGVkIGtleSwgbm90IG5ld2x5IGNvbXB1dGVkIGtleVxuXG4gICAgICAgIHZhciBjYWNoZSA9IHRoaXMuZ2V0Q2FjaGUoa2V5LCBsdmwpO1xuICAgICAgICByZXR1cm4gY2FjaGU7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcImhhc0NhY2hlXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gaGFzQ2FjaGUoa2V5LCBsdmwpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0Q2FjaGVzQXQobHZsKS5oYXMoa2V5KTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiaGFzXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gaGFzKGVsZSwgbHZsKSB7XG4gICAgICAgIHZhciBrZXkgPSB0aGlzLmdldEtleShlbGUpO1xuICAgICAgICByZXR1cm4gdGhpcy5oYXNDYWNoZShrZXksIGx2bCk7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcInNldENhY2hlXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gc2V0Q2FjaGUoa2V5LCBsdmwsIGNhY2hlKSB7XG4gICAgICAgIGNhY2hlLmtleSA9IGtleTtcbiAgICAgICAgdGhpcy5nZXRDYWNoZXNBdChsdmwpLnNldChrZXksIGNhY2hlKTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwic2V0XCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gc2V0KGVsZSwgbHZsLCBjYWNoZSkge1xuICAgICAgICB2YXIga2V5ID0gdGhpcy5nZXRLZXkoZWxlKTtcbiAgICAgICAgdGhpcy5zZXRDYWNoZShrZXksIGx2bCwgY2FjaGUpO1xuICAgICAgICB0aGlzLnVwZGF0ZUtleU1hcHBpbmdGb3IoZWxlKTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiZGVsZXRlQ2FjaGVcIixcbiAgICAgIHZhbHVlOiBmdW5jdGlvbiBkZWxldGVDYWNoZShrZXksIGx2bCkge1xuICAgICAgICB0aGlzLmdldENhY2hlc0F0KGx2bClbXCJkZWxldGVcIl0oa2V5KTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiZGVsZXRlXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gX2RlbGV0ZShlbGUsIGx2bCkge1xuICAgICAgICB2YXIga2V5ID0gdGhpcy5nZXRLZXkoZWxlKTtcbiAgICAgICAgdGhpcy5kZWxldGVDYWNoZShrZXksIGx2bCk7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcImludmFsaWRhdGVLZXlcIixcbiAgICAgIHZhbHVlOiBmdW5jdGlvbiBpbnZhbGlkYXRlS2V5KGtleSkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHRoaXMubHZscy5mb3JFYWNoKGZ1bmN0aW9uIChsdmwpIHtcbiAgICAgICAgICByZXR1cm4gX3RoaXMuZGVsZXRlQ2FjaGUoa2V5LCBsdmwpO1xuICAgICAgICB9KTtcbiAgICAgIH0gLy8gcmV0dXJucyB0cnVlIGlmIG5vIG90aGVyIGVsZXMgcmVmZXJlbmNlIHRoZSBpbnZhbGlkYXRlZCBjYWNoZSAobi5iLiBvdGhlciBlbGVzIG1heSBuZWVkIHRoZSBjYWNoZSB3aXRoIHRoZSBzYW1lIGtleSlcblxuICAgIH0sIHtcbiAgICAgIGtleTogXCJpbnZhbGlkYXRlXCIsXG4gICAgICB2YWx1ZTogZnVuY3Rpb24gaW52YWxpZGF0ZShlbGUpIHtcbiAgICAgICAgdmFyIGlkID0gZWxlLmlkKCk7XG4gICAgICAgIHZhciBrZXkgPSB0aGlzLmtleUZvcklkLmdldChpZCk7IC8vIG4uYi4gdXNlIHN0b3JlZCBrZXkgcmF0aGVyIHRoYW4gY3VycmVudCAocG90ZW50aWFsIGtleSlcblxuICAgICAgICB0aGlzLmRlbGV0ZUtleU1hcHBpbmdGb3IoZWxlKTtcbiAgICAgICAgdmFyIGVudGlyZUtleUludmFsaWRhdGVkID0gdGhpcy5kb2VzRWxlSW52YWxpZGF0ZUtleShlbGUpO1xuXG4gICAgICAgIGlmIChlbnRpcmVLZXlJbnZhbGlkYXRlZCkge1xuICAgICAgICAgIC8vIGNsZWFyIG1hcHBpbmcgZm9yIGN1cnJlbnQga2V5XG4gICAgICAgICAgdGhpcy5pbnZhbGlkYXRlS2V5KGtleSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZW50aXJlS2V5SW52YWxpZGF0ZWQgfHwgdGhpcy5nZXROdW1iZXJPZklkc0ZvcktleShrZXkpID09PSAwO1xuICAgICAgfVxuICAgIH1dKTtcblxuICAgIHJldHVybiBFbGVtZW50VGV4dHVyZUNhY2hlTG9va3VwO1xuICB9KCk7XG5cbiAgdmFyIG1pblR4ckggPSAyNTsgLy8gdGhlIHNpemUgb2YgdGhlIHRleHR1cmUgY2FjaGUgZm9yIHNtYWxsIGhlaWdodCBlbGVzIChzcGVjaWFsIGNhc2UpXG5cbiAgdmFyIHR4clN0ZXBIID0gNTA7IC8vIHRoZSBtaW4gc2l6ZSBvZiB0aGUgcmVndWxhciBjYWNoZSwgYW5kIHRoZSBzaXplIGl0IGluY3JlYXNlcyB3aXRoIGVhY2ggc3RlcCB1cFxuXG4gIHZhciBtaW5MdmwkMSA9IC00OyAvLyB3aGVuIHNjYWxpbmcgc21hbGxlciB0aGFuIHRoYXQgd2UgZG9uJ3QgbmVlZCB0byByZS1yZW5kZXJcblxuICB2YXIgbWF4THZsJDEgPSAzOyAvLyB3aGVuIGxhcmdlciB0aGFuIHRoaXMgc2NhbGUganVzdCByZW5kZXIgZGlyZWN0bHkgKGNhY2hpbmcgaXMgbm90IGhlbHBmdWwpXG5cbiAgdmFyIG1heFpvb20kMSA9IDcuOTk7IC8vIGJleW9uZCB0aGlzIHpvb20gbGV2ZWwsIGxheWVyZWQgdGV4dHVyZXMgYXJlIG5vdCB1c2VkXG5cbiAgdmFyIGVsZVR4clNwYWNpbmcgPSA4OyAvLyBzcGFjaW5nIGJldHdlZW4gZWxlbWVudHMgb24gdGV4dHVyZXMgdG8gYXZvaWQgYmxpdHRpbmcgb3ZlcmxhcHNcblxuICB2YXIgZGVmVHhyV2lkdGggPSAxMDI0OyAvLyBkZWZhdWx0L21pbmltdW0gdGV4dHVyZSB3aWR0aFxuXG4gIHZhciBtYXhUeHJXID0gMTAyNDsgLy8gdGhlIG1heGltdW0gd2lkdGggb2YgYSB0ZXh0dXJlXG5cbiAgdmFyIG1heFR4ckggPSAxMDI0OyAvLyB0aGUgbWF4aW11bSBoZWlnaHQgb2YgYSB0ZXh0dXJlXG5cbiAgdmFyIG1pblV0aWxpdHkgPSAwLjI7IC8vIGlmIHVzYWdlIG9mIHRleHR1cmUgaXMgbGVzcyB0aGFuIHRoaXMsIGl0IGlzIHJldGlyZWRcblxuICB2YXIgbWF4RnVsbG5lc3MgPSAwLjg7IC8vIGZ1bGxuZXNzIG9mIHRleHR1cmUgYWZ0ZXIgd2hpY2ggcXVldWUgcmVtb3ZhbCBpcyBjaGVja2VkXG5cbiAgdmFyIG1heEZ1bGxuZXNzQ2hlY2tzID0gMTA7IC8vIGRlcXVldWVkIGFmdGVyIHRoaXMgbWFueSBjaGVja3NcblxuICB2YXIgZGVxQ29zdCQxID0gMC4xNTsgLy8gJSBvZiBhZGQnbCByZW5kZXJpbmcgY29zdCBhbGxvd2VkIGZvciBkZXF1ZXVpbmcgZWxlIGNhY2hlcyBlYWNoIGZyYW1lXG5cbiAgdmFyIGRlcUF2Z0Nvc3QkMSA9IDAuMTsgLy8gJSBvZiBhZGQnbCByZW5kZXJpbmcgY29zdCBjb21wYXJlZCB0byBhdmVyYWdlIG92ZXJhbGwgcmVkcmF3IHRpbWVcblxuICB2YXIgZGVxTm9EcmF3Q29zdCQxID0gMC45OyAvLyAlIG9mIGF2ZyBmcmFtZSB0aW1lIHRoYXQgY2FuIGJlIHVzZWQgZm9yIGRlcXVldWVpbmcgd2hlbiBub3QgZHJhd2luZ1xuXG4gIHZhciBkZXFGYXN0Q29zdCQxID0gMC45OyAvLyAlIG9mIGZyYW1lIHRpbWUgdG8gYmUgdXNlZCB3aGVuID42MGZwc1xuXG4gIHZhciBkZXFSZWRyYXdUaHJlc2hvbGQkMSA9IDEwMDsgLy8gdGltZSB0byBiYXRjaCByZWRyYXdzIHRvZ2V0aGVyIGZyb20gZGVxdWV1ZWluZyB0byBhbGxvdyBtb3JlIGRlcXVldWVpbmcgY2FsY3MgdG8gaGFwcGVuIGluIHRoZSBtZWFud2hpbGVcblxuICB2YXIgbWF4RGVxU2l6ZSQxID0gMTsgLy8gbnVtYmVyIG9mIGVsZXMgdG8gZGVxdWV1ZSBhbmQgcmVuZGVyIGF0IGhpZ2hlciB0ZXh0dXJlIGluIGVhY2ggYmF0Y2hcblxuICB2YXIgZ2V0VHhyUmVhc29ucyA9IHtcbiAgICBkZXF1ZXVlOiAnZGVxdWV1ZScsXG4gICAgZG93bnNjYWxlOiAnZG93bnNjYWxlJyxcbiAgICBoaWdoUXVhbGl0eTogJ2hpZ2hRdWFsaXR5J1xuICB9O1xuICB2YXIgaW5pdERlZmF1bHRzID0gZGVmYXVsdHMkZyh7XG4gICAgZ2V0S2V5OiBudWxsLFxuICAgIGRvZXNFbGVJbnZhbGlkYXRlS2V5OiBmYWxzaWZ5LFxuICAgIGRyYXdFbGVtZW50OiBudWxsLFxuICAgIGdldEJvdW5kaW5nQm94OiBudWxsLFxuICAgIGdldFJvdGF0aW9uUG9pbnQ6IG51bGwsXG4gICAgZ2V0Um90YXRpb25PZmZzZXQ6IG51bGwsXG4gICAgaXNWaXNpYmxlOiB0cnVlaWZ5LFxuICAgIGFsbG93RWRnZVR4ckNhY2hpbmc6IHRydWUsXG4gICAgYWxsb3dQYXJlbnRUeHJDYWNoaW5nOiB0cnVlXG4gIH0pO1xuXG4gIHZhciBFbGVtZW50VGV4dHVyZUNhY2hlID0gZnVuY3Rpb24gRWxlbWVudFRleHR1cmVDYWNoZShyZW5kZXJlciwgaW5pdE9wdGlvbnMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgc2VsZi5yZW5kZXJlciA9IHJlbmRlcmVyO1xuICAgIHNlbGYub25EZXF1ZXVlcyA9IFtdO1xuICAgIHZhciBvcHRzID0gaW5pdERlZmF1bHRzKGluaXRPcHRpb25zKTtcbiAgICBleHRlbmQoc2VsZiwgb3B0cyk7XG4gICAgc2VsZi5sb29rdXAgPSBuZXcgRWxlbWVudFRleHR1cmVDYWNoZUxvb2t1cChvcHRzLmdldEtleSwgb3B0cy5kb2VzRWxlSW52YWxpZGF0ZUtleSk7XG4gICAgc2VsZi5zZXR1cERlcXVldWVpbmcoKTtcbiAgfTtcblxuICB2YXIgRVRDcCA9IEVsZW1lbnRUZXh0dXJlQ2FjaGUucHJvdG90eXBlO1xuICBFVENwLnJlYXNvbnMgPSBnZXRUeHJSZWFzb25zOyAvLyB0aGUgbGlzdCBvZiB0ZXh0dXJlcyBpbiB3aGljaCBuZXcgc3VidGV4dHVyZXMgZm9yIGVsZW1lbnRzIGNhbiBiZSBwbGFjZWRcblxuICBFVENwLmdldFRleHR1cmVRdWV1ZSA9IGZ1bmN0aW9uICh0eHJIKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHNlbGYuZWxlSW1nQ2FjaGVzID0gc2VsZi5lbGVJbWdDYWNoZXMgfHwge307XG4gICAgcmV0dXJuIHNlbGYuZWxlSW1nQ2FjaGVzW3R4ckhdID0gc2VsZi5lbGVJbWdDYWNoZXNbdHhySF0gfHwgW107XG4gIH07IC8vIHRoZSBsaXN0IG9mIHVzdXNlZCB0ZXh0dXJlcyB3aGljaCBjYW4gYmUgcmVjeWNsZWQgKGluIHVzZSBpbiB0ZXh0dXJlIHF1ZXVlKVxuXG5cbiAgRVRDcC5nZXRSZXRpcmVkVGV4dHVyZVF1ZXVlID0gZnVuY3Rpb24gKHR4ckgpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHJ0eHRyUXMgPSBzZWxmLmVsZUltZ0NhY2hlcy5yZXRpcmVkID0gc2VsZi5lbGVJbWdDYWNoZXMucmV0aXJlZCB8fCB7fTtcbiAgICB2YXIgcnR4dHJRID0gcnR4dHJRc1t0eHJIXSA9IHJ0eHRyUXNbdHhySF0gfHwgW107XG4gICAgcmV0dXJuIHJ0eHRyUTtcbiAgfTsgLy8gcXVldWUgb2YgZWxlbWVudCBkcmF3IHJlcXVlc3RzIGF0IGRpZmZlcmVudCBzY2FsZSBsZXZlbHNcblxuXG4gIEVUQ3AuZ2V0RWxlbWVudFF1ZXVlID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgcSA9IHNlbGYuZWxlQ2FjaGVRdWV1ZSA9IHNlbGYuZWxlQ2FjaGVRdWV1ZSB8fCBuZXcgaGVhcChmdW5jdGlvbiAoYSwgYikge1xuICAgICAgcmV0dXJuIGIucmVxcyAtIGEucmVxcztcbiAgICB9KTtcbiAgICByZXR1cm4gcTtcbiAgfTsgLy8gcXVldWUgb2YgZWxlbWVudCBkcmF3IHJlcXVlc3RzIGF0IGRpZmZlcmVudCBzY2FsZSBsZXZlbHMgKGVsZW1lbnQgaWQgbG9va3VwKVxuXG5cbiAgRVRDcC5nZXRFbGVtZW50S2V5VG9RdWV1ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGsycSA9IHNlbGYuZWxlS2V5VG9DYWNoZVF1ZXVlID0gc2VsZi5lbGVLZXlUb0NhY2hlUXVldWUgfHwge307XG4gICAgcmV0dXJuIGsycTtcbiAgfTtcblxuICBFVENwLmdldEVsZW1lbnQgPSBmdW5jdGlvbiAoZWxlLCBiYiwgcHhSYXRpbywgbHZsLCByZWFzb24pIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHIgPSB0aGlzLnJlbmRlcmVyO1xuICAgIHZhciB6b29tID0gci5jeS56b29tKCk7XG4gICAgdmFyIGxvb2t1cCA9IHRoaXMubG9va3VwO1xuXG4gICAgaWYgKCFiYiB8fCBiYi53ID09PSAwIHx8IGJiLmggPT09IDAgfHwgaXNOYU4oYmIudykgfHwgaXNOYU4oYmIuaCkgfHwgIWVsZS52aXNpYmxlKCkgfHwgZWxlLnJlbW92ZWQoKSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgaWYgKCFzZWxmLmFsbG93RWRnZVR4ckNhY2hpbmcgJiYgZWxlLmlzRWRnZSgpIHx8ICFzZWxmLmFsbG93UGFyZW50VHhyQ2FjaGluZyAmJiBlbGUuaXNQYXJlbnQoKSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgaWYgKGx2bCA9PSBudWxsKSB7XG4gICAgICBsdmwgPSBNYXRoLmNlaWwobG9nMih6b29tICogcHhSYXRpbykpO1xuICAgIH1cblxuICAgIGlmIChsdmwgPCBtaW5MdmwkMSkge1xuICAgICAgbHZsID0gbWluTHZsJDE7XG4gICAgfSBlbHNlIGlmICh6b29tID49IG1heFpvb20kMSB8fCBsdmwgPiBtYXhMdmwkMSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgdmFyIHNjYWxlID0gTWF0aC5wb3coMiwgbHZsKTtcbiAgICB2YXIgZWxlU2NhbGVkSCA9IGJiLmggKiBzY2FsZTtcbiAgICB2YXIgZWxlU2NhbGVkVyA9IGJiLncgKiBzY2FsZTtcbiAgICB2YXIgc2NhbGVkTGFiZWxTaG93biA9IHIuZWxlVGV4dEJpZ2dlclRoYW5NaW4oZWxlLCBzY2FsZSk7XG5cbiAgICBpZiAoIXRoaXMuaXNWaXNpYmxlKGVsZSwgc2NhbGVkTGFiZWxTaG93bikpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHZhciBlbGVDYWNoZSA9IGxvb2t1cC5nZXQoZWxlLCBsdmwpOyAvLyBpZiB0aGlzIGdldCB3YXMgb24gYW4gdW51c2VkL2ludmFsaWRhdGVkIGNhY2hlLCB0aGVuIHJlc3RvcmUgdGhlIHRleHR1cmUgdXNhZ2UgbWV0cmljXG5cbiAgICBpZiAoZWxlQ2FjaGUgJiYgZWxlQ2FjaGUuaW52YWxpZGF0ZWQpIHtcbiAgICAgIGVsZUNhY2hlLmludmFsaWRhdGVkID0gZmFsc2U7XG4gICAgICBlbGVDYWNoZS50ZXh0dXJlLmludmFsaWRhdGVkV2lkdGggLT0gZWxlQ2FjaGUud2lkdGg7XG4gICAgfVxuXG4gICAgaWYgKGVsZUNhY2hlKSB7XG4gICAgICByZXR1cm4gZWxlQ2FjaGU7XG4gICAgfVxuXG4gICAgdmFyIHR4ckg7IC8vIHdoaWNoIHRleHR1cmUgaGVpZ2h0IHRoaXMgZWxlIGJlbG9uZ3MgdG9cblxuICAgIGlmIChlbGVTY2FsZWRIIDw9IG1pblR4ckgpIHtcbiAgICAgIHR4ckggPSBtaW5UeHJIO1xuICAgIH0gZWxzZSBpZiAoZWxlU2NhbGVkSCA8PSB0eHJTdGVwSCkge1xuICAgICAgdHhySCA9IHR4clN0ZXBIO1xuICAgIH0gZWxzZSB7XG4gICAgICB0eHJIID0gTWF0aC5jZWlsKGVsZVNjYWxlZEggLyB0eHJTdGVwSCkgKiB0eHJTdGVwSDtcbiAgICB9XG5cbiAgICBpZiAoZWxlU2NhbGVkSCA+IG1heFR4ckggfHwgZWxlU2NhbGVkVyA+IG1heFR4clcpIHtcbiAgICAgIHJldHVybiBudWxsOyAvLyBjYWNoaW5nIGxhcmdlIGVsZW1lbnRzIGlzIG5vdCBlZmZpY2llbnRcbiAgICB9XG5cbiAgICB2YXIgdHhyUSA9IHNlbGYuZ2V0VGV4dHVyZVF1ZXVlKHR4ckgpOyAvLyBmaXJzdCB0cnkgdGhlIHNlY29uZCBsYXN0IG9uZSBpbiBjYXNlIGl0IGhhcyBzcGFjZSBhdCB0aGUgZW5kXG5cbiAgICB2YXIgdHhyID0gdHhyUVt0eHJRLmxlbmd0aCAtIDJdO1xuXG4gICAgdmFyIGFkZE5ld1R4ciA9IGZ1bmN0aW9uIGFkZE5ld1R4cigpIHtcbiAgICAgIHJldHVybiBzZWxmLnJlY3ljbGVUZXh0dXJlKHR4ckgsIGVsZVNjYWxlZFcpIHx8IHNlbGYuYWRkVGV4dHVyZSh0eHJILCBlbGVTY2FsZWRXKTtcbiAgICB9OyAvLyB0cnkgdGhlIGxhc3Qgb25lIGlmIHRoZXJlIGlzIG5vIHNlY29uZCBsYXN0IG9uZVxuXG5cbiAgICBpZiAoIXR4cikge1xuICAgICAgdHhyID0gdHhyUVt0eHJRLmxlbmd0aCAtIDFdO1xuICAgIH0gLy8gaWYgdGhlIGxhc3Qgb25lIGRvZXNuJ3QgZXhpc3QsIHdlIG5lZWQgYSBmaXJzdCBvbmVcblxuXG4gICAgaWYgKCF0eHIpIHtcbiAgICAgIHR4ciA9IGFkZE5ld1R4cigpO1xuICAgIH0gLy8gaWYgdGhlcmUncyBubyByb29tIGluIHRoZSBjdXJyZW50IHRleHR1cmUsIHdlIG5lZWQgYSBuZXcgb25lXG5cblxuICAgIGlmICh0eHIud2lkdGggLSB0eHIudXNlZFdpZHRoIDwgZWxlU2NhbGVkVykge1xuICAgICAgdHhyID0gYWRkTmV3VHhyKCk7XG4gICAgfVxuXG4gICAgdmFyIHNjYWxhYmxlRnJvbSA9IGZ1bmN0aW9uIHNjYWxhYmxlRnJvbShvdGhlckNhY2hlKSB7XG4gICAgICByZXR1cm4gb3RoZXJDYWNoZSAmJiBvdGhlckNhY2hlLnNjYWxlZExhYmVsU2hvd24gPT09IHNjYWxlZExhYmVsU2hvd247XG4gICAgfTtcblxuICAgIHZhciBkZXFpbmcgPSByZWFzb24gJiYgcmVhc29uID09PSBnZXRUeHJSZWFzb25zLmRlcXVldWU7XG4gICAgdmFyIGhpZ2hRdWFsaXR5UmVxID0gcmVhc29uICYmIHJlYXNvbiA9PT0gZ2V0VHhyUmVhc29ucy5oaWdoUXVhbGl0eTtcbiAgICB2YXIgZG93bnNjYWxlUmVxID0gcmVhc29uICYmIHJlYXNvbiA9PT0gZ2V0VHhyUmVhc29ucy5kb3duc2NhbGU7XG4gICAgdmFyIGhpZ2hlckNhY2hlOyAvLyB0aGUgbmVhcmVzdCBjYWNoZSB3aXRoIGEgaGlnaGVyIGxldmVsXG5cbiAgICBmb3IgKHZhciBsID0gbHZsICsgMTsgbCA8PSBtYXhMdmwkMTsgbCsrKSB7XG4gICAgICB2YXIgYyA9IGxvb2t1cC5nZXQoZWxlLCBsKTtcblxuICAgICAgaWYgKGMpIHtcbiAgICAgICAgaGlnaGVyQ2FjaGUgPSBjO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgb25lVXBDYWNoZSA9IGhpZ2hlckNhY2hlICYmIGhpZ2hlckNhY2hlLmxldmVsID09PSBsdmwgKyAxID8gaGlnaGVyQ2FjaGUgOiBudWxsO1xuXG4gICAgdmFyIGRvd25zY2FsZSA9IGZ1bmN0aW9uIGRvd25zY2FsZSgpIHtcbiAgICAgIHR4ci5jb250ZXh0LmRyYXdJbWFnZShvbmVVcENhY2hlLnRleHR1cmUuY2FudmFzLCBvbmVVcENhY2hlLngsIDAsIG9uZVVwQ2FjaGUud2lkdGgsIG9uZVVwQ2FjaGUuaGVpZ2h0LCB0eHIudXNlZFdpZHRoLCAwLCBlbGVTY2FsZWRXLCBlbGVTY2FsZWRIKTtcbiAgICB9OyAvLyByZXNldCBlbGUgYXJlYSBpbiB0ZXh0dXJlXG5cblxuICAgIHR4ci5jb250ZXh0LnNldFRyYW5zZm9ybSgxLCAwLCAwLCAxLCAwLCAwKTtcbiAgICB0eHIuY29udGV4dC5jbGVhclJlY3QodHhyLnVzZWRXaWR0aCwgMCwgZWxlU2NhbGVkVywgdHhySCk7XG5cbiAgICBpZiAoc2NhbGFibGVGcm9tKG9uZVVwQ2FjaGUpKSB7XG4gICAgICAvLyB0aGVuIHdlIGNhbiByZWxhdGl2ZWx5IGNoZWFwbHkgcmVzY2FsZSB0aGUgZXhpc3RpbmcgaW1hZ2Ugdy9vIHJlcmVuZGVyaW5nXG4gICAgICBkb3duc2NhbGUoKTtcbiAgICB9IGVsc2UgaWYgKHNjYWxhYmxlRnJvbShoaWdoZXJDYWNoZSkpIHtcbiAgICAgIC8vIHRoZW4gdXNlIHRoZSBoaWdoZXIgY2FjaGUgZm9yIG5vdyBhbmQgcXVldWUgdGhlIG5leHQgbGV2ZWwgZG93blxuICAgICAgLy8gdG8gY2hlYXBseSBzY2FsZSB0b3dhcmRzIHRoZSBzbWFsbGVyIGxldmVsXG4gICAgICBpZiAoaGlnaFF1YWxpdHlSZXEpIHtcbiAgICAgICAgZm9yICh2YXIgX2wgPSBoaWdoZXJDYWNoZS5sZXZlbDsgX2wgPiBsdmw7IF9sLS0pIHtcbiAgICAgICAgICBvbmVVcENhY2hlID0gc2VsZi5nZXRFbGVtZW50KGVsZSwgYmIsIHB4UmF0aW8sIF9sLCBnZXRUeHJSZWFzb25zLmRvd25zY2FsZSk7XG4gICAgICAgIH1cblxuICAgICAgICBkb3duc2NhbGUoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNlbGYucXVldWVFbGVtZW50KGVsZSwgaGlnaGVyQ2FjaGUubGV2ZWwgLSAxKTtcbiAgICAgICAgcmV0dXJuIGhpZ2hlckNhY2hlO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgbG93ZXJDYWNoZTsgLy8gdGhlIG5lYXJlc3QgY2FjaGUgd2l0aCBhIGxvd2VyIGxldmVsXG5cbiAgICAgIGlmICghZGVxaW5nICYmICFoaWdoUXVhbGl0eVJlcSAmJiAhZG93bnNjYWxlUmVxKSB7XG4gICAgICAgIGZvciAodmFyIF9sMiA9IGx2bCAtIDE7IF9sMiA+PSBtaW5MdmwkMTsgX2wyLS0pIHtcbiAgICAgICAgICB2YXIgX2MgPSBsb29rdXAuZ2V0KGVsZSwgX2wyKTtcblxuICAgICAgICAgIGlmIChfYykge1xuICAgICAgICAgICAgbG93ZXJDYWNoZSA9IF9jO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2FsYWJsZUZyb20obG93ZXJDYWNoZSkpIHtcbiAgICAgICAgLy8gdGhlbiB1c2UgdGhlIGxvd2VyIHF1YWxpdHkgY2FjaGUgZm9yIG5vdyBhbmQgcXVldWUgdGhlIGJldHRlciBvbmUgZm9yIGxhdGVyXG4gICAgICAgIHNlbGYucXVldWVFbGVtZW50KGVsZSwgbHZsKTtcbiAgICAgICAgcmV0dXJuIGxvd2VyQ2FjaGU7XG4gICAgICB9XG5cbiAgICAgIHR4ci5jb250ZXh0LnRyYW5zbGF0ZSh0eHIudXNlZFdpZHRoLCAwKTtcbiAgICAgIHR4ci5jb250ZXh0LnNjYWxlKHNjYWxlLCBzY2FsZSk7XG4gICAgICB0aGlzLmRyYXdFbGVtZW50KHR4ci5jb250ZXh0LCBlbGUsIGJiLCBzY2FsZWRMYWJlbFNob3duLCBmYWxzZSk7XG4gICAgICB0eHIuY29udGV4dC5zY2FsZSgxIC8gc2NhbGUsIDEgLyBzY2FsZSk7XG4gICAgICB0eHIuY29udGV4dC50cmFuc2xhdGUoLXR4ci51c2VkV2lkdGgsIDApO1xuICAgIH1cblxuICAgIGVsZUNhY2hlID0ge1xuICAgICAgeDogdHhyLnVzZWRXaWR0aCxcbiAgICAgIHRleHR1cmU6IHR4cixcbiAgICAgIGxldmVsOiBsdmwsXG4gICAgICBzY2FsZTogc2NhbGUsXG4gICAgICB3aWR0aDogZWxlU2NhbGVkVyxcbiAgICAgIGhlaWdodDogZWxlU2NhbGVkSCxcbiAgICAgIHNjYWxlZExhYmVsU2hvd246IHNjYWxlZExhYmVsU2hvd25cbiAgICB9O1xuICAgIHR4ci51c2VkV2lkdGggKz0gTWF0aC5jZWlsKGVsZVNjYWxlZFcgKyBlbGVUeHJTcGFjaW5nKTtcbiAgICB0eHIuZWxlQ2FjaGVzLnB1c2goZWxlQ2FjaGUpO1xuICAgIGxvb2t1cC5zZXQoZWxlLCBsdmwsIGVsZUNhY2hlKTtcbiAgICBzZWxmLmNoZWNrVGV4dHVyZUZ1bGxuZXNzKHR4cik7XG4gICAgcmV0dXJuIGVsZUNhY2hlO1xuICB9O1xuXG4gIEVUQ3AuaW52YWxpZGF0ZUVsZW1lbnRzID0gZnVuY3Rpb24gKGVsZXMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHRoaXMuaW52YWxpZGF0ZUVsZW1lbnQoZWxlc1tpXSk7XG4gICAgfVxuICB9O1xuXG4gIEVUQ3AuaW52YWxpZGF0ZUVsZW1lbnQgPSBmdW5jdGlvbiAoZWxlKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBsb29rdXAgPSBzZWxmLmxvb2t1cDtcbiAgICB2YXIgY2FjaGVzID0gW107XG4gICAgdmFyIGludmFsaWQgPSBsb29rdXAuaXNJbnZhbGlkKGVsZSk7XG5cbiAgICBpZiAoIWludmFsaWQpIHtcbiAgICAgIHJldHVybjsgLy8gb3ZlcnJpZGUgdGhlIGludmFsaWRhdGlvbiByZXF1ZXN0IGlmIHRoZSBlbGVtZW50IGtleSBoYXMgbm90IGNoYW5nZWRcbiAgICB9XG5cbiAgICBmb3IgKHZhciBsdmwgPSBtaW5MdmwkMTsgbHZsIDw9IG1heEx2bCQxOyBsdmwrKykge1xuICAgICAgdmFyIGNhY2hlID0gbG9va3VwLmdldEZvckNhY2hlZEtleShlbGUsIGx2bCk7XG5cbiAgICAgIGlmIChjYWNoZSkge1xuICAgICAgICBjYWNoZXMucHVzaChjYWNoZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIG5vT3RoZXJFbGVzVXNlQ2FjaGUgPSBsb29rdXAuaW52YWxpZGF0ZShlbGUpO1xuXG4gICAgaWYgKG5vT3RoZXJFbGVzVXNlQ2FjaGUpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2FjaGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBfY2FjaGUgPSBjYWNoZXNbaV07XG4gICAgICAgIHZhciB0eHIgPSBfY2FjaGUudGV4dHVyZTsgLy8gcmVtb3ZlIHNwYWNlIGZyb20gdGhlIHRleHR1cmUgaXQgYmVsb25ncyB0b1xuXG4gICAgICAgIHR4ci5pbnZhbGlkYXRlZFdpZHRoICs9IF9jYWNoZS53aWR0aDsgLy8gbWFyayB0aGUgY2FjaGUgYXMgaW52YWxpZGF0ZWRcblxuICAgICAgICBfY2FjaGUuaW52YWxpZGF0ZWQgPSB0cnVlOyAvLyByZXRpcmUgdGhlIHRleHR1cmUgaWYgaXRzIHV0aWxpdHkgaXMgbG93XG5cbiAgICAgICAgc2VsZi5jaGVja1RleHR1cmVVdGlsaXR5KHR4cik7XG4gICAgICB9XG4gICAgfSAvLyByZW1vdmUgZnJvbSBxdWV1ZSBzaW5jZSB0aGUgb2xkIHJlcSB3YXMgZm9yIHRoZSBvbGQgc3RhdGVcblxuXG4gICAgc2VsZi5yZW1vdmVGcm9tUXVldWUoZWxlKTtcbiAgfTtcblxuICBFVENwLmNoZWNrVGV4dHVyZVV0aWxpdHkgPSBmdW5jdGlvbiAodHhyKSB7XG4gICAgLy8gaW52YWxpZGF0ZSBhbGwgZW50cmllcyBpbiB0aGUgY2FjaGUgaWYgdGhlIGNhY2hlIHNpemUgaXMgc21hbGxcbiAgICBpZiAodHhyLmludmFsaWRhdGVkV2lkdGggPj0gbWluVXRpbGl0eSAqIHR4ci53aWR0aCkge1xuICAgICAgdGhpcy5yZXRpcmVUZXh0dXJlKHR4cik7XG4gICAgfVxuICB9O1xuXG4gIEVUQ3AuY2hlY2tUZXh0dXJlRnVsbG5lc3MgPSBmdW5jdGlvbiAodHhyKSB7XG4gICAgLy8gaWYgdGV4dHVyZSBoYXMgYmVlbiBtb3N0bHkgZmlsbGVkIGFuZCBwYXNzZWQgb3ZlciBzZXZlcmFsIHRpbWVzLCByZW1vdmVcbiAgICAvLyBpdCBmcm9tIHRoZSBxdWV1ZSBzbyB3ZSBkb24ndCBuZWVkIHRvIHdhc3RlIHRpbWUgbG9va2luZyBhdCBpdCB0byBwdXQgbmV3IHRoaW5nc1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgdHhyUSA9IHNlbGYuZ2V0VGV4dHVyZVF1ZXVlKHR4ci5oZWlnaHQpO1xuXG4gICAgaWYgKHR4ci51c2VkV2lkdGggLyB0eHIud2lkdGggPiBtYXhGdWxsbmVzcyAmJiB0eHIuZnVsbG5lc3NDaGVja3MgPj0gbWF4RnVsbG5lc3NDaGVja3MpIHtcbiAgICAgIHJlbW92ZUZyb21BcnJheSh0eHJRLCB0eHIpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0eHIuZnVsbG5lc3NDaGVja3MrKztcbiAgICB9XG4gIH07XG5cbiAgRVRDcC5yZXRpcmVUZXh0dXJlID0gZnVuY3Rpb24gKHR4cikge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgdHhySCA9IHR4ci5oZWlnaHQ7XG4gICAgdmFyIHR4clEgPSBzZWxmLmdldFRleHR1cmVRdWV1ZSh0eHJIKTtcbiAgICB2YXIgbG9va3VwID0gdGhpcy5sb29rdXA7IC8vIHJldGlyZSB0aGUgdGV4dHVyZSBmcm9tIHRoZSBhY3RpdmUgLyBzZWFyY2hhYmxlIHF1ZXVlOlxuXG4gICAgcmVtb3ZlRnJvbUFycmF5KHR4clEsIHR4cik7XG4gICAgdHhyLnJldGlyZWQgPSB0cnVlOyAvLyByZW1vdmUgdGhlIHJlZnMgZnJvbSB0aGUgZWxlcyB0byB0aGUgY2FjaGVzOlxuXG4gICAgdmFyIGVsZUNhY2hlcyA9IHR4ci5lbGVDYWNoZXM7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZUNhY2hlcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGVsZUNhY2hlID0gZWxlQ2FjaGVzW2ldO1xuICAgICAgbG9va3VwLmRlbGV0ZUNhY2hlKGVsZUNhY2hlLmtleSwgZWxlQ2FjaGUubGV2ZWwpO1xuICAgIH1cblxuICAgIGNsZWFyQXJyYXkoZWxlQ2FjaGVzKTsgLy8gYWRkIHRoZSB0ZXh0dXJlIHRvIGEgcmV0aXJlZCBxdWV1ZSBzbyBpdCBjYW4gYmUgcmVjeWNsZWQgaW4gZnV0dXJlOlxuXG4gICAgdmFyIHJ0eHRyUSA9IHNlbGYuZ2V0UmV0aXJlZFRleHR1cmVRdWV1ZSh0eHJIKTtcbiAgICBydHh0clEucHVzaCh0eHIpO1xuICB9O1xuXG4gIEVUQ3AuYWRkVGV4dHVyZSA9IGZ1bmN0aW9uICh0eHJILCBtaW5XKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciB0eHJRID0gc2VsZi5nZXRUZXh0dXJlUXVldWUodHhySCk7XG4gICAgdmFyIHR4ciA9IHt9O1xuICAgIHR4clEucHVzaCh0eHIpO1xuICAgIHR4ci5lbGVDYWNoZXMgPSBbXTtcbiAgICB0eHIuaGVpZ2h0ID0gdHhySDtcbiAgICB0eHIud2lkdGggPSBNYXRoLm1heChkZWZUeHJXaWR0aCwgbWluVyk7XG4gICAgdHhyLnVzZWRXaWR0aCA9IDA7XG4gICAgdHhyLmludmFsaWRhdGVkV2lkdGggPSAwO1xuICAgIHR4ci5mdWxsbmVzc0NoZWNrcyA9IDA7XG4gICAgdHhyLmNhbnZhcyA9IHNlbGYucmVuZGVyZXIubWFrZU9mZnNjcmVlbkNhbnZhcyh0eHIud2lkdGgsIHR4ci5oZWlnaHQpO1xuICAgIHR4ci5jb250ZXh0ID0gdHhyLmNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuICAgIHJldHVybiB0eHI7XG4gIH07XG5cbiAgRVRDcC5yZWN5Y2xlVGV4dHVyZSA9IGZ1bmN0aW9uICh0eHJILCBtaW5XKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciB0eHJRID0gc2VsZi5nZXRUZXh0dXJlUXVldWUodHhySCk7XG4gICAgdmFyIHJ0eHRyUSA9IHNlbGYuZ2V0UmV0aXJlZFRleHR1cmVRdWV1ZSh0eHJIKTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcnR4dHJRLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgdHhyID0gcnR4dHJRW2ldO1xuXG4gICAgICBpZiAodHhyLndpZHRoID49IG1pblcpIHtcbiAgICAgICAgdHhyLnJldGlyZWQgPSBmYWxzZTtcbiAgICAgICAgdHhyLnVzZWRXaWR0aCA9IDA7XG4gICAgICAgIHR4ci5pbnZhbGlkYXRlZFdpZHRoID0gMDtcbiAgICAgICAgdHhyLmZ1bGxuZXNzQ2hlY2tzID0gMDtcbiAgICAgICAgY2xlYXJBcnJheSh0eHIuZWxlQ2FjaGVzKTtcbiAgICAgICAgdHhyLmNvbnRleHQuc2V0VHJhbnNmb3JtKDEsIDAsIDAsIDEsIDAsIDApO1xuICAgICAgICB0eHIuY29udGV4dC5jbGVhclJlY3QoMCwgMCwgdHhyLndpZHRoLCB0eHIuaGVpZ2h0KTtcbiAgICAgICAgcmVtb3ZlRnJvbUFycmF5KHJ0eHRyUSwgdHhyKTtcbiAgICAgICAgdHhyUS5wdXNoKHR4cik7XG4gICAgICAgIHJldHVybiB0eHI7XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIEVUQ3AucXVldWVFbGVtZW50ID0gZnVuY3Rpb24gKGVsZSwgbHZsKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBxID0gc2VsZi5nZXRFbGVtZW50UXVldWUoKTtcbiAgICB2YXIgazJxID0gc2VsZi5nZXRFbGVtZW50S2V5VG9RdWV1ZSgpO1xuICAgIHZhciBrZXkgPSB0aGlzLmdldEtleShlbGUpO1xuICAgIHZhciBleGlzdGluZ1JlcSA9IGsycVtrZXldO1xuXG4gICAgaWYgKGV4aXN0aW5nUmVxKSB7XG4gICAgICAvLyB1c2UgdGhlIG1heCBsdmwgYi9jIGluIGJldHdlZW4gbHZscyBhcmUgY2hlYXAgdG8gbWFrZVxuICAgICAgZXhpc3RpbmdSZXEubGV2ZWwgPSBNYXRoLm1heChleGlzdGluZ1JlcS5sZXZlbCwgbHZsKTtcbiAgICAgIGV4aXN0aW5nUmVxLmVsZXMubWVyZ2UoZWxlKTtcbiAgICAgIGV4aXN0aW5nUmVxLnJlcXMrKztcbiAgICAgIHEudXBkYXRlSXRlbShleGlzdGluZ1JlcSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciByZXEgPSB7XG4gICAgICAgIGVsZXM6IGVsZS5zcGF3bigpLm1lcmdlKGVsZSksXG4gICAgICAgIGxldmVsOiBsdmwsXG4gICAgICAgIHJlcXM6IDEsXG4gICAgICAgIGtleToga2V5XG4gICAgICB9O1xuICAgICAgcS5wdXNoKHJlcSk7XG4gICAgICBrMnFba2V5XSA9IHJlcTtcbiAgICB9XG4gIH07XG5cbiAgRVRDcC5kZXF1ZXVlID0gZnVuY3Rpb24gKHB4UmF0aW9cbiAgLyosIGV4dGVudCovXG4gICkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgcSA9IHNlbGYuZ2V0RWxlbWVudFF1ZXVlKCk7XG4gICAgdmFyIGsycSA9IHNlbGYuZ2V0RWxlbWVudEtleVRvUXVldWUoKTtcbiAgICB2YXIgZGVxdWV1ZWQgPSBbXTtcbiAgICB2YXIgbG9va3VwID0gc2VsZi5sb29rdXA7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG1heERlcVNpemUkMTsgaSsrKSB7XG4gICAgICBpZiAocS5zaXplKCkgPiAwKSB7XG4gICAgICAgIHZhciByZXEgPSBxLnBvcCgpO1xuICAgICAgICB2YXIga2V5ID0gcmVxLmtleTtcbiAgICAgICAgdmFyIGVsZSA9IHJlcS5lbGVzWzBdOyAvLyBhbGwgZWxlcyBoYXZlIHRoZSBzYW1lIGtleVxuXG4gICAgICAgIHZhciBjYWNoZUV4aXN0cyA9IGxvb2t1cC5oYXNDYWNoZShlbGUsIHJlcS5sZXZlbCk7IC8vIGNsZWFyIG91dCB0aGUga2V5IHRvIHJlcSBsb29rdXBcblxuICAgICAgICBrMnFba2V5XSA9IG51bGw7IC8vIGRlcXVldWVpbmcgaXNuJ3QgbmVjZXNzYXJ5IHdpdGggYW4gZXhpc3RpbmcgY2FjaGVcblxuICAgICAgICBpZiAoY2FjaGVFeGlzdHMpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGRlcXVldWVkLnB1c2gocmVxKTtcbiAgICAgICAgdmFyIGJiID0gc2VsZi5nZXRCb3VuZGluZ0JveChlbGUpO1xuICAgICAgICBzZWxmLmdldEVsZW1lbnQoZWxlLCBiYiwgcHhSYXRpbywgcmVxLmxldmVsLCBnZXRUeHJSZWFzb25zLmRlcXVldWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlcXVldWVkO1xuICB9O1xuXG4gIEVUQ3AucmVtb3ZlRnJvbVF1ZXVlID0gZnVuY3Rpb24gKGVsZSkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgcSA9IHNlbGYuZ2V0RWxlbWVudFF1ZXVlKCk7XG4gICAgdmFyIGsycSA9IHNlbGYuZ2V0RWxlbWVudEtleVRvUXVldWUoKTtcbiAgICB2YXIga2V5ID0gdGhpcy5nZXRLZXkoZWxlKTtcbiAgICB2YXIgcmVxID0gazJxW2tleV07XG5cbiAgICBpZiAocmVxICE9IG51bGwpIHtcbiAgICAgIGlmIChyZXEuZWxlcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgLy8gcmVtb3ZlIGlmIGxhc3QgZWxlIGluIHRoZSByZXFcbiAgICAgICAgLy8gYnJpbmcgdG8gZnJvbnQgb2YgcXVldWVcbiAgICAgICAgcmVxLnJlcXMgPSBNQVhfSU5UJDE7XG4gICAgICAgIHEudXBkYXRlSXRlbShyZXEpO1xuICAgICAgICBxLnBvcCgpOyAvLyByZW1vdmUgZnJvbSBxdWV1ZVxuXG4gICAgICAgIGsycVtrZXldID0gbnVsbDsgLy8gcmVtb3ZlIGZyb20gbG9va3VwIG1hcFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gb3RoZXJ3aXNlIGp1c3QgcmVtb3ZlIGVsZSBmcm9tIHJlcVxuICAgICAgICByZXEuZWxlcy51bm1lcmdlKGVsZSk7XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIEVUQ3Aub25EZXF1ZXVlID0gZnVuY3Rpb24gKGZuKSB7XG4gICAgdGhpcy5vbkRlcXVldWVzLnB1c2goZm4pO1xuICB9O1xuXG4gIEVUQ3Aub2ZmRGVxdWV1ZSA9IGZ1bmN0aW9uIChmbikge1xuICAgIHJlbW92ZUZyb21BcnJheSh0aGlzLm9uRGVxdWV1ZXMsIGZuKTtcbiAgfTtcblxuICBFVENwLnNldHVwRGVxdWV1ZWluZyA9IGRlZnMuc2V0dXBEZXF1ZXVlaW5nKHtcbiAgICBkZXFSZWRyYXdUaHJlc2hvbGQ6IGRlcVJlZHJhd1RocmVzaG9sZCQxLFxuICAgIGRlcUNvc3Q6IGRlcUNvc3QkMSxcbiAgICBkZXFBdmdDb3N0OiBkZXFBdmdDb3N0JDEsXG4gICAgZGVxTm9EcmF3Q29zdDogZGVxTm9EcmF3Q29zdCQxLFxuICAgIGRlcUZhc3RDb3N0OiBkZXFGYXN0Q29zdCQxLFxuICAgIGRlcTogZnVuY3Rpb24gZGVxKHNlbGYsIHB4UmF0aW8sIGV4dGVudCkge1xuICAgICAgcmV0dXJuIHNlbGYuZGVxdWV1ZShweFJhdGlvLCBleHRlbnQpO1xuICAgIH0sXG4gICAgb25EZXFkOiBmdW5jdGlvbiBvbkRlcWQoc2VsZiwgZGVxZCkge1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzZWxmLm9uRGVxdWV1ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGZuID0gc2VsZi5vbkRlcXVldWVzW2ldO1xuICAgICAgICBmbihkZXFkKTtcbiAgICAgIH1cbiAgICB9LFxuICAgIHNob3VsZFJlZHJhdzogZnVuY3Rpb24gc2hvdWxkUmVkcmF3KHNlbGYsIGRlcWQsIHB4UmF0aW8sIGV4dGVudCkge1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkZXFkLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBlbGVzID0gZGVxZFtpXS5lbGVzO1xuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgZWxlcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgIHZhciBiYiA9IGVsZXNbal0uYm91bmRpbmdCb3goKTtcblxuICAgICAgICAgIGlmIChib3VuZGluZ0JveGVzSW50ZXJzZWN0KGJiLCBleHRlbnQpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0sXG4gICAgcHJpb3JpdHk6IGZ1bmN0aW9uIHByaW9yaXR5KHNlbGYpIHtcbiAgICAgIHJldHVybiBzZWxmLnJlbmRlcmVyLmJlZm9yZVJlbmRlclByaW9yaXRpZXMuZWxlVHhyRGVxO1xuICAgIH1cbiAgfSk7XG5cbiAgdmFyIGRlZk51bUxheWVycyA9IDE7IC8vIGRlZmF1bHQgbnVtYmVyIG9mIGxheWVycyB0byB1c2VcblxuICB2YXIgbWluTHZsID0gLTQ7IC8vIHdoZW4gc2NhbGluZyBzbWFsbGVyIHRoYW4gdGhhdCB3ZSBkb24ndCBuZWVkIHRvIHJlLXJlbmRlclxuXG4gIHZhciBtYXhMdmwgPSAyOyAvLyB3aGVuIGxhcmdlciB0aGFuIHRoaXMgc2NhbGUganVzdCByZW5kZXIgZGlyZWN0bHkgKGNhY2hpbmcgaXMgbm90IGhlbHBmdWwpXG5cbiAgdmFyIG1heFpvb20gPSAzLjk5OyAvLyBiZXlvbmQgdGhpcyB6b29tIGxldmVsLCBsYXllcmVkIHRleHR1cmVzIGFyZSBub3QgdXNlZFxuXG4gIHZhciBkZXFSZWRyYXdUaHJlc2hvbGQgPSA1MDsgLy8gdGltZSB0byBiYXRjaCByZWRyYXdzIHRvZ2V0aGVyIGZyb20gZGVxdWV1ZWluZyB0byBhbGxvdyBtb3JlIGRlcXVldWVpbmcgY2FsY3MgdG8gaGFwcGVuIGluIHRoZSBtZWFud2hpbGVcblxuICB2YXIgcmVmaW5lRWxlRGVib3VuY2VUaW1lID0gNTA7IC8vIHRpbWUgdG8gZGVib3VuY2Ugc2hhcnBlciBlbGUgdGV4dHVyZSB1cGRhdGVzXG5cbiAgdmFyIGRlcUNvc3QgPSAwLjE1OyAvLyAlIG9mIGFkZCdsIHJlbmRlcmluZyBjb3N0IGFsbG93ZWQgZm9yIGRlcXVldWluZyBlbGUgY2FjaGVzIGVhY2ggZnJhbWVcblxuICB2YXIgZGVxQXZnQ29zdCA9IDAuMTsgLy8gJSBvZiBhZGQnbCByZW5kZXJpbmcgY29zdCBjb21wYXJlZCB0byBhdmVyYWdlIG92ZXJhbGwgcmVkcmF3IHRpbWVcblxuICB2YXIgZGVxTm9EcmF3Q29zdCA9IDAuOTsgLy8gJSBvZiBhdmcgZnJhbWUgdGltZSB0aGF0IGNhbiBiZSB1c2VkIGZvciBkZXF1ZXVlaW5nIHdoZW4gbm90IGRyYXdpbmdcblxuICB2YXIgZGVxRmFzdENvc3QgPSAwLjk7IC8vICUgb2YgZnJhbWUgdGltZSB0byBiZSB1c2VkIHdoZW4gPjYwZnBzXG5cbiAgdmFyIG1heERlcVNpemUgPSAxOyAvLyBudW1iZXIgb2YgZWxlcyB0byBkZXF1ZXVlIGFuZCByZW5kZXIgYXQgaGlnaGVyIHRleHR1cmUgaW4gZWFjaCBiYXRjaFxuXG4gIHZhciBpbnZhbGlkVGhyZXNob2xkID0gMjUwOyAvLyB0aW1lIHRocmVzaG9sZCBmb3IgZGlzYWJsaW5nIGIvYyBvZiBpbnZhbGlkYXRpb25zXG5cbiAgdmFyIG1heExheWVyQXJlYSA9IDQwMDAgKiA0MDAwOyAvLyBsYXllcnMgY2FuJ3QgYmUgYmlnZ2VyIHRoYW4gdGhpc1xuXG4gIHZhciB1c2VIaWdoUXVhbGl0eUVsZVR4clJlcXMgPSB0cnVlOyAvLyB3aGV0aGVyIHRvIHVzZSBoaWdoIHF1YWxpdHkgZWxlIHR4ciByZXF1ZXN0cyAoZ2VuZXJhbGx5IGZhc3RlciBhbmQgY2hlYXBlciBpbiB0aGUgbG9uZ3Rlcm0pXG4gIC8vIHZhciBsb2cgPSBmdW5jdGlvbigpeyBjb25zb2xlLmxvZy5hcHBseSggY29uc29sZSwgYXJndW1lbnRzICk7IH07XG5cbiAgdmFyIExheWVyZWRUZXh0dXJlQ2FjaGUgPSBmdW5jdGlvbiBMYXllcmVkVGV4dHVyZUNhY2hlKHJlbmRlcmVyKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciByID0gc2VsZi5yZW5kZXJlciA9IHJlbmRlcmVyO1xuICAgIHZhciBjeSA9IHIuY3k7XG4gICAgc2VsZi5sYXllcnNCeUxldmVsID0ge307IC8vIGUuZy4gMiA9PiBbIGxheWVyMSwgbGF5ZXIyLCAuLi4sIGxheWVyTiBdXG5cbiAgICBzZWxmLmZpcnN0R2V0ID0gdHJ1ZTtcbiAgICBzZWxmLmxhc3RJbnZhbGlkYXRpb25UaW1lID0gcGVyZm9ybWFuY2VOb3coKSAtIDIgKiBpbnZhbGlkVGhyZXNob2xkO1xuICAgIHNlbGYuc2tpcHBpbmcgPSBmYWxzZTtcbiAgICBzZWxmLmVsZVR4ckRlcXMgPSBjeS5jb2xsZWN0aW9uKCk7XG4gICAgc2VsZi5zY2hlZHVsZUVsZW1lbnRSZWZpbmVtZW50ID0gZGVib3VuY2VfMShmdW5jdGlvbiAoKSB7XG4gICAgICBzZWxmLnJlZmluZUVsZW1lbnRUZXh0dXJlcyhzZWxmLmVsZVR4ckRlcXMpO1xuICAgICAgc2VsZi5lbGVUeHJEZXFzLnVubWVyZ2Uoc2VsZi5lbGVUeHJEZXFzKTtcbiAgICB9LCByZWZpbmVFbGVEZWJvdW5jZVRpbWUpO1xuICAgIHIuYmVmb3JlUmVuZGVyKGZ1bmN0aW9uICh3aWxsRHJhdywgbm93KSB7XG4gICAgICBpZiAobm93IC0gc2VsZi5sYXN0SW52YWxpZGF0aW9uVGltZSA8PSBpbnZhbGlkVGhyZXNob2xkKSB7XG4gICAgICAgIHNlbGYuc2tpcHBpbmcgPSB0cnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2VsZi5za2lwcGluZyA9IGZhbHNlO1xuICAgICAgfVxuICAgIH0sIHIuYmVmb3JlUmVuZGVyUHJpb3JpdGllcy5seXJUeHJTa2lwKTtcblxuICAgIHZhciBxU29ydCA9IGZ1bmN0aW9uIHFTb3J0KGEsIGIpIHtcbiAgICAgIHJldHVybiBiLnJlcXMgLSBhLnJlcXM7XG4gICAgfTtcblxuICAgIHNlbGYubGF5ZXJzUXVldWUgPSBuZXcgaGVhcChxU29ydCk7XG4gICAgc2VsZi5zZXR1cERlcXVldWVpbmcoKTtcbiAgfTtcblxuICB2YXIgTFRDcCA9IExheWVyZWRUZXh0dXJlQ2FjaGUucHJvdG90eXBlO1xuICB2YXIgbGF5ZXJJZFBvb2wgPSAwO1xuICB2YXIgTUFYX0lOVCA9IE1hdGgucG93KDIsIDUzKSAtIDE7XG5cbiAgTFRDcC5tYWtlTGF5ZXIgPSBmdW5jdGlvbiAoYmIsIGx2bCkge1xuICAgIHZhciBzY2FsZSA9IE1hdGgucG93KDIsIGx2bCk7XG4gICAgdmFyIHcgPSBNYXRoLmNlaWwoYmIudyAqIHNjYWxlKTtcbiAgICB2YXIgaCA9IE1hdGguY2VpbChiYi5oICogc2NhbGUpO1xuICAgIHZhciBjYW52YXMgPSB0aGlzLnJlbmRlcmVyLm1ha2VPZmZzY3JlZW5DYW52YXModywgaCk7XG4gICAgdmFyIGxheWVyID0ge1xuICAgICAgaWQ6IGxheWVySWRQb29sID0gKytsYXllcklkUG9vbCAlIE1BWF9JTlQsXG4gICAgICBiYjogYmIsXG4gICAgICBsZXZlbDogbHZsLFxuICAgICAgd2lkdGg6IHcsXG4gICAgICBoZWlnaHQ6IGgsXG4gICAgICBjYW52YXM6IGNhbnZhcyxcbiAgICAgIGNvbnRleHQ6IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpLFxuICAgICAgZWxlczogW10sXG4gICAgICBlbGVzUXVldWU6IFtdLFxuICAgICAgcmVxczogMFxuICAgIH07IC8vIGxvZygnbWFrZSBsYXllciAlcyB3aXRoIHcgJXMgYW5kIGggJXMgYW5kIGx2bCAlcycsIGxheWVyLmlkLCBsYXllci53aWR0aCwgbGF5ZXIuaGVpZ2h0LCBsYXllci5sZXZlbCk7XG5cbiAgICB2YXIgY3h0ID0gbGF5ZXIuY29udGV4dDtcbiAgICB2YXIgZHggPSAtbGF5ZXIuYmIueDE7XG4gICAgdmFyIGR5ID0gLWxheWVyLmJiLnkxOyAvLyBkbyB0aGUgdHJhbnNmb3JtIG9uIGNyZWF0aW9uIHRvIHNhdmUgY3ljbGVzIChpdCdzIHRoZSBzYW1lIGZvciBhbGwgZWxlcylcblxuICAgIGN4dC5zY2FsZShzY2FsZSwgc2NhbGUpO1xuICAgIGN4dC50cmFuc2xhdGUoZHgsIGR5KTtcbiAgICByZXR1cm4gbGF5ZXI7XG4gIH07XG5cbiAgTFRDcC5nZXRMYXllcnMgPSBmdW5jdGlvbiAoZWxlcywgcHhSYXRpbywgbHZsKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciByID0gc2VsZi5yZW5kZXJlcjtcbiAgICB2YXIgY3kgPSByLmN5O1xuICAgIHZhciB6b29tID0gY3kuem9vbSgpO1xuICAgIHZhciBmaXJzdEdldCA9IHNlbGYuZmlyc3RHZXQ7XG4gICAgc2VsZi5maXJzdEdldCA9IGZhbHNlOyAvLyBsb2coJy0tXFxuZ2V0IGxheWVycyB3aXRoICVzIGVsZXMnLCBlbGVzLmxlbmd0aCk7XG4gICAgLy9sb2cgZWxlcy5tYXAoZnVuY3Rpb24oZWxlKXsgcmV0dXJuIGVsZS5pZCgpIH0pICk7XG5cbiAgICBpZiAobHZsID09IG51bGwpIHtcbiAgICAgIGx2bCA9IE1hdGguY2VpbChsb2cyKHpvb20gKiBweFJhdGlvKSk7XG5cbiAgICAgIGlmIChsdmwgPCBtaW5MdmwpIHtcbiAgICAgICAgbHZsID0gbWluTHZsO1xuICAgICAgfSBlbHNlIGlmICh6b29tID49IG1heFpvb20gfHwgbHZsID4gbWF4THZsKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgIH1cblxuICAgIHNlbGYudmFsaWRhdGVMYXllcnNFbGVzT3JkZXJpbmcobHZsLCBlbGVzKTtcbiAgICB2YXIgbGF5ZXJzQnlMdmwgPSBzZWxmLmxheWVyc0J5TGV2ZWw7XG4gICAgdmFyIHNjYWxlID0gTWF0aC5wb3coMiwgbHZsKTtcbiAgICB2YXIgbGF5ZXJzID0gbGF5ZXJzQnlMdmxbbHZsXSA9IGxheWVyc0J5THZsW2x2bF0gfHwgW107XG4gICAgdmFyIGJiO1xuICAgIHZhciBsdmxDb21wbGV0ZSA9IHNlbGYubGV2ZWxJc0NvbXBsZXRlKGx2bCwgZWxlcyk7XG4gICAgdmFyIHRtcExheWVycztcblxuICAgIHZhciBjaGVja1RlbXBMZXZlbHMgPSBmdW5jdGlvbiBjaGVja1RlbXBMZXZlbHMoKSB7XG4gICAgICB2YXIgY2FuVXNlQXNUbXBMdmwgPSBmdW5jdGlvbiBjYW5Vc2VBc1RtcEx2bChsKSB7XG4gICAgICAgIHNlbGYudmFsaWRhdGVMYXllcnNFbGVzT3JkZXJpbmcobCwgZWxlcyk7XG5cbiAgICAgICAgaWYgKHNlbGYubGV2ZWxJc0NvbXBsZXRlKGwsIGVsZXMpKSB7XG4gICAgICAgICAgdG1wTGF5ZXJzID0gbGF5ZXJzQnlMdmxbbF07XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIHZhciBjaGVja0x2bHMgPSBmdW5jdGlvbiBjaGVja0x2bHMoZGlyKSB7XG4gICAgICAgIGlmICh0bXBMYXllcnMpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKHZhciBsID0gbHZsICsgZGlyOyBtaW5MdmwgPD0gbCAmJiBsIDw9IG1heEx2bDsgbCArPSBkaXIpIHtcbiAgICAgICAgICBpZiAoY2FuVXNlQXNUbXBMdmwobCkpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgY2hlY2tMdmxzKCsxKTtcbiAgICAgIGNoZWNrTHZscygtMSk7IC8vIHJlbW92ZSB0aGUgaW52YWxpZCBsYXllcnM7IHRoZXkgd2lsbCBiZSByZXBsYWNlZCBhcyBuZWVkZWQgbGF0ZXIgaW4gdGhpcyBmdW5jdGlvblxuXG4gICAgICBmb3IgKHZhciBpID0gbGF5ZXJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgIHZhciBsYXllciA9IGxheWVyc1tpXTtcblxuICAgICAgICBpZiAobGF5ZXIuaW52YWxpZCkge1xuICAgICAgICAgIHJlbW92ZUZyb21BcnJheShsYXllcnMsIGxheWVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICBpZiAoIWx2bENvbXBsZXRlKSB7XG4gICAgICAvLyBpZiB0aGUgY3VycmVudCBsZXZlbCBpcyBpbmNvbXBsZXRlLCB0aGVuIHVzZSB0aGUgY2xvc2VzdCwgYmVzdCBxdWFsaXR5IGxheWVyc2V0IHRlbXBvcmFyaWx5XG4gICAgICAvLyBhbmQgbGF0ZXIgcXVldWUgdGhlIGN1cnJlbnQgbGF5ZXJzZXQgc28gd2UgY2FuIGdldCB0aGUgcHJvcGVyIHF1YWxpdHkgbGV2ZWwgc29vblxuICAgICAgY2hlY2tUZW1wTGV2ZWxzKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGxvZygnbGV2ZWwgY29tcGxldGUsIHVzaW5nIGV4aXN0aW5nIGxheWVyc1xcbi0tJyk7XG4gICAgICByZXR1cm4gbGF5ZXJzO1xuICAgIH1cblxuICAgIHZhciBnZXRCYiA9IGZ1bmN0aW9uIGdldEJiKCkge1xuICAgICAgaWYgKCFiYikge1xuICAgICAgICBiYiA9IG1ha2VCb3VuZGluZ0JveCgpO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHVwZGF0ZUJvdW5kaW5nQm94KGJiLCBlbGVzW2ldLmJvdW5kaW5nQm94KCkpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBiYjtcbiAgICB9O1xuXG4gICAgdmFyIG1ha2VMYXllciA9IGZ1bmN0aW9uIG1ha2VMYXllcihvcHRzKSB7XG4gICAgICBvcHRzID0gb3B0cyB8fCB7fTtcbiAgICAgIHZhciBhZnRlciA9IG9wdHMuYWZ0ZXI7XG4gICAgICBnZXRCYigpO1xuICAgICAgdmFyIGFyZWEgPSBiYi53ICogc2NhbGUgKiAoYmIuaCAqIHNjYWxlKTtcblxuICAgICAgaWYgKGFyZWEgPiBtYXhMYXllckFyZWEpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIHZhciBsYXllciA9IHNlbGYubWFrZUxheWVyKGJiLCBsdmwpO1xuXG4gICAgICBpZiAoYWZ0ZXIgIT0gbnVsbCkge1xuICAgICAgICB2YXIgaW5kZXggPSBsYXllcnMuaW5kZXhPZihhZnRlcikgKyAxO1xuICAgICAgICBsYXllcnMuc3BsaWNlKGluZGV4LCAwLCBsYXllcik7XG4gICAgICB9IGVsc2UgaWYgKG9wdHMuaW5zZXJ0ID09PSB1bmRlZmluZWQgfHwgb3B0cy5pbnNlcnQpIHtcbiAgICAgICAgLy8gbm8gYWZ0ZXIgc3BlY2lmaWVkID0+IGZpcnN0IGxheWVyIG1hZGUgc28gcHV0IGF0IHN0YXJ0XG4gICAgICAgIGxheWVycy51bnNoaWZ0KGxheWVyKTtcbiAgICAgIH0gLy8gaWYoIHRtcExheWVycyApe1xuICAgICAgLy9zZWxmLnF1ZXVlTGF5ZXIoIGxheWVyICk7XG4gICAgICAvLyB9XG5cblxuICAgICAgcmV0dXJuIGxheWVyO1xuICAgIH07XG5cbiAgICBpZiAoc2VsZi5za2lwcGluZyAmJiAhZmlyc3RHZXQpIHtcbiAgICAgIC8vIGxvZygnc2tpcCBsYXllcnMnKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gLy8gbG9nKCdkbyBsYXllcnMnKTtcblxuXG4gICAgdmFyIGxheWVyID0gbnVsbDtcbiAgICB2YXIgbWF4RWxlc1BlckxheWVyID0gZWxlcy5sZW5ndGggLyBkZWZOdW1MYXllcnM7XG4gICAgdmFyIGFsbG93TGF6eVF1ZXVlaW5nID0gIWZpcnN0R2V0O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBlbGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZWxlID0gZWxlc1tpXTtcbiAgICAgIHZhciBycyA9IGVsZS5fcHJpdmF0ZS5yc2NyYXRjaDtcbiAgICAgIHZhciBjYWNoZXMgPSBycy5pbWdMYXllckNhY2hlcyA9IHJzLmltZ0xheWVyQ2FjaGVzIHx8IHt9OyAvLyBsb2coJ2xvb2sgYXQgZWxlJywgZWxlLmlkKCkpO1xuXG4gICAgICB2YXIgZXhpc3RpbmdMYXllciA9IGNhY2hlc1tsdmxdO1xuXG4gICAgICBpZiAoZXhpc3RpbmdMYXllcikge1xuICAgICAgICAvLyByZXVzZSBsYXllciBmb3IgbGF0ZXIgZWxlc1xuICAgICAgICAvLyBsb2coJ3JldXNlIGxheWVyIGZvcicsIGVsZS5pZCgpKTtcbiAgICAgICAgbGF5ZXIgPSBleGlzdGluZ0xheWVyO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFsYXllciB8fCBsYXllci5lbGVzLmxlbmd0aCA+PSBtYXhFbGVzUGVyTGF5ZXIgfHwgIWJvdW5kaW5nQm94SW5Cb3VuZGluZ0JveChsYXllci5iYiwgZWxlLmJvdW5kaW5nQm94KCkpKSB7XG4gICAgICAgIC8vIGxvZygnbWFrZSBuZXcgbGF5ZXIgZm9yIGVsZSAlcycsIGVsZS5pZCgpKTtcbiAgICAgICAgbGF5ZXIgPSBtYWtlTGF5ZXIoe1xuICAgICAgICAgIGluc2VydDogdHJ1ZSxcbiAgICAgICAgICBhZnRlcjogbGF5ZXJcbiAgICAgICAgfSk7IC8vIGlmIG5vdyBsYXllciBjYW4gYmUgYnVpbHQgdGhlbiB3ZSBjYW4ndCB1c2UgbGF5ZXJzIGF0IHRoaXMgbGV2ZWxcblxuICAgICAgICBpZiAoIWxheWVyKSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH0gLy8gbG9nKCduZXcgbGF5ZXIgd2l0aCBpZCAlcycsIGxheWVyLmlkKTtcblxuICAgICAgfVxuXG4gICAgICBpZiAodG1wTGF5ZXJzIHx8IGFsbG93TGF6eVF1ZXVlaW5nKSB7XG4gICAgICAgIC8vIGxvZygncXVldWUgZWxlICVzIGluIGxheWVyICVzJywgZWxlLmlkKCksIGxheWVyLmlkKTtcbiAgICAgICAgc2VsZi5xdWV1ZUxheWVyKGxheWVyLCBlbGUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gbG9nKCdkcmF3IGVsZSAlcyBpbiBsYXllciAlcycsIGVsZS5pZCgpLCBsYXllci5pZCk7XG4gICAgICAgIHNlbGYuZHJhd0VsZUluTGF5ZXIobGF5ZXIsIGVsZSwgbHZsLCBweFJhdGlvKTtcbiAgICAgIH1cblxuICAgICAgbGF5ZXIuZWxlcy5wdXNoKGVsZSk7XG4gICAgICBjYWNoZXNbbHZsXSA9IGxheWVyO1xuICAgIH0gLy8gbG9nKCctLScpO1xuXG5cbiAgICBpZiAodG1wTGF5ZXJzKSB7XG4gICAgICAvLyB0aGVuIHdlIG9ubHkgcXVldWVkIHRoZSBjdXJyZW50IGxheWVyc2V0IGFuZCBjYW4ndCBkcmF3IGl0IHlldFxuICAgICAgcmV0dXJuIHRtcExheWVycztcbiAgICB9XG5cbiAgICBpZiAoYWxsb3dMYXp5UXVldWVpbmcpIHtcbiAgICAgIC8vIGxvZygnbGF6eSBxdWV1ZSBsZXZlbCcsIGx2bCk7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gbGF5ZXJzO1xuICB9OyAvLyBhIGxheWVyIG1heSB3YW50IHRvIHVzZSBhbiBlbGUgY2FjaGUgb2YgYSBoaWdoZXIgbGV2ZWwgdG8gYXZvaWQgYmx1cnJpbmVzc1xuICAvLyBzbyB0aGUgbGF5ZXIgbGV2ZWwgbWlnaHQgbm90IGVxdWFsIHRoZSBlbGUgbGV2ZWxcblxuXG4gIExUQ3AuZ2V0RWxlTGV2ZWxGb3JMYXllckxldmVsID0gZnVuY3Rpb24gKGx2bCwgcHhSYXRpbykge1xuICAgIHJldHVybiBsdmw7XG4gIH07XG5cbiAgTFRDcC5kcmF3RWxlSW5MYXllciA9IGZ1bmN0aW9uIChsYXllciwgZWxlLCBsdmwsIHB4UmF0aW8pIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHIgPSB0aGlzLnJlbmRlcmVyO1xuICAgIHZhciBjb250ZXh0ID0gbGF5ZXIuY29udGV4dDtcbiAgICB2YXIgYmIgPSBlbGUuYm91bmRpbmdCb3goKTtcblxuICAgIGlmIChiYi53ID09PSAwIHx8IGJiLmggPT09IDAgfHwgIWVsZS52aXNpYmxlKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBsdmwgPSBzZWxmLmdldEVsZUxldmVsRm9yTGF5ZXJMZXZlbChsdmwsIHB4UmF0aW8pO1xuXG4gICAge1xuICAgICAgci5zZXRJbWdTbW9vdGhpbmcoY29udGV4dCwgZmFsc2UpO1xuICAgIH1cblxuICAgIHtcbiAgICAgIHIuZHJhd0NhY2hlZEVsZW1lbnQoY29udGV4dCwgZWxlLCBudWxsLCBudWxsLCBsdmwsIHVzZUhpZ2hRdWFsaXR5RWxlVHhyUmVxcyk7XG4gICAgfVxuXG4gICAge1xuICAgICAgci5zZXRJbWdTbW9vdGhpbmcoY29udGV4dCwgdHJ1ZSk7XG4gICAgfVxuICB9O1xuXG4gIExUQ3AubGV2ZWxJc0NvbXBsZXRlID0gZnVuY3Rpb24gKGx2bCwgZWxlcykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgbGF5ZXJzID0gc2VsZi5sYXllcnNCeUxldmVsW2x2bF07XG5cbiAgICBpZiAoIWxheWVycyB8fCBsYXllcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdmFyIG51bUVsZXNJbkxheWVycyA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxheWVycy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGxheWVyID0gbGF5ZXJzW2ldOyAvLyBpZiB0aGVyZSBhcmUgYW55IGVsZXMgbmVlZGVkIHRvIGJlIGRyYXduIHlldCwgdGhlIGxldmVsIGlzIG5vdCBjb21wbGV0ZVxuXG4gICAgICBpZiAobGF5ZXIucmVxcyA+IDApIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSAvLyBpZiB0aGUgbGF5ZXIgaXMgaW52YWxpZCwgdGhlIGxldmVsIGlzIG5vdCBjb21wbGV0ZVxuXG5cbiAgICAgIGlmIChsYXllci5pbnZhbGlkKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgbnVtRWxlc0luTGF5ZXJzICs9IGxheWVyLmVsZXMubGVuZ3RoO1xuICAgIH0gLy8gd2Ugc2hvdWxkIGhhdmUgZXhhY3RseSB0aGUgbnVtYmVyIG9mIGVsZXMgcGFzc2VkIGluIHRvIGJlIGNvbXBsZXRlXG5cblxuICAgIGlmIChudW1FbGVzSW5MYXllcnMgIT09IGVsZXMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgTFRDcC52YWxpZGF0ZUxheWVyc0VsZXNPcmRlcmluZyA9IGZ1bmN0aW9uIChsdmwsIGVsZXMpIHtcbiAgICB2YXIgbGF5ZXJzID0gdGhpcy5sYXllcnNCeUxldmVsW2x2bF07XG5cbiAgICBpZiAoIWxheWVycykge1xuICAgICAgcmV0dXJuO1xuICAgIH0gLy8gaWYgaW4gYSBsYXllciB0aGUgZWxlcyBhcmUgbm90IGluIHRoZSBzYW1lIG9yZGVyLCB0aGVuIHRoZSBsYXllciBpcyBpbnZhbGlkXG4gICAgLy8gKGkuZS4gdGhlcmUgaXMgYW4gZWxlIGluIGJldHdlZW4gdGhlIGVsZXMgaW4gdGhlIGxheWVyKVxuXG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxheWVycy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGxheWVyID0gbGF5ZXJzW2ldO1xuICAgICAgdmFyIG9mZnNldCA9IC0xOyAvLyBmaW5kIHRoZSBvZmZzZXRcblxuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBlbGVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIGlmIChsYXllci5lbGVzWzBdID09PSBlbGVzW2pdKSB7XG4gICAgICAgICAgb2Zmc2V0ID0gajtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAob2Zmc2V0IDwgMCkge1xuICAgICAgICAvLyB0aGVuIHRoZSBsYXllciBoYXMgbm9uZXhpc3RlbnQgZWxlbWVudHMgYW5kIGlzIGludmFsaWRcbiAgICAgICAgdGhpcy5pbnZhbGlkYXRlTGF5ZXIobGF5ZXIpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH0gLy8gdGhlIGVsZXMgaW4gdGhlIGxheWVyIG11c3QgYmUgaW4gdGhlIHNhbWUgY29udGludW91cyBvcmRlciwgZWxzZSB0aGUgbGF5ZXIgaXMgaW52YWxpZFxuXG5cbiAgICAgIHZhciBvID0gb2Zmc2V0O1xuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGxheWVyLmVsZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKGxheWVyLmVsZXNbal0gIT09IGVsZXNbbyArIGpdKSB7XG4gICAgICAgICAgLy8gbG9nKCdpbnZhbGlkYXRlIGJhc2VkIG9uIG9yZGVyaW5nJywgbGF5ZXIuaWQpO1xuICAgICAgICAgIHRoaXMuaW52YWxpZGF0ZUxheWVyKGxheWVyKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBMVENwLnVwZGF0ZUVsZW1lbnRzSW5MYXllcnMgPSBmdW5jdGlvbiAoZWxlcywgdXBkYXRlKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBpc0VsZXMgPSBlbGVtZW50KGVsZXNbMF0pOyAvLyBjb2xsZWN0IHVkcGF0ZWQgZWxlbWVudHMgKGNhc2NhZGVkIGZyb20gdGhlIGxheWVycykgYW5kIHVwZGF0ZSBlYWNoXG4gICAgLy8gbGF5ZXIgaXRzZWxmIGFsb25nIHRoZSB3YXlcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHJlcSA9IGlzRWxlcyA/IG51bGwgOiBlbGVzW2ldO1xuICAgICAgdmFyIGVsZSA9IGlzRWxlcyA/IGVsZXNbaV0gOiBlbGVzW2ldLmVsZTtcbiAgICAgIHZhciBycyA9IGVsZS5fcHJpdmF0ZS5yc2NyYXRjaDtcbiAgICAgIHZhciBjYWNoZXMgPSBycy5pbWdMYXllckNhY2hlcyA9IHJzLmltZ0xheWVyQ2FjaGVzIHx8IHt9O1xuXG4gICAgICBmb3IgKHZhciBsID0gbWluTHZsOyBsIDw9IG1heEx2bDsgbCsrKSB7XG4gICAgICAgIHZhciBsYXllciA9IGNhY2hlc1tsXTtcblxuICAgICAgICBpZiAoIWxheWVyKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH0gLy8gaWYgdXBkYXRlIGlzIGEgcmVxdWVzdCBmcm9tIHRoZSBlbGUgY2FjaGUsIHRoZW4gaXQgYWZmZWN0cyBvbmx5XG4gICAgICAgIC8vIHRoZSBtYXRjaGluZyBsZXZlbFxuXG5cbiAgICAgICAgaWYgKHJlcSAmJiBzZWxmLmdldEVsZUxldmVsRm9yTGF5ZXJMZXZlbChsYXllci5sZXZlbCkgIT09IHJlcS5sZXZlbCkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdXBkYXRlKGxheWVyLCBlbGUsIHJlcSk7XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIExUQ3AuaGF2ZUxheWVycyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGhhdmVMYXllcnMgPSBmYWxzZTtcblxuICAgIGZvciAodmFyIGwgPSBtaW5Mdmw7IGwgPD0gbWF4THZsOyBsKyspIHtcbiAgICAgIHZhciBsYXllcnMgPSBzZWxmLmxheWVyc0J5TGV2ZWxbbF07XG5cbiAgICAgIGlmIChsYXllcnMgJiYgbGF5ZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgaGF2ZUxheWVycyA9IHRydWU7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBoYXZlTGF5ZXJzO1xuICB9O1xuXG4gIExUQ3AuaW52YWxpZGF0ZUVsZW1lbnRzID0gZnVuY3Rpb24gKGVsZXMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICBpZiAoZWxlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzZWxmLmxhc3RJbnZhbGlkYXRpb25UaW1lID0gcGVyZm9ybWFuY2VOb3coKTsgLy8gbG9nKCd1cGRhdGUgaW52YWxpZGF0ZSBsYXllciB0aW1lIGZyb20gZWxlcycpO1xuXG4gICAgaWYgKGVsZXMubGVuZ3RoID09PSAwIHx8ICFzZWxmLmhhdmVMYXllcnMoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHNlbGYudXBkYXRlRWxlbWVudHNJbkxheWVycyhlbGVzLCBmdW5jdGlvbiBpbnZhbEFzc29jTGF5ZXJzKGxheWVyLCBlbGUsIHJlcSkge1xuICAgICAgc2VsZi5pbnZhbGlkYXRlTGF5ZXIobGF5ZXIpO1xuICAgIH0pO1xuICB9O1xuXG4gIExUQ3AuaW52YWxpZGF0ZUxheWVyID0gZnVuY3Rpb24gKGxheWVyKSB7XG4gICAgLy8gbG9nKCd1cGRhdGUgaW52YWxpZGF0ZSBsYXllciB0aW1lJyk7XG4gICAgdGhpcy5sYXN0SW52YWxpZGF0aW9uVGltZSA9IHBlcmZvcm1hbmNlTm93KCk7XG5cbiAgICBpZiAobGF5ZXIuaW52YWxpZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH0gLy8gc2F2ZSBjeWNsZXNcblxuXG4gICAgdmFyIGx2bCA9IGxheWVyLmxldmVsO1xuICAgIHZhciBlbGVzID0gbGF5ZXIuZWxlcztcbiAgICB2YXIgbGF5ZXJzID0gdGhpcy5sYXllcnNCeUxldmVsW2x2bF07IC8vIGxvZygnaW52YWxpZGF0ZSBsYXllcicsIGxheWVyLmlkICk7XG5cbiAgICByZW1vdmVGcm9tQXJyYXkobGF5ZXJzLCBsYXllcik7IC8vIGxheWVyLmVsZXMgPSBbXTtcblxuICAgIGxheWVyLmVsZXNRdWV1ZSA9IFtdO1xuICAgIGxheWVyLmludmFsaWQgPSB0cnVlO1xuXG4gICAgaWYgKGxheWVyLnJlcGxhY2VtZW50KSB7XG4gICAgICBsYXllci5yZXBsYWNlbWVudC5pbnZhbGlkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBjYWNoZXMgPSBlbGVzW2ldLl9wcml2YXRlLnJzY3JhdGNoLmltZ0xheWVyQ2FjaGVzO1xuXG4gICAgICBpZiAoY2FjaGVzKSB7XG4gICAgICAgIGNhY2hlc1tsdmxdID0gbnVsbDtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgTFRDcC5yZWZpbmVFbGVtZW50VGV4dHVyZXMgPSBmdW5jdGlvbiAoZWxlcykge1xuICAgIHZhciBzZWxmID0gdGhpczsgLy8gbG9nKCdyZWZpbmUnLCBlbGVzLmxlbmd0aCk7XG5cbiAgICBzZWxmLnVwZGF0ZUVsZW1lbnRzSW5MYXllcnMoZWxlcywgZnVuY3Rpb24gcmVmaW5lRWFjaEVsZShsYXllciwgZWxlLCByZXEpIHtcbiAgICAgIHZhciByTHlyID0gbGF5ZXIucmVwbGFjZW1lbnQ7XG5cbiAgICAgIGlmICghckx5cikge1xuICAgICAgICByTHlyID0gbGF5ZXIucmVwbGFjZW1lbnQgPSBzZWxmLm1ha2VMYXllcihsYXllci5iYiwgbGF5ZXIubGV2ZWwpO1xuICAgICAgICByTHlyLnJlcGxhY2VzID0gbGF5ZXI7XG4gICAgICAgIHJMeXIuZWxlcyA9IGxheWVyLmVsZXM7IC8vIGxvZygnbWFrZSByZXBsYWNlbWVudCBsYXllciAlcyBmb3IgJXMgd2l0aCBsZXZlbCAlcycsIHJMeXIuaWQsIGxheWVyLmlkLCByTHlyLmxldmVsKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFyTHlyLnJlcXMpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByTHlyLmVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICBzZWxmLnF1ZXVlTGF5ZXIockx5ciwgckx5ci5lbGVzW2ldKTtcbiAgICAgICAgfSAvLyBsb2coJ3F1ZXVlIHJlcGxhY2VtZW50IGxheWVyIHJlZmluZW1lbnQnLCByTHlyLmlkKTtcblxuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIExUQ3AuZW5xdWV1ZUVsZW1lbnRSZWZpbmVtZW50ID0gZnVuY3Rpb24gKGVsZSkge1xuXG4gICAgdGhpcy5lbGVUeHJEZXFzLm1lcmdlKGVsZSk7XG4gICAgdGhpcy5zY2hlZHVsZUVsZW1lbnRSZWZpbmVtZW50KCk7XG4gIH07XG5cbiAgTFRDcC5xdWV1ZUxheWVyID0gZnVuY3Rpb24gKGxheWVyLCBlbGUpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHEgPSBzZWxmLmxheWVyc1F1ZXVlO1xuICAgIHZhciBlbGVzUSA9IGxheWVyLmVsZXNRdWV1ZTtcbiAgICB2YXIgaGFzSWQgPSBlbGVzUS5oYXNJZCA9IGVsZXNRLmhhc0lkIHx8IHt9OyAvLyBpZiBhIGxheWVyIGlzIGdvaW5nIHRvIGJlIHJlcGxhY2VkLCBxdWV1aW5nIGlzIGEgd2FzdGUgb2YgdGltZVxuXG4gICAgaWYgKGxheWVyLnJlcGxhY2VtZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGVsZSkge1xuICAgICAgaWYgKGhhc0lkW2VsZS5pZCgpXSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGVsZXNRLnB1c2goZWxlKTtcbiAgICAgIGhhc0lkW2VsZS5pZCgpXSA9IHRydWU7XG4gICAgfVxuXG4gICAgaWYgKGxheWVyLnJlcXMpIHtcbiAgICAgIGxheWVyLnJlcXMrKztcbiAgICAgIHEudXBkYXRlSXRlbShsYXllcik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxheWVyLnJlcXMgPSAxO1xuICAgICAgcS5wdXNoKGxheWVyKTtcbiAgICB9XG4gIH07XG5cbiAgTFRDcC5kZXF1ZXVlID0gZnVuY3Rpb24gKHB4UmF0aW8pIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHEgPSBzZWxmLmxheWVyc1F1ZXVlO1xuICAgIHZhciBkZXFkID0gW107XG4gICAgdmFyIGVsZURlcXMgPSAwO1xuXG4gICAgd2hpbGUgKGVsZURlcXMgPCBtYXhEZXFTaXplKSB7XG4gICAgICBpZiAocS5zaXplKCkgPT09IDApIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIHZhciBsYXllciA9IHEucGVlaygpOyAvLyBpZiBhIGxheWVyIGhhcyBiZWVuIG9yIHdpbGwgYmUgcmVwbGFjZWQsIHRoZW4gZG9uJ3Qgd2FzdGUgdGltZSB3aXRoIGl0XG5cbiAgICAgIGlmIChsYXllci5yZXBsYWNlbWVudCkge1xuICAgICAgICAvLyBsb2coJ2xheWVyICVzIGluIHF1ZXVlIHNraXBwZWQgYi9jIGl0IGFscmVhZHkgaGFzIGEgcmVwbGFjZW1lbnQnLCBsYXllci5pZCk7XG4gICAgICAgIHEucG9wKCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfSAvLyBpZiB0aGlzIGlzIGEgcmVwbGFjZW1lbnQgbGF5ZXIgdGhhdCBoYXMgYmVlbiBzdXBlcmNlZGVkLCB0aGVuIGZvcmdldCBpdFxuXG5cbiAgICAgIGlmIChsYXllci5yZXBsYWNlcyAmJiBsYXllciAhPT0gbGF5ZXIucmVwbGFjZXMucmVwbGFjZW1lbnQpIHtcbiAgICAgICAgLy8gbG9nKCdsYXllciBpcyBubyBsb25nZXIgdGhlIG1vc3QgdXB0b2RhdGUgcmVwbGFjZW1lbnQ7IGRlcXVldWVkJywgbGF5ZXIuaWQpXG4gICAgICAgIHEucG9wKCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAobGF5ZXIuaW52YWxpZCkge1xuICAgICAgICAvLyBsb2coJ3JlcGxhY2VtZW50IGxheWVyICVzIGlzIGludmFsaWQ7IGRlcXVldWVkJywgbGF5ZXIuaWQpO1xuICAgICAgICBxLnBvcCgpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdmFyIGVsZSA9IGxheWVyLmVsZXNRdWV1ZS5zaGlmdCgpO1xuXG4gICAgICBpZiAoZWxlKSB7XG4gICAgICAgIC8vIGxvZygnZGVxdWV1ZSBsYXllciAlcycsIGxheWVyLmlkKTtcbiAgICAgICAgc2VsZi5kcmF3RWxlSW5MYXllcihsYXllciwgZWxlLCBsYXllci5sZXZlbCwgcHhSYXRpbyk7XG4gICAgICAgIGVsZURlcXMrKztcbiAgICAgIH1cblxuICAgICAgaWYgKGRlcWQubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIC8vIHdlIG5lZWQgb25seSBvbmUgZW50cnkgaW4gZGVxZCB0byBxdWV1ZSByZWRyYXdpbmcgZXRjXG4gICAgICAgIGRlcWQucHVzaCh0cnVlKTtcbiAgICAgIH0gLy8gaWYgdGhlIGxheWVyIGhhcyBhbGwgaXRzIGVsZXMgZG9uZSwgdGhlbiByZW1vdmUgZnJvbSB0aGUgcXVldWVcblxuXG4gICAgICBpZiAobGF5ZXIuZWxlc1F1ZXVlLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBxLnBvcCgpO1xuICAgICAgICBsYXllci5yZXFzID0gMDsgLy8gbG9nKCdkZXF1ZXVlIG9mIGxheWVyICVzIGNvbXBsZXRlJywgbGF5ZXIuaWQpO1xuICAgICAgICAvLyB3aGVuIGEgcmVwbGFjZW1lbnQgbGF5ZXIgaXMgZGVxdWV1ZWQsIGl0IHJlcGxhY2VzIHRoZSBvbGQgbGF5ZXIgaW4gdGhlIGxldmVsXG5cbiAgICAgICAgaWYgKGxheWVyLnJlcGxhY2VzKSB7XG4gICAgICAgICAgc2VsZi5hcHBseUxheWVyUmVwbGFjZW1lbnQobGF5ZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5yZXF1ZXN0UmVkcmF3KCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlcWQ7XG4gIH07XG5cbiAgTFRDcC5hcHBseUxheWVyUmVwbGFjZW1lbnQgPSBmdW5jdGlvbiAobGF5ZXIpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGxheWVyc0luTGV2ZWwgPSBzZWxmLmxheWVyc0J5TGV2ZWxbbGF5ZXIubGV2ZWxdO1xuICAgIHZhciByZXBsYWNlZCA9IGxheWVyLnJlcGxhY2VzO1xuICAgIHZhciBpbmRleCA9IGxheWVyc0luTGV2ZWwuaW5kZXhPZihyZXBsYWNlZCk7IC8vIGlmIHRoZSByZXBsYWNlZCBsYXllciBpcyBub3QgaW4gdGhlIGFjdGl2ZSBsaXN0IGZvciB0aGUgbGV2ZWwsIHRoZW4gcmVwbGFjaW5nXG4gICAgLy8gcmVmcyB3b3VsZCBiZSBhIG1pc3Rha2UgKGkuZS4gb3ZlcndyaXRpbmcgdGhlIHRydWUgYWN0aXZlIGxheWVyKVxuXG4gICAgaWYgKGluZGV4IDwgMCB8fCByZXBsYWNlZC5pbnZhbGlkKSB7XG4gICAgICAvLyBsb2coJ3JlcGxhY2VtZW50IGxheWVyIHdvdWxkIGhhdmUgbm8gZWZmZWN0JywgbGF5ZXIuaWQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGxheWVyc0luTGV2ZWxbaW5kZXhdID0gbGF5ZXI7IC8vIHJlcGxhY2UgbGV2ZWwgcmVmXG4gICAgLy8gcmVwbGFjZSByZWZzIGluIGVsZXNcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGF5ZXIuZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIF9wID0gbGF5ZXIuZWxlc1tpXS5fcHJpdmF0ZTtcbiAgICAgIHZhciBjYWNoZSA9IF9wLmltZ0xheWVyQ2FjaGVzID0gX3AuaW1nTGF5ZXJDYWNoZXMgfHwge307XG5cbiAgICAgIGlmIChjYWNoZSkge1xuICAgICAgICBjYWNoZVtsYXllci5sZXZlbF0gPSBsYXllcjtcbiAgICAgIH1cbiAgICB9IC8vIGxvZygnYXBwbHkgcmVwbGFjZW1lbnQgbGF5ZXIgJXMgb3ZlciAlcycsIGxheWVyLmlkLCByZXBsYWNlZC5pZCk7XG5cblxuICAgIHNlbGYucmVxdWVzdFJlZHJhdygpO1xuICB9O1xuXG4gIExUQ3AucmVxdWVzdFJlZHJhdyA9IGRlYm91bmNlXzEoZnVuY3Rpb24gKCkge1xuICAgIHZhciByID0gdGhpcy5yZW5kZXJlcjtcbiAgICByLnJlZHJhd0hpbnQoJ2VsZXMnLCB0cnVlKTtcbiAgICByLnJlZHJhd0hpbnQoJ2RyYWcnLCB0cnVlKTtcbiAgICByLnJlZHJhdygpO1xuICB9LCAxMDApO1xuICBMVENwLnNldHVwRGVxdWV1ZWluZyA9IGRlZnMuc2V0dXBEZXF1ZXVlaW5nKHtcbiAgICBkZXFSZWRyYXdUaHJlc2hvbGQ6IGRlcVJlZHJhd1RocmVzaG9sZCxcbiAgICBkZXFDb3N0OiBkZXFDb3N0LFxuICAgIGRlcUF2Z0Nvc3Q6IGRlcUF2Z0Nvc3QsXG4gICAgZGVxTm9EcmF3Q29zdDogZGVxTm9EcmF3Q29zdCxcbiAgICBkZXFGYXN0Q29zdDogZGVxRmFzdENvc3QsXG4gICAgZGVxOiBmdW5jdGlvbiBkZXEoc2VsZiwgcHhSYXRpbykge1xuICAgICAgcmV0dXJuIHNlbGYuZGVxdWV1ZShweFJhdGlvKTtcbiAgICB9LFxuICAgIG9uRGVxZDogbm9vcCQxLFxuICAgIHNob3VsZFJlZHJhdzogdHJ1ZWlmeSxcbiAgICBwcmlvcml0eTogZnVuY3Rpb24gcHJpb3JpdHkoc2VsZikge1xuICAgICAgcmV0dXJuIHNlbGYucmVuZGVyZXIuYmVmb3JlUmVuZGVyUHJpb3JpdGllcy5seXJUeHJEZXE7XG4gICAgfVxuICB9KTtcblxuICB2YXIgQ1JwJGEgPSB7fTtcbiAgdmFyIGltcGw7XG5cbiAgZnVuY3Rpb24gcG9seWdvbihjb250ZXh0LCBwb2ludHMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHB0ID0gcG9pbnRzW2ldO1xuICAgICAgY29udGV4dC5saW5lVG8ocHQueCwgcHQueSk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gdHJpYW5nbGVCYWNrY3VydmUoY29udGV4dCwgcG9pbnRzLCBjb250cm9sUG9pbnQpIHtcbiAgICB2YXIgZmlyc3RQdDtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgcHQgPSBwb2ludHNbaV07XG5cbiAgICAgIGlmIChpID09PSAwKSB7XG4gICAgICAgIGZpcnN0UHQgPSBwdDtcbiAgICAgIH1cblxuICAgICAgY29udGV4dC5saW5lVG8ocHQueCwgcHQueSk7XG4gICAgfVxuXG4gICAgY29udGV4dC5xdWFkcmF0aWNDdXJ2ZVRvKGNvbnRyb2xQb2ludC54LCBjb250cm9sUG9pbnQueSwgZmlyc3RQdC54LCBmaXJzdFB0LnkpO1xuICB9XG5cbiAgZnVuY3Rpb24gdHJpYW5nbGVUZWUoY29udGV4dCwgdHJpYW5nbGVQb2ludHMsIHRlZVBvaW50cykge1xuICAgIGlmIChjb250ZXh0LmJlZ2luUGF0aCkge1xuICAgICAgY29udGV4dC5iZWdpblBhdGgoKTtcbiAgICB9XG5cbiAgICB2YXIgdHJpUHRzID0gdHJpYW5nbGVQb2ludHM7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRyaVB0cy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHB0ID0gdHJpUHRzW2ldO1xuICAgICAgY29udGV4dC5saW5lVG8ocHQueCwgcHQueSk7XG4gICAgfVxuXG4gICAgdmFyIHRlZVB0cyA9IHRlZVBvaW50cztcbiAgICB2YXIgZmlyc3RUZWVQdCA9IHRlZVBvaW50c1swXTtcbiAgICBjb250ZXh0Lm1vdmVUbyhmaXJzdFRlZVB0LngsIGZpcnN0VGVlUHQueSk7XG5cbiAgICBmb3IgKHZhciBpID0gMTsgaSA8IHRlZVB0cy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHB0ID0gdGVlUHRzW2ldO1xuICAgICAgY29udGV4dC5saW5lVG8ocHQueCwgcHQueSk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQuY2xvc2VQYXRoKSB7XG4gICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGNpcmNsZVRyaWFuZ2xlKGNvbnRleHQsIHRyaWFuZ2xlUG9pbnRzLCByeCwgcnksIHIpIHtcbiAgICBpZiAoY29udGV4dC5iZWdpblBhdGgpIHtcbiAgICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XG4gICAgfVxuXG4gICAgY29udGV4dC5hcmMocngsIHJ5LCByLCAwLCBNYXRoLlBJICogMiwgZmFsc2UpO1xuICAgIHZhciB0cmlQdHMgPSB0cmlhbmdsZVBvaW50cztcbiAgICB2YXIgZmlyc3RUclB0ID0gdHJpUHRzWzBdO1xuICAgIGNvbnRleHQubW92ZVRvKGZpcnN0VHJQdC54LCBmaXJzdFRyUHQueSk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRyaVB0cy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHB0ID0gdHJpUHRzW2ldO1xuICAgICAgY29udGV4dC5saW5lVG8ocHQueCwgcHQueSk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQuY2xvc2VQYXRoKSB7XG4gICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGNpcmNsZShjb250ZXh0LCByeCwgcnksIHIpIHtcbiAgICBjb250ZXh0LmFyYyhyeCwgcnksIHIsIDAsIE1hdGguUEkgKiAyLCBmYWxzZSk7XG4gIH1cblxuICBDUnAkYS5hcnJvd1NoYXBlSW1wbCA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgcmV0dXJuIChpbXBsIHx8IChpbXBsID0ge1xuICAgICAgJ3BvbHlnb24nOiBwb2x5Z29uLFxuICAgICAgJ3RyaWFuZ2xlLWJhY2tjdXJ2ZSc6IHRyaWFuZ2xlQmFja2N1cnZlLFxuICAgICAgJ3RyaWFuZ2xlLXRlZSc6IHRyaWFuZ2xlVGVlLFxuICAgICAgJ2NpcmNsZS10cmlhbmdsZSc6IGNpcmNsZVRyaWFuZ2xlLFxuICAgICAgJ3RyaWFuZ2xlLWNyb3NzJzogdHJpYW5nbGVUZWUsXG4gICAgICAnY2lyY2xlJzogY2lyY2xlXG4gICAgfSkpW25hbWVdO1xuICB9O1xuXG4gIHZhciBDUnAkOSA9IHt9O1xuXG4gIENScCQ5LmRyYXdFbGVtZW50ID0gZnVuY3Rpb24gKGNvbnRleHQsIGVsZSwgc2hpZnRUb09yaWdpbldpdGhCYiwgc2hvd0xhYmVsLCBzaG93T3ZlcmxheSwgc2hvd09wYWNpdHkpIHtcbiAgICB2YXIgciA9IHRoaXM7XG5cbiAgICBpZiAoZWxlLmlzTm9kZSgpKSB7XG4gICAgICByLmRyYXdOb2RlKGNvbnRleHQsIGVsZSwgc2hpZnRUb09yaWdpbldpdGhCYiwgc2hvd0xhYmVsLCBzaG93T3ZlcmxheSwgc2hvd09wYWNpdHkpO1xuICAgIH0gZWxzZSB7XG4gICAgICByLmRyYXdFZGdlKGNvbnRleHQsIGVsZSwgc2hpZnRUb09yaWdpbldpdGhCYiwgc2hvd0xhYmVsLCBzaG93T3ZlcmxheSwgc2hvd09wYWNpdHkpO1xuICAgIH1cbiAgfTtcblxuICBDUnAkOS5kcmF3RWxlbWVudE92ZXJsYXkgPSBmdW5jdGlvbiAoY29udGV4dCwgZWxlKSB7XG4gICAgdmFyIHIgPSB0aGlzO1xuXG4gICAgaWYgKGVsZS5pc05vZGUoKSkge1xuICAgICAgci5kcmF3Tm9kZU92ZXJsYXkoY29udGV4dCwgZWxlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgci5kcmF3RWRnZU92ZXJsYXkoY29udGV4dCwgZWxlKTtcbiAgICB9XG4gIH07XG5cbiAgQ1JwJDkuZHJhd0VsZW1lbnRVbmRlcmxheSA9IGZ1bmN0aW9uIChjb250ZXh0LCBlbGUpIHtcbiAgICB2YXIgciA9IHRoaXM7XG5cbiAgICBpZiAoZWxlLmlzTm9kZSgpKSB7XG4gICAgICByLmRyYXdOb2RlVW5kZXJsYXkoY29udGV4dCwgZWxlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgci5kcmF3RWRnZVVuZGVybGF5KGNvbnRleHQsIGVsZSk7XG4gICAgfVxuICB9O1xuXG4gIENScCQ5LmRyYXdDYWNoZWRFbGVtZW50UG9ydGlvbiA9IGZ1bmN0aW9uIChjb250ZXh0LCBlbGUsIGVsZVR4ckNhY2hlLCBweFJhdGlvLCBsdmwsIHJlYXNvbiwgZ2V0Um90YXRpb24sIGdldE9wYWNpdHkpIHtcbiAgICB2YXIgciA9IHRoaXM7XG4gICAgdmFyIGJiID0gZWxlVHhyQ2FjaGUuZ2V0Qm91bmRpbmdCb3goZWxlKTtcblxuICAgIGlmIChiYi53ID09PSAwIHx8IGJiLmggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9IC8vIGlnbm9yZSB6ZXJvIHNpemUgY2FzZVxuXG5cbiAgICB2YXIgZWxlQ2FjaGUgPSBlbGVUeHJDYWNoZS5nZXRFbGVtZW50KGVsZSwgYmIsIHB4UmF0aW8sIGx2bCwgcmVhc29uKTtcblxuICAgIGlmIChlbGVDYWNoZSAhPSBudWxsKSB7XG4gICAgICB2YXIgb3BhY2l0eSA9IGdldE9wYWNpdHkociwgZWxlKTtcblxuICAgICAgaWYgKG9wYWNpdHkgPT09IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgdGhldGEgPSBnZXRSb3RhdGlvbihyLCBlbGUpO1xuICAgICAgdmFyIHgxID0gYmIueDEsXG4gICAgICAgICAgeTEgPSBiYi55MSxcbiAgICAgICAgICB3ID0gYmIudyxcbiAgICAgICAgICBoID0gYmIuaDtcbiAgICAgIHZhciB4LCB5LCBzeCwgc3ksIHNtb290aDtcblxuICAgICAgaWYgKHRoZXRhICE9PSAwKSB7XG4gICAgICAgIHZhciByb3RQdCA9IGVsZVR4ckNhY2hlLmdldFJvdGF0aW9uUG9pbnQoZWxlKTtcbiAgICAgICAgc3ggPSByb3RQdC54O1xuICAgICAgICBzeSA9IHJvdFB0Lnk7XG4gICAgICAgIGNvbnRleHQudHJhbnNsYXRlKHN4LCBzeSk7XG4gICAgICAgIGNvbnRleHQucm90YXRlKHRoZXRhKTtcbiAgICAgICAgc21vb3RoID0gci5nZXRJbWdTbW9vdGhpbmcoY29udGV4dCk7XG5cbiAgICAgICAgaWYgKCFzbW9vdGgpIHtcbiAgICAgICAgICByLnNldEltZ1Ntb290aGluZyhjb250ZXh0LCB0cnVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBvZmYgPSBlbGVUeHJDYWNoZS5nZXRSb3RhdGlvbk9mZnNldChlbGUpO1xuICAgICAgICB4ID0gb2ZmLng7XG4gICAgICAgIHkgPSBvZmYueTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHggPSB4MTtcbiAgICAgICAgeSA9IHkxO1xuICAgICAgfVxuXG4gICAgICB2YXIgb2xkR2xvYmFsQWxwaGE7XG5cbiAgICAgIGlmIChvcGFjaXR5ICE9PSAxKSB7XG4gICAgICAgIG9sZEdsb2JhbEFscGhhID0gY29udGV4dC5nbG9iYWxBbHBoYTtcbiAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IG9sZEdsb2JhbEFscGhhICogb3BhY2l0eTtcbiAgICAgIH1cblxuICAgICAgY29udGV4dC5kcmF3SW1hZ2UoZWxlQ2FjaGUudGV4dHVyZS5jYW52YXMsIGVsZUNhY2hlLngsIDAsIGVsZUNhY2hlLndpZHRoLCBlbGVDYWNoZS5oZWlnaHQsIHgsIHksIHcsIGgpO1xuXG4gICAgICBpZiAob3BhY2l0eSAhPT0gMSkge1xuICAgICAgICBjb250ZXh0Lmdsb2JhbEFscGhhID0gb2xkR2xvYmFsQWxwaGE7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGV0YSAhPT0gMCkge1xuICAgICAgICBjb250ZXh0LnJvdGF0ZSgtdGhldGEpO1xuICAgICAgICBjb250ZXh0LnRyYW5zbGF0ZSgtc3gsIC1zeSk7XG5cbiAgICAgICAgaWYgKCFzbW9vdGgpIHtcbiAgICAgICAgICByLnNldEltZ1Ntb290aGluZyhjb250ZXh0LCBmYWxzZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgZWxlVHhyQ2FjaGUuZHJhd0VsZW1lbnQoY29udGV4dCwgZWxlKTsgLy8gZGlyZWN0IGRyYXcgZmFsbGJhY2tcbiAgICB9XG4gIH07XG5cbiAgdmFyIGdldFplcm9Sb3RhdGlvbiA9IGZ1bmN0aW9uIGdldFplcm9Sb3RhdGlvbigpIHtcbiAgICByZXR1cm4gMDtcbiAgfTtcblxuICB2YXIgZ2V0TGFiZWxSb3RhdGlvbiA9IGZ1bmN0aW9uIGdldExhYmVsUm90YXRpb24ociwgZWxlKSB7XG4gICAgcmV0dXJuIHIuZ2V0VGV4dEFuZ2xlKGVsZSwgbnVsbCk7XG4gIH07XG5cbiAgdmFyIGdldFNvdXJjZUxhYmVsUm90YXRpb24gPSBmdW5jdGlvbiBnZXRTb3VyY2VMYWJlbFJvdGF0aW9uKHIsIGVsZSkge1xuICAgIHJldHVybiByLmdldFRleHRBbmdsZShlbGUsICdzb3VyY2UnKTtcbiAgfTtcblxuICB2YXIgZ2V0VGFyZ2V0TGFiZWxSb3RhdGlvbiA9IGZ1bmN0aW9uIGdldFRhcmdldExhYmVsUm90YXRpb24ociwgZWxlKSB7XG4gICAgcmV0dXJuIHIuZ2V0VGV4dEFuZ2xlKGVsZSwgJ3RhcmdldCcpO1xuICB9O1xuXG4gIHZhciBnZXRPcGFjaXR5ID0gZnVuY3Rpb24gZ2V0T3BhY2l0eShyLCBlbGUpIHtcbiAgICByZXR1cm4gZWxlLmVmZmVjdGl2ZU9wYWNpdHkoKTtcbiAgfTtcblxuICB2YXIgZ2V0VGV4dE9wYWNpdHkgPSBmdW5jdGlvbiBnZXRUZXh0T3BhY2l0eShlLCBlbGUpIHtcbiAgICByZXR1cm4gZWxlLnBzdHlsZSgndGV4dC1vcGFjaXR5JykucGZWYWx1ZSAqIGVsZS5lZmZlY3RpdmVPcGFjaXR5KCk7XG4gIH07XG5cbiAgQ1JwJDkuZHJhd0NhY2hlZEVsZW1lbnQgPSBmdW5jdGlvbiAoY29udGV4dCwgZWxlLCBweFJhdGlvLCBleHRlbnQsIGx2bCwgcmVxdWVzdEhpZ2hRdWFsaXR5KSB7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBfciRkYXRhID0gci5kYXRhLFxuICAgICAgICBlbGVUeHJDYWNoZSA9IF9yJGRhdGEuZWxlVHhyQ2FjaGUsXG4gICAgICAgIGxibFR4ckNhY2hlID0gX3IkZGF0YS5sYmxUeHJDYWNoZSxcbiAgICAgICAgc2xiVHhyQ2FjaGUgPSBfciRkYXRhLnNsYlR4ckNhY2hlLFxuICAgICAgICB0bGJUeHJDYWNoZSA9IF9yJGRhdGEudGxiVHhyQ2FjaGU7XG4gICAgdmFyIGJiID0gZWxlLmJvdW5kaW5nQm94KCk7XG4gICAgdmFyIHJlYXNvbiA9IHJlcXVlc3RIaWdoUXVhbGl0eSA9PT0gdHJ1ZSA/IGVsZVR4ckNhY2hlLnJlYXNvbnMuaGlnaFF1YWxpdHkgOiBudWxsO1xuXG4gICAgaWYgKGJiLncgPT09IDAgfHwgYmIuaCA9PT0gMCB8fCAhZWxlLnZpc2libGUoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICghZXh0ZW50IHx8IGJvdW5kaW5nQm94ZXNJbnRlcnNlY3QoYmIsIGV4dGVudCkpIHtcbiAgICAgIHZhciBpc0VkZ2UgPSBlbGUuaXNFZGdlKCk7XG5cbiAgICAgIHZhciBiYWRMaW5lID0gZWxlLmVsZW1lbnQoKS5fcHJpdmF0ZS5yc2NyYXRjaC5iYWRMaW5lO1xuXG4gICAgICByLmRyYXdFbGVtZW50VW5kZXJsYXkoY29udGV4dCwgZWxlKTtcbiAgICAgIHIuZHJhd0NhY2hlZEVsZW1lbnRQb3J0aW9uKGNvbnRleHQsIGVsZSwgZWxlVHhyQ2FjaGUsIHB4UmF0aW8sIGx2bCwgcmVhc29uLCBnZXRaZXJvUm90YXRpb24sIGdldE9wYWNpdHkpO1xuXG4gICAgICBpZiAoIWlzRWRnZSB8fCAhYmFkTGluZSkge1xuICAgICAgICByLmRyYXdDYWNoZWRFbGVtZW50UG9ydGlvbihjb250ZXh0LCBlbGUsIGxibFR4ckNhY2hlLCBweFJhdGlvLCBsdmwsIHJlYXNvbiwgZ2V0TGFiZWxSb3RhdGlvbiwgZ2V0VGV4dE9wYWNpdHkpO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNFZGdlICYmICFiYWRMaW5lKSB7XG4gICAgICAgIHIuZHJhd0NhY2hlZEVsZW1lbnRQb3J0aW9uKGNvbnRleHQsIGVsZSwgc2xiVHhyQ2FjaGUsIHB4UmF0aW8sIGx2bCwgcmVhc29uLCBnZXRTb3VyY2VMYWJlbFJvdGF0aW9uLCBnZXRUZXh0T3BhY2l0eSk7XG4gICAgICAgIHIuZHJhd0NhY2hlZEVsZW1lbnRQb3J0aW9uKGNvbnRleHQsIGVsZSwgdGxiVHhyQ2FjaGUsIHB4UmF0aW8sIGx2bCwgcmVhc29uLCBnZXRUYXJnZXRMYWJlbFJvdGF0aW9uLCBnZXRUZXh0T3BhY2l0eSk7XG4gICAgICB9XG5cbiAgICAgIHIuZHJhd0VsZW1lbnRPdmVybGF5KGNvbnRleHQsIGVsZSk7XG4gICAgfVxuICB9O1xuXG4gIENScCQ5LmRyYXdFbGVtZW50cyA9IGZ1bmN0aW9uIChjb250ZXh0LCBlbGVzKSB7XG4gICAgdmFyIHIgPSB0aGlzO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBlbGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZWxlID0gZWxlc1tpXTtcbiAgICAgIHIuZHJhd0VsZW1lbnQoY29udGV4dCwgZWxlKTtcbiAgICB9XG4gIH07XG5cbiAgQ1JwJDkuZHJhd0NhY2hlZEVsZW1lbnRzID0gZnVuY3Rpb24gKGNvbnRleHQsIGVsZXMsIHB4UmF0aW8sIGV4dGVudCkge1xuICAgIHZhciByID0gdGhpcztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG4gICAgICByLmRyYXdDYWNoZWRFbGVtZW50KGNvbnRleHQsIGVsZSwgcHhSYXRpbywgZXh0ZW50KTtcbiAgICB9XG4gIH07XG5cbiAgQ1JwJDkuZHJhd0NhY2hlZE5vZGVzID0gZnVuY3Rpb24gKGNvbnRleHQsIGVsZXMsIHB4UmF0aW8sIGV4dGVudCkge1xuICAgIHZhciByID0gdGhpcztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGVsZSA9IGVsZXNbaV07XG5cbiAgICAgIGlmICghZWxlLmlzTm9kZSgpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICByLmRyYXdDYWNoZWRFbGVtZW50KGNvbnRleHQsIGVsZSwgcHhSYXRpbywgZXh0ZW50KTtcbiAgICB9XG4gIH07XG5cbiAgQ1JwJDkuZHJhd0xheWVyZWRFbGVtZW50cyA9IGZ1bmN0aW9uIChjb250ZXh0LCBlbGVzLCBweFJhdGlvLCBleHRlbnQpIHtcbiAgICB2YXIgciA9IHRoaXM7XG4gICAgdmFyIGxheWVycyA9IHIuZGF0YS5seXJUeHJDYWNoZS5nZXRMYXllcnMoZWxlcywgcHhSYXRpbyk7XG5cbiAgICBpZiAobGF5ZXJzKSB7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxheWVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgbGF5ZXIgPSBsYXllcnNbaV07XG4gICAgICAgIHZhciBiYiA9IGxheWVyLmJiO1xuXG4gICAgICAgIGlmIChiYi53ID09PSAwIHx8IGJiLmggPT09IDApIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnRleHQuZHJhd0ltYWdlKGxheWVyLmNhbnZhcywgYmIueDEsIGJiLnkxLCBiYi53LCBiYi5oKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gZmFsbCBiYWNrIG9uIHBsYWluIGNhY2hpbmcgaWYgbm8gbGF5ZXJzXG4gICAgICByLmRyYXdDYWNoZWRFbGVtZW50cyhjb250ZXh0LCBlbGVzLCBweFJhdGlvLCBleHRlbnQpO1xuICAgIH1cbiAgfTtcblxuICAvKiBnbG9iYWwgUGF0aDJEICovXG4gIHZhciBDUnAkOCA9IHt9O1xuXG4gIENScCQ4LmRyYXdFZGdlID0gZnVuY3Rpb24gKGNvbnRleHQsIGVkZ2UsIHNoaWZ0VG9PcmlnaW5XaXRoQmIpIHtcbiAgICB2YXIgZHJhd0xhYmVsID0gYXJndW1lbnRzLmxlbmd0aCA+IDMgJiYgYXJndW1lbnRzWzNdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbM10gOiB0cnVlO1xuICAgIHZhciBzaG91bGREcmF3T3ZlcmxheSA9IGFyZ3VtZW50cy5sZW5ndGggPiA0ICYmIGFyZ3VtZW50c1s0XSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzRdIDogdHJ1ZTtcbiAgICB2YXIgc2hvdWxkRHJhd09wYWNpdHkgPSBhcmd1bWVudHMubGVuZ3RoID4gNSAmJiBhcmd1bWVudHNbNV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1s1XSA6IHRydWU7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7XG5cbiAgICBpZiAoc2hvdWxkRHJhd09wYWNpdHkgJiYgIWVkZ2UudmlzaWJsZSgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfSAvLyBpZiBiZXppZXIgY3RybCBwdHMgY2FuIG5vdCBiZSBjYWxjdWxhdGVkLCB0aGVuIGRpZVxuXG5cbiAgICBpZiAocnMuYmFkTGluZSB8fCBycy5hbGxwdHMgPT0gbnVsbCB8fCBpc05hTihycy5hbGxwdHNbMF0pKSB7XG4gICAgICAvLyBpc05hTiBpbiBjYXNlIGVkZ2UgaXMgaW1wb3NzaWJsZSBhbmQgYnJvd3NlciBidWdzIChlLmcuIHNhZmFyaSlcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgYmI7XG5cbiAgICBpZiAoc2hpZnRUb09yaWdpbldpdGhCYikge1xuICAgICAgYmIgPSBzaGlmdFRvT3JpZ2luV2l0aEJiO1xuICAgICAgY29udGV4dC50cmFuc2xhdGUoLWJiLngxLCAtYmIueTEpO1xuICAgIH1cblxuICAgIHZhciBvcGFjaXR5ID0gc2hvdWxkRHJhd09wYWNpdHkgPyBlZGdlLnBzdHlsZSgnb3BhY2l0eScpLnZhbHVlIDogMTtcbiAgICB2YXIgbGluZU9wYWNpdHkgPSBzaG91bGREcmF3T3BhY2l0eSA/IGVkZ2UucHN0eWxlKCdsaW5lLW9wYWNpdHknKS52YWx1ZSA6IDE7XG4gICAgdmFyIGN1cnZlU3R5bGUgPSBlZGdlLnBzdHlsZSgnY3VydmUtc3R5bGUnKS52YWx1ZTtcbiAgICB2YXIgbGluZVN0eWxlID0gZWRnZS5wc3R5bGUoJ2xpbmUtc3R5bGUnKS52YWx1ZTtcbiAgICB2YXIgZWRnZVdpZHRoID0gZWRnZS5wc3R5bGUoJ3dpZHRoJykucGZWYWx1ZTtcbiAgICB2YXIgbGluZUNhcCA9IGVkZ2UucHN0eWxlKCdsaW5lLWNhcCcpLnZhbHVlO1xuICAgIHZhciBlZmZlY3RpdmVMaW5lT3BhY2l0eSA9IG9wYWNpdHkgKiBsaW5lT3BhY2l0eTsgLy8gc2VwYXJhdGUgYXJyb3cgb3BhY2l0eSB3b3VsZCByZXF1aXJlIGFycm93LW9wYWNpdHkgcHJvcGVydHlcblxuICAgIHZhciBlZmZlY3RpdmVBcnJvd09wYWNpdHkgPSBvcGFjaXR5ICogbGluZU9wYWNpdHk7XG5cbiAgICB2YXIgZHJhd0xpbmUgPSBmdW5jdGlvbiBkcmF3TGluZSgpIHtcbiAgICAgIHZhciBzdHJva2VPcGFjaXR5ID0gYXJndW1lbnRzLmxlbmd0aCA+IDAgJiYgYXJndW1lbnRzWzBdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMF0gOiBlZmZlY3RpdmVMaW5lT3BhY2l0eTtcblxuICAgICAgaWYgKGN1cnZlU3R5bGUgPT09ICdzdHJhaWdodC10cmlhbmdsZScpIHtcbiAgICAgICAgci5lbGVTdHJva2VTdHlsZShjb250ZXh0LCBlZGdlLCBzdHJva2VPcGFjaXR5KTtcbiAgICAgICAgci5kcmF3RWRnZVRyaWFuZ2xlUGF0aChlZGdlLCBjb250ZXh0LCBycy5hbGxwdHMpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29udGV4dC5saW5lV2lkdGggPSBlZGdlV2lkdGg7XG4gICAgICAgIGNvbnRleHQubGluZUNhcCA9IGxpbmVDYXA7XG4gICAgICAgIHIuZWxlU3Ryb2tlU3R5bGUoY29udGV4dCwgZWRnZSwgc3Ryb2tlT3BhY2l0eSk7XG4gICAgICAgIHIuZHJhd0VkZ2VQYXRoKGVkZ2UsIGNvbnRleHQsIHJzLmFsbHB0cywgbGluZVN0eWxlKTtcbiAgICAgICAgY29udGV4dC5saW5lQ2FwID0gJ2J1dHQnOyAvLyByZXNldCBmb3Igb3RoZXIgZHJhd2luZyBmdW5jdGlvbnNcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGRyYXdPdmVybGF5ID0gZnVuY3Rpb24gZHJhd092ZXJsYXkoKSB7XG4gICAgICBpZiAoIXNob3VsZERyYXdPdmVybGF5KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgci5kcmF3RWRnZU92ZXJsYXkoY29udGV4dCwgZWRnZSk7XG4gICAgfTtcblxuICAgIHZhciBkcmF3VW5kZXJsYXkgPSBmdW5jdGlvbiBkcmF3VW5kZXJsYXkoKSB7XG4gICAgICBpZiAoIXNob3VsZERyYXdPdmVybGF5KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgci5kcmF3RWRnZVVuZGVybGF5KGNvbnRleHQsIGVkZ2UpO1xuICAgIH07XG5cbiAgICB2YXIgZHJhd0Fycm93cyA9IGZ1bmN0aW9uIGRyYXdBcnJvd3MoKSB7XG4gICAgICB2YXIgYXJyb3dPcGFjaXR5ID0gYXJndW1lbnRzLmxlbmd0aCA+IDAgJiYgYXJndW1lbnRzWzBdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMF0gOiBlZmZlY3RpdmVBcnJvd09wYWNpdHk7XG4gICAgICByLmRyYXdBcnJvd2hlYWRzKGNvbnRleHQsIGVkZ2UsIGFycm93T3BhY2l0eSk7XG4gICAgfTtcblxuICAgIHZhciBkcmF3VGV4dCA9IGZ1bmN0aW9uIGRyYXdUZXh0KCkge1xuICAgICAgci5kcmF3RWxlbWVudFRleHQoY29udGV4dCwgZWRnZSwgbnVsbCwgZHJhd0xhYmVsKTtcbiAgICB9O1xuXG4gICAgY29udGV4dC5saW5lSm9pbiA9ICdyb3VuZCc7XG4gICAgdmFyIGdob3N0ID0gZWRnZS5wc3R5bGUoJ2dob3N0JykudmFsdWUgPT09ICd5ZXMnO1xuXG4gICAgaWYgKGdob3N0KSB7XG4gICAgICB2YXIgZ3ggPSBlZGdlLnBzdHlsZSgnZ2hvc3Qtb2Zmc2V0LXgnKS5wZlZhbHVlO1xuICAgICAgdmFyIGd5ID0gZWRnZS5wc3R5bGUoJ2dob3N0LW9mZnNldC15JykucGZWYWx1ZTtcbiAgICAgIHZhciBnaG9zdE9wYWNpdHkgPSBlZGdlLnBzdHlsZSgnZ2hvc3Qtb3BhY2l0eScpLnZhbHVlO1xuICAgICAgdmFyIGVmZmVjdGl2ZUdob3N0T3BhY2l0eSA9IGVmZmVjdGl2ZUxpbmVPcGFjaXR5ICogZ2hvc3RPcGFjaXR5O1xuICAgICAgY29udGV4dC50cmFuc2xhdGUoZ3gsIGd5KTtcbiAgICAgIGRyYXdMaW5lKGVmZmVjdGl2ZUdob3N0T3BhY2l0eSk7XG4gICAgICBkcmF3QXJyb3dzKGVmZmVjdGl2ZUdob3N0T3BhY2l0eSk7XG4gICAgICBjb250ZXh0LnRyYW5zbGF0ZSgtZ3gsIC1neSk7XG4gICAgfVxuXG4gICAgZHJhd1VuZGVybGF5KCk7XG4gICAgZHJhd0xpbmUoKTtcbiAgICBkcmF3QXJyb3dzKCk7XG4gICAgZHJhd092ZXJsYXkoKTtcbiAgICBkcmF3VGV4dCgpO1xuXG4gICAgaWYgKHNoaWZ0VG9PcmlnaW5XaXRoQmIpIHtcbiAgICAgIGNvbnRleHQudHJhbnNsYXRlKGJiLngxLCBiYi55MSk7XG4gICAgfVxuICB9O1xuXG4gIHZhciBkcmF3RWRnZU92ZXJsYXlVbmRlcmxheSA9IGZ1bmN0aW9uIGRyYXdFZGdlT3ZlcmxheVVuZGVybGF5KG92ZXJsYXlPclVuZGVybGF5KSB7XG4gICAgaWYgKCFbJ292ZXJsYXknLCAndW5kZXJsYXknXS5pbmNsdWRlcyhvdmVybGF5T3JVbmRlcmxheSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzdGF0ZScpO1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbiAoY29udGV4dCwgZWRnZSkge1xuICAgICAgaWYgKCFlZGdlLnZpc2libGUoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciBvcGFjaXR5ID0gZWRnZS5wc3R5bGUoXCJcIi5jb25jYXQob3ZlcmxheU9yVW5kZXJsYXksIFwiLW9wYWNpdHlcIikpLnZhbHVlO1xuXG4gICAgICBpZiAob3BhY2l0eSA9PT0gMCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciByID0gdGhpcztcbiAgICAgIHZhciB1c2VQYXRocyA9IHIudXNlUGF0aHMoKTtcbiAgICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgICB2YXIgcGFkZGluZyA9IGVkZ2UucHN0eWxlKFwiXCIuY29uY2F0KG92ZXJsYXlPclVuZGVybGF5LCBcIi1wYWRkaW5nXCIpKS5wZlZhbHVlO1xuICAgICAgdmFyIHdpZHRoID0gMiAqIHBhZGRpbmc7XG4gICAgICB2YXIgY29sb3IgPSBlZGdlLnBzdHlsZShcIlwiLmNvbmNhdChvdmVybGF5T3JVbmRlcmxheSwgXCItY29sb3JcIikpLnZhbHVlO1xuICAgICAgY29udGV4dC5saW5lV2lkdGggPSB3aWR0aDtcblxuICAgICAgaWYgKHJzLmVkZ2VUeXBlID09PSAnc2VsZicgJiYgIXVzZVBhdGhzKSB7XG4gICAgICAgIGNvbnRleHQubGluZUNhcCA9ICdidXR0JztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnRleHQubGluZUNhcCA9ICdyb3VuZCc7XG4gICAgICB9XG5cbiAgICAgIHIuY29sb3JTdHJva2VTdHlsZShjb250ZXh0LCBjb2xvclswXSwgY29sb3JbMV0sIGNvbG9yWzJdLCBvcGFjaXR5KTtcbiAgICAgIHIuZHJhd0VkZ2VQYXRoKGVkZ2UsIGNvbnRleHQsIHJzLmFsbHB0cywgJ3NvbGlkJyk7XG4gICAgfTtcbiAgfTtcblxuICBDUnAkOC5kcmF3RWRnZU92ZXJsYXkgPSBkcmF3RWRnZU92ZXJsYXlVbmRlcmxheSgnb3ZlcmxheScpO1xuICBDUnAkOC5kcmF3RWRnZVVuZGVybGF5ID0gZHJhd0VkZ2VPdmVybGF5VW5kZXJsYXkoJ3VuZGVybGF5Jyk7XG5cbiAgQ1JwJDguZHJhd0VkZ2VQYXRoID0gZnVuY3Rpb24gKGVkZ2UsIGNvbnRleHQsIHB0cywgdHlwZSkge1xuICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgdmFyIGNhbnZhc0N4dCA9IGNvbnRleHQ7XG4gICAgdmFyIHBhdGg7XG4gICAgdmFyIHBhdGhDYWNoZUhpdCA9IGZhbHNlO1xuICAgIHZhciB1c2VQYXRocyA9IHRoaXMudXNlUGF0aHMoKTtcbiAgICB2YXIgbGluZURhc2hQYXR0ZXJuID0gZWRnZS5wc3R5bGUoJ2xpbmUtZGFzaC1wYXR0ZXJuJykucGZWYWx1ZTtcbiAgICB2YXIgbGluZURhc2hPZmZzZXQgPSBlZGdlLnBzdHlsZSgnbGluZS1kYXNoLW9mZnNldCcpLnBmVmFsdWU7XG5cbiAgICBpZiAodXNlUGF0aHMpIHtcbiAgICAgIHZhciBwYXRoQ2FjaGVLZXkgPSBwdHMuam9pbignJCcpO1xuICAgICAgdmFyIGtleU1hdGNoZXMgPSBycy5wYXRoQ2FjaGVLZXkgJiYgcnMucGF0aENhY2hlS2V5ID09PSBwYXRoQ2FjaGVLZXk7XG5cbiAgICAgIGlmIChrZXlNYXRjaGVzKSB7XG4gICAgICAgIHBhdGggPSBjb250ZXh0ID0gcnMucGF0aENhY2hlO1xuICAgICAgICBwYXRoQ2FjaGVIaXQgPSB0cnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcGF0aCA9IGNvbnRleHQgPSBuZXcgUGF0aDJEKCk7XG4gICAgICAgIHJzLnBhdGhDYWNoZUtleSA9IHBhdGhDYWNoZUtleTtcbiAgICAgICAgcnMucGF0aENhY2hlID0gcGF0aDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY2FudmFzQ3h0LnNldExpbmVEYXNoKSB7XG4gICAgICAvLyBmb3IgdmVyeSBvdXRvZmRhdGUgYnJvd3NlcnNcbiAgICAgIHN3aXRjaCAodHlwZSkge1xuICAgICAgICBjYXNlICdkb3R0ZWQnOlxuICAgICAgICAgIGNhbnZhc0N4dC5zZXRMaW5lRGFzaChbMSwgMV0pO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGNhc2UgJ2Rhc2hlZCc6XG4gICAgICAgICAgY2FudmFzQ3h0LnNldExpbmVEYXNoKGxpbmVEYXNoUGF0dGVybik7XG4gICAgICAgICAgY2FudmFzQ3h0LmxpbmVEYXNoT2Zmc2V0ID0gbGluZURhc2hPZmZzZXQ7XG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgY2FzZSAnc29saWQnOlxuICAgICAgICAgIGNhbnZhc0N4dC5zZXRMaW5lRGFzaChbXSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFwYXRoQ2FjaGVIaXQgJiYgIXJzLmJhZExpbmUpIHtcbiAgICAgIGlmIChjb250ZXh0LmJlZ2luUGF0aCkge1xuICAgICAgICBjb250ZXh0LmJlZ2luUGF0aCgpO1xuICAgICAgfVxuXG4gICAgICBjb250ZXh0Lm1vdmVUbyhwdHNbMF0sIHB0c1sxXSk7XG5cbiAgICAgIHN3aXRjaCAocnMuZWRnZVR5cGUpIHtcbiAgICAgICAgY2FzZSAnYmV6aWVyJzpcbiAgICAgICAgY2FzZSAnc2VsZic6XG4gICAgICAgIGNhc2UgJ2NvbXBvdW5kJzpcbiAgICAgICAgY2FzZSAnbXVsdGliZXppZXInOlxuICAgICAgICAgIGZvciAodmFyIGkgPSAyOyBpICsgMyA8IHB0cy5sZW5ndGg7IGkgKz0gNCkge1xuICAgICAgICAgICAgY29udGV4dC5xdWFkcmF0aWNDdXJ2ZVRvKHB0c1tpXSwgcHRzW2kgKyAxXSwgcHRzW2kgKyAyXSwgcHRzW2kgKyAzXSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgY2FzZSAnc3RyYWlnaHQnOlxuICAgICAgICBjYXNlICdzZWdtZW50cyc6XG4gICAgICAgIGNhc2UgJ2hheXN0YWNrJzpcbiAgICAgICAgICBmb3IgKHZhciBfaSA9IDI7IF9pICsgMSA8IHB0cy5sZW5ndGg7IF9pICs9IDIpIHtcbiAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHB0c1tfaV0sIHB0c1tfaSArIDFdKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb250ZXh0ID0gY2FudmFzQ3h0O1xuXG4gICAgaWYgKHVzZVBhdGhzKSB7XG4gICAgICBjb250ZXh0LnN0cm9rZShwYXRoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29udGV4dC5zdHJva2UoKTtcbiAgICB9IC8vIHJlc2V0IGFueSBsaW5lIGRhc2hlc1xuXG5cbiAgICBpZiAoY29udGV4dC5zZXRMaW5lRGFzaCkge1xuICAgICAgLy8gZm9yIHZlcnkgb3V0b2ZkYXRlIGJyb3dzZXJzXG4gICAgICBjb250ZXh0LnNldExpbmVEYXNoKFtdKTtcbiAgICB9XG4gIH07XG5cbiAgQ1JwJDguZHJhd0VkZ2VUcmlhbmdsZVBhdGggPSBmdW5jdGlvbiAoZWRnZSwgY29udGV4dCwgcHRzKSB7XG4gICAgLy8gdXNlIGxpbmUgc3Ryb2tlIHN0eWxlIGZvciB0cmlhbmdsZSBmaWxsIHN0eWxlXG4gICAgY29udGV4dC5maWxsU3R5bGUgPSBjb250ZXh0LnN0cm9rZVN0eWxlO1xuICAgIHZhciBlZGdlV2lkdGggPSBlZGdlLnBzdHlsZSgnd2lkdGgnKS5wZlZhbHVlO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgKyAxIDwgcHRzLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgICB2YXIgdmVjdG9yID0gW3B0c1tpICsgMl0gLSBwdHNbaV0sIHB0c1tpICsgM10gLSBwdHNbaSArIDFdXTtcbiAgICAgIHZhciBsZW5ndGggPSBNYXRoLnNxcnQodmVjdG9yWzBdICogdmVjdG9yWzBdICsgdmVjdG9yWzFdICogdmVjdG9yWzFdKTtcbiAgICAgIHZhciBub3JtYWwgPSBbdmVjdG9yWzFdIC8gbGVuZ3RoLCAtdmVjdG9yWzBdIC8gbGVuZ3RoXTtcbiAgICAgIHZhciB0cmlhbmdsZUhlYWQgPSBbbm9ybWFsWzBdICogZWRnZVdpZHRoIC8gMiwgbm9ybWFsWzFdICogZWRnZVdpZHRoIC8gMl07XG4gICAgICBjb250ZXh0LmJlZ2luUGF0aCgpO1xuICAgICAgY29udGV4dC5tb3ZlVG8ocHRzW2ldIC0gdHJpYW5nbGVIZWFkWzBdLCBwdHNbaSArIDFdIC0gdHJpYW5nbGVIZWFkWzFdKTtcbiAgICAgIGNvbnRleHQubGluZVRvKHB0c1tpXSArIHRyaWFuZ2xlSGVhZFswXSwgcHRzW2kgKyAxXSArIHRyaWFuZ2xlSGVhZFsxXSk7XG4gICAgICBjb250ZXh0LmxpbmVUbyhwdHNbaSArIDJdLCBwdHNbaSArIDNdKTtcbiAgICAgIGNvbnRleHQuY2xvc2VQYXRoKCk7XG4gICAgICBjb250ZXh0LmZpbGwoKTtcbiAgICB9XG4gIH07XG5cbiAgQ1JwJDguZHJhd0Fycm93aGVhZHMgPSBmdW5jdGlvbiAoY29udGV4dCwgZWRnZSwgb3BhY2l0eSkge1xuICAgIHZhciBycyA9IGVkZ2UuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgdmFyIGlzSGF5c3RhY2sgPSBycy5lZGdlVHlwZSA9PT0gJ2hheXN0YWNrJztcblxuICAgIGlmICghaXNIYXlzdGFjaykge1xuICAgICAgdGhpcy5kcmF3QXJyb3doZWFkKGNvbnRleHQsIGVkZ2UsICdzb3VyY2UnLCBycy5hcnJvd1N0YXJ0WCwgcnMuYXJyb3dTdGFydFksIHJzLnNyY0Fycm93QW5nbGUsIG9wYWNpdHkpO1xuICAgIH1cblxuICAgIHRoaXMuZHJhd0Fycm93aGVhZChjb250ZXh0LCBlZGdlLCAnbWlkLXRhcmdldCcsIHJzLm1pZFgsIHJzLm1pZFksIHJzLm1pZHRndEFycm93QW5nbGUsIG9wYWNpdHkpO1xuICAgIHRoaXMuZHJhd0Fycm93aGVhZChjb250ZXh0LCBlZGdlLCAnbWlkLXNvdXJjZScsIHJzLm1pZFgsIHJzLm1pZFksIHJzLm1pZHNyY0Fycm93QW5nbGUsIG9wYWNpdHkpO1xuXG4gICAgaWYgKCFpc0hheXN0YWNrKSB7XG4gICAgICB0aGlzLmRyYXdBcnJvd2hlYWQoY29udGV4dCwgZWRnZSwgJ3RhcmdldCcsIHJzLmFycm93RW5kWCwgcnMuYXJyb3dFbmRZLCBycy50Z3RBcnJvd0FuZ2xlLCBvcGFjaXR5KTtcbiAgICB9XG4gIH07XG5cbiAgQ1JwJDguZHJhd0Fycm93aGVhZCA9IGZ1bmN0aW9uIChjb250ZXh0LCBlZGdlLCBwcmVmaXgsIHgsIHksIGFuZ2xlLCBvcGFjaXR5KSB7XG4gICAgaWYgKGlzTmFOKHgpIHx8IHggPT0gbnVsbCB8fCBpc05hTih5KSB8fCB5ID09IG51bGwgfHwgaXNOYU4oYW5nbGUpIHx8IGFuZ2xlID09IG51bGwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGFycm93U2hhcGUgPSBlZGdlLnBzdHlsZShwcmVmaXggKyAnLWFycm93LXNoYXBlJykudmFsdWU7XG5cbiAgICBpZiAoYXJyb3dTaGFwZSA9PT0gJ25vbmUnKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGFycm93Q2xlYXJGaWxsID0gZWRnZS5wc3R5bGUocHJlZml4ICsgJy1hcnJvdy1maWxsJykudmFsdWUgPT09ICdob2xsb3cnID8gJ2JvdGgnIDogJ2ZpbGxlZCc7XG4gICAgdmFyIGFycm93RmlsbCA9IGVkZ2UucHN0eWxlKHByZWZpeCArICctYXJyb3ctZmlsbCcpLnZhbHVlO1xuICAgIHZhciBlZGdlV2lkdGggPSBlZGdlLnBzdHlsZSgnd2lkdGgnKS5wZlZhbHVlO1xuICAgIHZhciBlZGdlT3BhY2l0eSA9IGVkZ2UucHN0eWxlKCdvcGFjaXR5JykudmFsdWU7XG5cbiAgICBpZiAob3BhY2l0eSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBvcGFjaXR5ID0gZWRnZU9wYWNpdHk7XG4gICAgfVxuXG4gICAgdmFyIGdjbyA9IGNvbnRleHQuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uO1xuXG4gICAgaWYgKG9wYWNpdHkgIT09IDEgfHwgYXJyb3dGaWxsID09PSAnaG9sbG93Jykge1xuICAgICAgLy8gdGhlbiBleHRyYSBjbGVhciBpcyBuZWVkZWRcbiAgICAgIGNvbnRleHQuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uID0gJ2Rlc3RpbmF0aW9uLW91dCc7XG4gICAgICBzZWxmLmNvbG9yRmlsbFN0eWxlKGNvbnRleHQsIDI1NSwgMjU1LCAyNTUsIDEpO1xuICAgICAgc2VsZi5jb2xvclN0cm9rZVN0eWxlKGNvbnRleHQsIDI1NSwgMjU1LCAyNTUsIDEpO1xuICAgICAgc2VsZi5kcmF3QXJyb3dTaGFwZShlZGdlLCBjb250ZXh0LCBhcnJvd0NsZWFyRmlsbCwgZWRnZVdpZHRoLCBhcnJvd1NoYXBlLCB4LCB5LCBhbmdsZSk7XG4gICAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9IGdjbztcbiAgICB9IC8vIG90aGVyd2lzZSwgdGhlIG9wYXF1ZSBhcnJvdyBjbGVhcnMgaXQgZm9yIGZyZWUgOilcblxuXG4gICAgdmFyIGNvbG9yID0gZWRnZS5wc3R5bGUocHJlZml4ICsgJy1hcnJvdy1jb2xvcicpLnZhbHVlO1xuICAgIHNlbGYuY29sb3JGaWxsU3R5bGUoY29udGV4dCwgY29sb3JbMF0sIGNvbG9yWzFdLCBjb2xvclsyXSwgb3BhY2l0eSk7XG4gICAgc2VsZi5jb2xvclN0cm9rZVN0eWxlKGNvbnRleHQsIGNvbG9yWzBdLCBjb2xvclsxXSwgY29sb3JbMl0sIG9wYWNpdHkpO1xuICAgIHNlbGYuZHJhd0Fycm93U2hhcGUoZWRnZSwgY29udGV4dCwgYXJyb3dGaWxsLCBlZGdlV2lkdGgsIGFycm93U2hhcGUsIHgsIHksIGFuZ2xlKTtcbiAgfTtcblxuICBDUnAkOC5kcmF3QXJyb3dTaGFwZSA9IGZ1bmN0aW9uIChlZGdlLCBjb250ZXh0LCBmaWxsLCBlZGdlV2lkdGgsIHNoYXBlLCB4LCB5LCBhbmdsZSkge1xuICAgIHZhciByID0gdGhpcztcbiAgICB2YXIgdXNlUGF0aHMgPSB0aGlzLnVzZVBhdGhzKCkgJiYgc2hhcGUgIT09ICd0cmlhbmdsZS1jcm9zcyc7XG4gICAgdmFyIHBhdGhDYWNoZUhpdCA9IGZhbHNlO1xuICAgIHZhciBwYXRoO1xuICAgIHZhciBjYW52YXNDb250ZXh0ID0gY29udGV4dDtcbiAgICB2YXIgdHJhbnNsYXRpb24gPSB7XG4gICAgICB4OiB4LFxuICAgICAgeTogeVxuICAgIH07XG4gICAgdmFyIHNjYWxlID0gZWRnZS5wc3R5bGUoJ2Fycm93LXNjYWxlJykudmFsdWU7XG4gICAgdmFyIHNpemUgPSB0aGlzLmdldEFycm93V2lkdGgoZWRnZVdpZHRoLCBzY2FsZSk7XG4gICAgdmFyIHNoYXBlSW1wbCA9IHIuYXJyb3dTaGFwZXNbc2hhcGVdO1xuXG4gICAgaWYgKHVzZVBhdGhzKSB7XG4gICAgICB2YXIgY2FjaGUgPSByLmFycm93UGF0aENhY2hlID0gci5hcnJvd1BhdGhDYWNoZSB8fCBbXTtcbiAgICAgIHZhciBrZXkgPSBoYXNoU3RyaW5nKHNoYXBlKTtcbiAgICAgIHZhciBjYWNoZWRQYXRoID0gY2FjaGVba2V5XTtcblxuICAgICAgaWYgKGNhY2hlZFBhdGggIT0gbnVsbCkge1xuICAgICAgICBwYXRoID0gY29udGV4dCA9IGNhY2hlZFBhdGg7XG4gICAgICAgIHBhdGhDYWNoZUhpdCA9IHRydWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwYXRoID0gY29udGV4dCA9IG5ldyBQYXRoMkQoKTtcbiAgICAgICAgY2FjaGVba2V5XSA9IHBhdGg7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFwYXRoQ2FjaGVIaXQpIHtcbiAgICAgIGlmIChjb250ZXh0LmJlZ2luUGF0aCkge1xuICAgICAgICBjb250ZXh0LmJlZ2luUGF0aCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAodXNlUGF0aHMpIHtcbiAgICAgICAgLy8gc3RvcmUgaW4gdGhlIHBhdGggY2FjaGUgd2l0aCB2YWx1ZXMgZWFzaWx5IG1hbmlwdWxhdGVkIGxhdGVyXG4gICAgICAgIHNoYXBlSW1wbC5kcmF3KGNvbnRleHQsIDEsIDAsIHtcbiAgICAgICAgICB4OiAwLFxuICAgICAgICAgIHk6IDBcbiAgICAgICAgfSwgMSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzaGFwZUltcGwuZHJhdyhjb250ZXh0LCBzaXplLCBhbmdsZSwgdHJhbnNsYXRpb24sIGVkZ2VXaWR0aCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChjb250ZXh0LmNsb3NlUGF0aCkge1xuICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnRleHQgPSBjYW52YXNDb250ZXh0O1xuXG4gICAgaWYgKHVzZVBhdGhzKSB7XG4gICAgICAvLyBzZXQgdHJhbnNmb3JtIHRvIGFycm93IHBvc2l0aW9uL29yaWVudGF0aW9uXG4gICAgICBjb250ZXh0LnRyYW5zbGF0ZSh4LCB5KTtcbiAgICAgIGNvbnRleHQucm90YXRlKGFuZ2xlKTtcbiAgICAgIGNvbnRleHQuc2NhbGUoc2l6ZSwgc2l6ZSk7XG4gICAgfVxuXG4gICAgaWYgKGZpbGwgPT09ICdmaWxsZWQnIHx8IGZpbGwgPT09ICdib3RoJykge1xuICAgICAgaWYgKHVzZVBhdGhzKSB7XG4gICAgICAgIGNvbnRleHQuZmlsbChwYXRoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnRleHQuZmlsbCgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChmaWxsID09PSAnaG9sbG93JyB8fCBmaWxsID09PSAnYm90aCcpIHtcbiAgICAgIGNvbnRleHQubGluZVdpZHRoID0gKHNoYXBlSW1wbC5tYXRjaEVkZ2VXaWR0aCA/IGVkZ2VXaWR0aCA6IDEpIC8gKHVzZVBhdGhzID8gc2l6ZSA6IDEpO1xuICAgICAgY29udGV4dC5saW5lSm9pbiA9ICdtaXRlcic7XG5cbiAgICAgIGlmICh1c2VQYXRocykge1xuICAgICAgICBjb250ZXh0LnN0cm9rZShwYXRoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnRleHQuc3Ryb2tlKCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHVzZVBhdGhzKSB7XG4gICAgICAvLyByZXNldCB0cmFuc2Zvcm0gYnkgYXBwbHlpbmcgaW52ZXJzZVxuICAgICAgY29udGV4dC5zY2FsZSgxIC8gc2l6ZSwgMSAvIHNpemUpO1xuICAgICAgY29udGV4dC5yb3RhdGUoLWFuZ2xlKTtcbiAgICAgIGNvbnRleHQudHJhbnNsYXRlKC14LCAteSk7XG4gICAgfVxuICB9O1xuXG4gIHZhciBDUnAkNyA9IHt9O1xuXG4gIENScCQ3LnNhZmVEcmF3SW1hZ2UgPSBmdW5jdGlvbiAoY29udGV4dCwgaW1nLCBpeCwgaXksIGl3LCBpaCwgeCwgeSwgdywgaCkge1xuICAgIC8vIGRldGVjdCBwcm9ibGVtYXRpYyBjYXNlcyBmb3Igb2xkIGJyb3dzZXJzIHdpdGggYmFkIGltYWdlcyAoY2hlYXBlciB0aGFuIHRyeS1jYXRjaClcbiAgICBpZiAoaXcgPD0gMCB8fCBpaCA8PSAwIHx8IHcgPD0gMCB8fCBoIDw9IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29udGV4dC5kcmF3SW1hZ2UoaW1nLCBpeCwgaXksIGl3LCBpaCwgeCwgeSwgdywgaCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgd2FybihlKTtcbiAgICB9XG4gIH07XG5cbiAgQ1JwJDcuZHJhd0luc2NyaWJlZEltYWdlID0gZnVuY3Rpb24gKGNvbnRleHQsIGltZywgbm9kZSwgaW5kZXgsIG5vZGVPcGFjaXR5KSB7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBwb3MgPSBub2RlLnBvc2l0aW9uKCk7XG4gICAgdmFyIG5vZGVYID0gcG9zLng7XG4gICAgdmFyIG5vZGVZID0gcG9zLnk7XG4gICAgdmFyIHN0eWxlT2JqID0gbm9kZS5jeSgpLnN0eWxlKCk7XG4gICAgdmFyIGdldEluZGV4ZWRTdHlsZSA9IHN0eWxlT2JqLmdldEluZGV4ZWRTdHlsZS5iaW5kKHN0eWxlT2JqKTtcbiAgICB2YXIgZml0ID0gZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLWZpdCcsICd2YWx1ZScsIGluZGV4KTtcbiAgICB2YXIgcmVwZWF0ID0gZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLXJlcGVhdCcsICd2YWx1ZScsIGluZGV4KTtcbiAgICB2YXIgbm9kZVcgPSBub2RlLndpZHRoKCk7XG4gICAgdmFyIG5vZGVIID0gbm9kZS5oZWlnaHQoKTtcbiAgICB2YXIgcGFkZGluZ1gyID0gbm9kZS5wYWRkaW5nKCkgKiAyO1xuICAgIHZhciBub2RlVFcgPSBub2RlVyArIChnZXRJbmRleGVkU3R5bGUobm9kZSwgJ2JhY2tncm91bmQtd2lkdGgtcmVsYXRpdmUtdG8nLCAndmFsdWUnLCBpbmRleCkgPT09ICdpbm5lcicgPyAwIDogcGFkZGluZ1gyKTtcbiAgICB2YXIgbm9kZVRIID0gbm9kZUggKyAoZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLWhlaWdodC1yZWxhdGl2ZS10bycsICd2YWx1ZScsIGluZGV4KSA9PT0gJ2lubmVyJyA/IDAgOiBwYWRkaW5nWDIpO1xuICAgIHZhciBycyA9IG5vZGUuX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgdmFyIGNsaXAgPSBnZXRJbmRleGVkU3R5bGUobm9kZSwgJ2JhY2tncm91bmQtY2xpcCcsICd2YWx1ZScsIGluZGV4KTtcbiAgICB2YXIgc2hvdWxkQ2xpcCA9IGNsaXAgPT09ICdub2RlJztcbiAgICB2YXIgaW1nT3BhY2l0eSA9IGdldEluZGV4ZWRTdHlsZShub2RlLCAnYmFja2dyb3VuZC1pbWFnZS1vcGFjaXR5JywgJ3ZhbHVlJywgaW5kZXgpICogbm9kZU9wYWNpdHk7XG4gICAgdmFyIHNtb290aCA9IGdldEluZGV4ZWRTdHlsZShub2RlLCAnYmFja2dyb3VuZC1pbWFnZS1zbW9vdGhpbmcnLCAndmFsdWUnLCBpbmRleCk7XG4gICAgdmFyIGltZ1cgPSBpbWcud2lkdGggfHwgaW1nLmNhY2hlZFc7XG4gICAgdmFyIGltZ0ggPSBpbWcuaGVpZ2h0IHx8IGltZy5jYWNoZWRIOyAvLyB3b3JrYXJvdW5kIGZvciBicm9rZW4gYnJvd3NlcnMgbGlrZSBpZVxuXG4gICAgaWYgKG51bGwgPT0gaW1nVyB8fCBudWxsID09IGltZ0gpIHtcbiAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoaW1nKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuXG4gICAgICBpbWdXID0gaW1nLmNhY2hlZFcgPSBpbWcud2lkdGggfHwgaW1nLm9mZnNldFdpZHRoO1xuICAgICAgaW1nSCA9IGltZy5jYWNoZWRIID0gaW1nLmhlaWdodCB8fCBpbWcub2Zmc2V0SGVpZ2h0O1xuICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChpbWcpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4gICAgfVxuXG4gICAgdmFyIHcgPSBpbWdXO1xuICAgIHZhciBoID0gaW1nSDtcblxuICAgIGlmIChnZXRJbmRleGVkU3R5bGUobm9kZSwgJ2JhY2tncm91bmQtd2lkdGgnLCAndmFsdWUnLCBpbmRleCkgIT09ICdhdXRvJykge1xuICAgICAgaWYgKGdldEluZGV4ZWRTdHlsZShub2RlLCAnYmFja2dyb3VuZC13aWR0aCcsICd1bml0cycsIGluZGV4KSA9PT0gJyUnKSB7XG4gICAgICAgIHcgPSBnZXRJbmRleGVkU3R5bGUobm9kZSwgJ2JhY2tncm91bmQtd2lkdGgnLCAncGZWYWx1ZScsIGluZGV4KSAqIG5vZGVUVztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHcgPSBnZXRJbmRleGVkU3R5bGUobm9kZSwgJ2JhY2tncm91bmQtd2lkdGgnLCAncGZWYWx1ZScsIGluZGV4KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLWhlaWdodCcsICd2YWx1ZScsIGluZGV4KSAhPT0gJ2F1dG8nKSB7XG4gICAgICBpZiAoZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLWhlaWdodCcsICd1bml0cycsIGluZGV4KSA9PT0gJyUnKSB7XG4gICAgICAgIGggPSBnZXRJbmRleGVkU3R5bGUobm9kZSwgJ2JhY2tncm91bmQtaGVpZ2h0JywgJ3BmVmFsdWUnLCBpbmRleCkgKiBub2RlVEg7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoID0gZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLWhlaWdodCcsICdwZlZhbHVlJywgaW5kZXgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh3ID09PSAwIHx8IGggPT09IDApIHtcbiAgICAgIHJldHVybjsgLy8gbm8gcG9pbnQgaW4gZHJhd2luZyBlbXB0eSBpbWFnZSAoYW5kIGNocm9tZSBpcyBicm9rZW4gaW4gdGhpcyBjYXNlKVxuICAgIH1cblxuICAgIGlmIChmaXQgPT09ICdjb250YWluJykge1xuICAgICAgdmFyIHNjYWxlID0gTWF0aC5taW4obm9kZVRXIC8gdywgbm9kZVRIIC8gaCk7XG4gICAgICB3ICo9IHNjYWxlO1xuICAgICAgaCAqPSBzY2FsZTtcbiAgICB9IGVsc2UgaWYgKGZpdCA9PT0gJ2NvdmVyJykge1xuICAgICAgdmFyIHNjYWxlID0gTWF0aC5tYXgobm9kZVRXIC8gdywgbm9kZVRIIC8gaCk7XG4gICAgICB3ICo9IHNjYWxlO1xuICAgICAgaCAqPSBzY2FsZTtcbiAgICB9XG5cbiAgICB2YXIgeCA9IG5vZGVYIC0gbm9kZVRXIC8gMjsgLy8gbGVmdFxuXG4gICAgdmFyIHBvc1hVbml0cyA9IGdldEluZGV4ZWRTdHlsZShub2RlLCAnYmFja2dyb3VuZC1wb3NpdGlvbi14JywgJ3VuaXRzJywgaW5kZXgpO1xuICAgIHZhciBwb3NYUGZWYWwgPSBnZXRJbmRleGVkU3R5bGUobm9kZSwgJ2JhY2tncm91bmQtcG9zaXRpb24teCcsICdwZlZhbHVlJywgaW5kZXgpO1xuXG4gICAgaWYgKHBvc1hVbml0cyA9PT0gJyUnKSB7XG4gICAgICB4ICs9IChub2RlVFcgLSB3KSAqIHBvc1hQZlZhbDtcbiAgICB9IGVsc2Uge1xuICAgICAgeCArPSBwb3NYUGZWYWw7XG4gICAgfVxuXG4gICAgdmFyIG9mZlhVbml0cyA9IGdldEluZGV4ZWRTdHlsZShub2RlLCAnYmFja2dyb3VuZC1vZmZzZXQteCcsICd1bml0cycsIGluZGV4KTtcbiAgICB2YXIgb2ZmWFBmVmFsID0gZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLW9mZnNldC14JywgJ3BmVmFsdWUnLCBpbmRleCk7XG5cbiAgICBpZiAob2ZmWFVuaXRzID09PSAnJScpIHtcbiAgICAgIHggKz0gKG5vZGVUVyAtIHcpICogb2ZmWFBmVmFsO1xuICAgIH0gZWxzZSB7XG4gICAgICB4ICs9IG9mZlhQZlZhbDtcbiAgICB9XG5cbiAgICB2YXIgeSA9IG5vZGVZIC0gbm9kZVRIIC8gMjsgLy8gdG9wXG5cbiAgICB2YXIgcG9zWVVuaXRzID0gZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLXBvc2l0aW9uLXknLCAndW5pdHMnLCBpbmRleCk7XG4gICAgdmFyIHBvc1lQZlZhbCA9IGdldEluZGV4ZWRTdHlsZShub2RlLCAnYmFja2dyb3VuZC1wb3NpdGlvbi15JywgJ3BmVmFsdWUnLCBpbmRleCk7XG5cbiAgICBpZiAocG9zWVVuaXRzID09PSAnJScpIHtcbiAgICAgIHkgKz0gKG5vZGVUSCAtIGgpICogcG9zWVBmVmFsO1xuICAgIH0gZWxzZSB7XG4gICAgICB5ICs9IHBvc1lQZlZhbDtcbiAgICB9XG5cbiAgICB2YXIgb2ZmWVVuaXRzID0gZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLW9mZnNldC15JywgJ3VuaXRzJywgaW5kZXgpO1xuICAgIHZhciBvZmZZUGZWYWwgPSBnZXRJbmRleGVkU3R5bGUobm9kZSwgJ2JhY2tncm91bmQtb2Zmc2V0LXknLCAncGZWYWx1ZScsIGluZGV4KTtcblxuICAgIGlmIChvZmZZVW5pdHMgPT09ICclJykge1xuICAgICAgeSArPSAobm9kZVRIIC0gaCkgKiBvZmZZUGZWYWw7XG4gICAgfSBlbHNlIHtcbiAgICAgIHkgKz0gb2ZmWVBmVmFsO1xuICAgIH1cblxuICAgIGlmIChycy5wYXRoQ2FjaGUpIHtcbiAgICAgIHggLT0gbm9kZVg7XG4gICAgICB5IC09IG5vZGVZO1xuICAgICAgbm9kZVggPSAwO1xuICAgICAgbm9kZVkgPSAwO1xuICAgIH1cblxuICAgIHZhciBnQWxwaGEgPSBjb250ZXh0Lmdsb2JhbEFscGhhO1xuICAgIGNvbnRleHQuZ2xvYmFsQWxwaGEgPSBpbWdPcGFjaXR5O1xuICAgIHZhciBzbW9vdGhpbmdFbmFibGVkID0gci5nZXRJbWdTbW9vdGhpbmcoY29udGV4dCk7XG4gICAgdmFyIGlzU21vb3RoaW5nU3dpdGNoZWQgPSBmYWxzZTtcblxuICAgIGlmIChzbW9vdGggPT09ICdubycgJiYgc21vb3RoaW5nRW5hYmxlZCkge1xuICAgICAgci5zZXRJbWdTbW9vdGhpbmcoY29udGV4dCwgZmFsc2UpO1xuICAgICAgaXNTbW9vdGhpbmdTd2l0Y2hlZCA9IHRydWU7XG4gICAgfSBlbHNlIGlmIChzbW9vdGggPT09ICd5ZXMnICYmICFzbW9vdGhpbmdFbmFibGVkKSB7XG4gICAgICByLnNldEltZ1Ntb290aGluZyhjb250ZXh0LCB0cnVlKTtcbiAgICAgIGlzU21vb3RoaW5nU3dpdGNoZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIGlmIChyZXBlYXQgPT09ICduby1yZXBlYXQnKSB7XG4gICAgICBpZiAoc2hvdWxkQ2xpcCkge1xuICAgICAgICBjb250ZXh0LnNhdmUoKTtcblxuICAgICAgICBpZiAocnMucGF0aENhY2hlKSB7XG4gICAgICAgICAgY29udGV4dC5jbGlwKHJzLnBhdGhDYWNoZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgci5ub2RlU2hhcGVzW3IuZ2V0Tm9kZVNoYXBlKG5vZGUpXS5kcmF3KGNvbnRleHQsIG5vZGVYLCBub2RlWSwgbm9kZVRXLCBub2RlVEgpO1xuICAgICAgICAgIGNvbnRleHQuY2xpcCgpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHIuc2FmZURyYXdJbWFnZShjb250ZXh0LCBpbWcsIDAsIDAsIGltZ1csIGltZ0gsIHgsIHksIHcsIGgpO1xuXG4gICAgICBpZiAoc2hvdWxkQ2xpcCkge1xuICAgICAgICBjb250ZXh0LnJlc3RvcmUoKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIHBhdHRlcm4gPSBjb250ZXh0LmNyZWF0ZVBhdHRlcm4oaW1nLCByZXBlYXQpO1xuICAgICAgY29udGV4dC5maWxsU3R5bGUgPSBwYXR0ZXJuO1xuICAgICAgci5ub2RlU2hhcGVzW3IuZ2V0Tm9kZVNoYXBlKG5vZGUpXS5kcmF3KGNvbnRleHQsIG5vZGVYLCBub2RlWSwgbm9kZVRXLCBub2RlVEgpO1xuICAgICAgY29udGV4dC50cmFuc2xhdGUoeCwgeSk7XG4gICAgICBjb250ZXh0LmZpbGwoKTtcbiAgICAgIGNvbnRleHQudHJhbnNsYXRlKC14LCAteSk7XG4gICAgfVxuXG4gICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGdBbHBoYTtcblxuICAgIGlmIChpc1Ntb290aGluZ1N3aXRjaGVkKSB7XG4gICAgICByLnNldEltZ1Ntb290aGluZyhjb250ZXh0LCBzbW9vdGhpbmdFbmFibGVkKTtcbiAgICB9XG4gIH07XG5cbiAgdmFyIENScCQ2ID0ge307XG5cbiAgQ1JwJDYuZWxlVGV4dEJpZ2dlclRoYW5NaW4gPSBmdW5jdGlvbiAoZWxlLCBzY2FsZSkge1xuICAgIGlmICghc2NhbGUpIHtcbiAgICAgIHZhciB6b29tID0gZWxlLmN5KCkuem9vbSgpO1xuICAgICAgdmFyIHB4UmF0aW8gPSB0aGlzLmdldFBpeGVsUmF0aW8oKTtcbiAgICAgIHZhciBsdmwgPSBNYXRoLmNlaWwobG9nMih6b29tICogcHhSYXRpbykpOyAvLyB0aGUgZWZmZWN0aXZlIHRleHR1cmUgbGV2ZWxcblxuICAgICAgc2NhbGUgPSBNYXRoLnBvdygyLCBsdmwpO1xuICAgIH1cblxuICAgIHZhciBjb21wdXRlZFNpemUgPSBlbGUucHN0eWxlKCdmb250LXNpemUnKS5wZlZhbHVlICogc2NhbGU7XG4gICAgdmFyIG1pblNpemUgPSBlbGUucHN0eWxlKCdtaW4tem9vbWVkLWZvbnQtc2l6ZScpLnBmVmFsdWU7XG5cbiAgICBpZiAoY29tcHV0ZWRTaXplIDwgbWluU2l6ZSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9O1xuXG4gIENScCQ2LmRyYXdFbGVtZW50VGV4dCA9IGZ1bmN0aW9uIChjb250ZXh0LCBlbGUsIHNoaWZ0VG9PcmlnaW5XaXRoQmIsIGZvcmNlLCBwcmVmaXgpIHtcbiAgICB2YXIgdXNlRWxlT3BhY2l0eSA9IGFyZ3VtZW50cy5sZW5ndGggPiA1ICYmIGFyZ3VtZW50c1s1XSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzVdIDogdHJ1ZTtcbiAgICB2YXIgciA9IHRoaXM7XG5cbiAgICBpZiAoZm9yY2UgPT0gbnVsbCkge1xuICAgICAgaWYgKHVzZUVsZU9wYWNpdHkgJiYgIXIuZWxlVGV4dEJpZ2dlclRoYW5NaW4oZWxlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChmb3JjZSA9PT0gZmFsc2UpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoZWxlLmlzTm9kZSgpKSB7XG4gICAgICB2YXIgbGFiZWwgPSBlbGUucHN0eWxlKCdsYWJlbCcpO1xuXG4gICAgICBpZiAoIWxhYmVsIHx8ICFsYWJlbC52YWx1ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciBqdXN0aWZpY2F0aW9uID0gci5nZXRMYWJlbEp1c3RpZmljYXRpb24oZWxlKTtcbiAgICAgIGNvbnRleHQudGV4dEFsaWduID0ganVzdGlmaWNhdGlvbjtcbiAgICAgIGNvbnRleHQudGV4dEJhc2VsaW5lID0gJ2JvdHRvbSc7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBiYWRMaW5lID0gZWxlLmVsZW1lbnQoKS5fcHJpdmF0ZS5yc2NyYXRjaC5iYWRMaW5lO1xuXG4gICAgICB2YXIgX2xhYmVsID0gZWxlLnBzdHlsZSgnbGFiZWwnKTtcblxuICAgICAgdmFyIHNyY0xhYmVsID0gZWxlLnBzdHlsZSgnc291cmNlLWxhYmVsJyk7XG4gICAgICB2YXIgdGd0TGFiZWwgPSBlbGUucHN0eWxlKCd0YXJnZXQtbGFiZWwnKTtcblxuICAgICAgaWYgKGJhZExpbmUgfHwgKCFfbGFiZWwgfHwgIV9sYWJlbC52YWx1ZSkgJiYgKCFzcmNMYWJlbCB8fCAhc3JjTGFiZWwudmFsdWUpICYmICghdGd0TGFiZWwgfHwgIXRndExhYmVsLnZhbHVlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnRleHQudGV4dEFsaWduID0gJ2NlbnRlcic7XG4gICAgICBjb250ZXh0LnRleHRCYXNlbGluZSA9ICdib3R0b20nO1xuICAgIH1cblxuICAgIHZhciBhcHBseVJvdGF0aW9uID0gIXNoaWZ0VG9PcmlnaW5XaXRoQmI7XG4gICAgdmFyIGJiO1xuXG4gICAgaWYgKHNoaWZ0VG9PcmlnaW5XaXRoQmIpIHtcbiAgICAgIGJiID0gc2hpZnRUb09yaWdpbldpdGhCYjtcbiAgICAgIGNvbnRleHQudHJhbnNsYXRlKC1iYi54MSwgLWJiLnkxKTtcbiAgICB9XG5cbiAgICBpZiAocHJlZml4ID09IG51bGwpIHtcbiAgICAgIHIuZHJhd1RleHQoY29udGV4dCwgZWxlLCBudWxsLCBhcHBseVJvdGF0aW9uLCB1c2VFbGVPcGFjaXR5KTtcblxuICAgICAgaWYgKGVsZS5pc0VkZ2UoKSkge1xuICAgICAgICByLmRyYXdUZXh0KGNvbnRleHQsIGVsZSwgJ3NvdXJjZScsIGFwcGx5Um90YXRpb24sIHVzZUVsZU9wYWNpdHkpO1xuICAgICAgICByLmRyYXdUZXh0KGNvbnRleHQsIGVsZSwgJ3RhcmdldCcsIGFwcGx5Um90YXRpb24sIHVzZUVsZU9wYWNpdHkpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICByLmRyYXdUZXh0KGNvbnRleHQsIGVsZSwgcHJlZml4LCBhcHBseVJvdGF0aW9uLCB1c2VFbGVPcGFjaXR5KTtcbiAgICB9XG5cbiAgICBpZiAoc2hpZnRUb09yaWdpbldpdGhCYikge1xuICAgICAgY29udGV4dC50cmFuc2xhdGUoYmIueDEsIGJiLnkxKTtcbiAgICB9XG4gIH07XG5cbiAgQ1JwJDYuZ2V0Rm9udENhY2hlID0gZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICB2YXIgY2FjaGU7XG4gICAgdGhpcy5mb250Q2FjaGVzID0gdGhpcy5mb250Q2FjaGVzIHx8IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmZvbnRDYWNoZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNhY2hlID0gdGhpcy5mb250Q2FjaGVzW2ldO1xuXG4gICAgICBpZiAoY2FjaGUuY29udGV4dCA9PT0gY29udGV4dCkge1xuICAgICAgICByZXR1cm4gY2FjaGU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY2FjaGUgPSB7XG4gICAgICBjb250ZXh0OiBjb250ZXh0XG4gICAgfTtcbiAgICB0aGlzLmZvbnRDYWNoZXMucHVzaChjYWNoZSk7XG4gICAgcmV0dXJuIGNhY2hlO1xuICB9OyAvLyBzZXQgdXAgY2FudmFzIGNvbnRleHQgd2l0aCBmb250XG4gIC8vIHJldHVybnMgdHJhbnNmb3JtZWQgdGV4dCBzdHJpbmdcblxuXG4gIENScCQ2LnNldHVwVGV4dFN0eWxlID0gZnVuY3Rpb24gKGNvbnRleHQsIGVsZSkge1xuICAgIHZhciB1c2VFbGVPcGFjaXR5ID0gYXJndW1lbnRzLmxlbmd0aCA+IDIgJiYgYXJndW1lbnRzWzJdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMl0gOiB0cnVlO1xuICAgIC8vIEZvbnQgc3R5bGVcbiAgICB2YXIgbGFiZWxTdHlsZSA9IGVsZS5wc3R5bGUoJ2ZvbnQtc3R5bGUnKS5zdHJWYWx1ZTtcbiAgICB2YXIgbGFiZWxTaXplID0gZWxlLnBzdHlsZSgnZm9udC1zaXplJykucGZWYWx1ZSArICdweCc7XG4gICAgdmFyIGxhYmVsRmFtaWx5ID0gZWxlLnBzdHlsZSgnZm9udC1mYW1pbHknKS5zdHJWYWx1ZTtcbiAgICB2YXIgbGFiZWxXZWlnaHQgPSBlbGUucHN0eWxlKCdmb250LXdlaWdodCcpLnN0clZhbHVlO1xuICAgIHZhciBvcGFjaXR5ID0gdXNlRWxlT3BhY2l0eSA/IGVsZS5lZmZlY3RpdmVPcGFjaXR5KCkgKiBlbGUucHN0eWxlKCd0ZXh0LW9wYWNpdHknKS52YWx1ZSA6IDE7XG4gICAgdmFyIG91dGxpbmVPcGFjaXR5ID0gZWxlLnBzdHlsZSgndGV4dC1vdXRsaW5lLW9wYWNpdHknKS52YWx1ZSAqIG9wYWNpdHk7XG4gICAgdmFyIGNvbG9yID0gZWxlLnBzdHlsZSgnY29sb3InKS52YWx1ZTtcbiAgICB2YXIgb3V0bGluZUNvbG9yID0gZWxlLnBzdHlsZSgndGV4dC1vdXRsaW5lLWNvbG9yJykudmFsdWU7XG4gICAgY29udGV4dC5mb250ID0gbGFiZWxTdHlsZSArICcgJyArIGxhYmVsV2VpZ2h0ICsgJyAnICsgbGFiZWxTaXplICsgJyAnICsgbGFiZWxGYW1pbHk7XG4gICAgY29udGV4dC5saW5lSm9pbiA9ICdyb3VuZCc7IC8vIHNvIHRleHQgb3V0bGluZXMgYXJlbid0IGphZ2dlZFxuXG4gICAgdGhpcy5jb2xvckZpbGxTdHlsZShjb250ZXh0LCBjb2xvclswXSwgY29sb3JbMV0sIGNvbG9yWzJdLCBvcGFjaXR5KTtcbiAgICB0aGlzLmNvbG9yU3Ryb2tlU3R5bGUoY29udGV4dCwgb3V0bGluZUNvbG9yWzBdLCBvdXRsaW5lQ29sb3JbMV0sIG91dGxpbmVDb2xvclsyXSwgb3V0bGluZU9wYWNpdHkpO1xuICB9OyAvLyBUT0RPIGVuc3VyZSByZS11c2VkXG5cblxuICBmdW5jdGlvbiByb3VuZFJlY3QoY3R4LCB4LCB5LCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgdmFyIHJhZGl1cyA9IGFyZ3VtZW50cy5sZW5ndGggPiA1ICYmIGFyZ3VtZW50c1s1XSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzVdIDogNTtcbiAgICBjdHguYmVnaW5QYXRoKCk7XG4gICAgY3R4Lm1vdmVUbyh4ICsgcmFkaXVzLCB5KTtcbiAgICBjdHgubGluZVRvKHggKyB3aWR0aCAtIHJhZGl1cywgeSk7XG4gICAgY3R4LnF1YWRyYXRpY0N1cnZlVG8oeCArIHdpZHRoLCB5LCB4ICsgd2lkdGgsIHkgKyByYWRpdXMpO1xuICAgIGN0eC5saW5lVG8oeCArIHdpZHRoLCB5ICsgaGVpZ2h0IC0gcmFkaXVzKTtcbiAgICBjdHgucXVhZHJhdGljQ3VydmVUbyh4ICsgd2lkdGgsIHkgKyBoZWlnaHQsIHggKyB3aWR0aCAtIHJhZGl1cywgeSArIGhlaWdodCk7XG4gICAgY3R4LmxpbmVUbyh4ICsgcmFkaXVzLCB5ICsgaGVpZ2h0KTtcbiAgICBjdHgucXVhZHJhdGljQ3VydmVUbyh4LCB5ICsgaGVpZ2h0LCB4LCB5ICsgaGVpZ2h0IC0gcmFkaXVzKTtcbiAgICBjdHgubGluZVRvKHgsIHkgKyByYWRpdXMpO1xuICAgIGN0eC5xdWFkcmF0aWNDdXJ2ZVRvKHgsIHksIHggKyByYWRpdXMsIHkpO1xuICAgIGN0eC5jbG9zZVBhdGgoKTtcbiAgICBjdHguZmlsbCgpO1xuICB9XG5cbiAgQ1JwJDYuZ2V0VGV4dEFuZ2xlID0gZnVuY3Rpb24gKGVsZSwgcHJlZml4KSB7XG4gICAgdmFyIHRoZXRhO1xuICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICB2YXIgcnNjcmF0Y2ggPSBfcC5yc2NyYXRjaDtcbiAgICB2YXIgcGRhc2ggPSBwcmVmaXggPyBwcmVmaXggKyAnLScgOiAnJztcbiAgICB2YXIgcm90YXRpb24gPSBlbGUucHN0eWxlKHBkYXNoICsgJ3RleHQtcm90YXRpb24nKTtcbiAgICB2YXIgdGV4dEFuZ2xlID0gZ2V0UHJlZml4ZWRQcm9wZXJ0eShyc2NyYXRjaCwgJ2xhYmVsQW5nbGUnLCBwcmVmaXgpO1xuXG4gICAgaWYgKHJvdGF0aW9uLnN0clZhbHVlID09PSAnYXV0b3JvdGF0ZScpIHtcbiAgICAgIHRoZXRhID0gZWxlLmlzRWRnZSgpID8gdGV4dEFuZ2xlIDogMDtcbiAgICB9IGVsc2UgaWYgKHJvdGF0aW9uLnN0clZhbHVlID09PSAnbm9uZScpIHtcbiAgICAgIHRoZXRhID0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhldGEgPSByb3RhdGlvbi5wZlZhbHVlO1xuICAgIH1cblxuICAgIHJldHVybiB0aGV0YTtcbiAgfTtcblxuICBDUnAkNi5kcmF3VGV4dCA9IGZ1bmN0aW9uIChjb250ZXh0LCBlbGUsIHByZWZpeCkge1xuICAgIHZhciBhcHBseVJvdGF0aW9uID0gYXJndW1lbnRzLmxlbmd0aCA+IDMgJiYgYXJndW1lbnRzWzNdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbM10gOiB0cnVlO1xuICAgIHZhciB1c2VFbGVPcGFjaXR5ID0gYXJndW1lbnRzLmxlbmd0aCA+IDQgJiYgYXJndW1lbnRzWzRdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbNF0gOiB0cnVlO1xuICAgIHZhciBfcCA9IGVsZS5fcHJpdmF0ZTtcbiAgICB2YXIgcnNjcmF0Y2ggPSBfcC5yc2NyYXRjaDtcbiAgICB2YXIgcGFyZW50T3BhY2l0eSA9IHVzZUVsZU9wYWNpdHkgPyBlbGUuZWZmZWN0aXZlT3BhY2l0eSgpIDogMTtcblxuICAgIGlmICh1c2VFbGVPcGFjaXR5ICYmIChwYXJlbnRPcGFjaXR5ID09PSAwIHx8IGVsZS5wc3R5bGUoJ3RleHQtb3BhY2l0eScpLnZhbHVlID09PSAwKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH0gLy8gdXNlICdtYWluJyBhcyBhbiBhbGlhcyBmb3IgdGhlIG1haW4gbGFiZWwgKGkuZS4gbnVsbCBwcmVmaXgpXG5cblxuICAgIGlmIChwcmVmaXggPT09ICdtYWluJykge1xuICAgICAgcHJlZml4ID0gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgdGV4dFggPSBnZXRQcmVmaXhlZFByb3BlcnR5KHJzY3JhdGNoLCAnbGFiZWxYJywgcHJlZml4KTtcbiAgICB2YXIgdGV4dFkgPSBnZXRQcmVmaXhlZFByb3BlcnR5KHJzY3JhdGNoLCAnbGFiZWxZJywgcHJlZml4KTtcbiAgICB2YXIgb3JnVGV4dFgsIG9yZ1RleHRZOyAvLyB1c2VkIGZvciByb3RhdGlvblxuXG4gICAgdmFyIHRleHQgPSB0aGlzLmdldExhYmVsVGV4dChlbGUsIHByZWZpeCk7XG5cbiAgICBpZiAodGV4dCAhPSBudWxsICYmIHRleHQgIT09ICcnICYmICFpc05hTih0ZXh0WCkgJiYgIWlzTmFOKHRleHRZKSkge1xuICAgICAgdGhpcy5zZXR1cFRleHRTdHlsZShjb250ZXh0LCBlbGUsIHVzZUVsZU9wYWNpdHkpO1xuICAgICAgdmFyIHBkYXNoID0gcHJlZml4ID8gcHJlZml4ICsgJy0nIDogJyc7XG4gICAgICB2YXIgdGV4dFcgPSBnZXRQcmVmaXhlZFByb3BlcnR5KHJzY3JhdGNoLCAnbGFiZWxXaWR0aCcsIHByZWZpeCk7XG4gICAgICB2YXIgdGV4dEggPSBnZXRQcmVmaXhlZFByb3BlcnR5KHJzY3JhdGNoLCAnbGFiZWxIZWlnaHQnLCBwcmVmaXgpO1xuICAgICAgdmFyIG1hcmdpblggPSBlbGUucHN0eWxlKHBkYXNoICsgJ3RleHQtbWFyZ2luLXgnKS5wZlZhbHVlO1xuICAgICAgdmFyIG1hcmdpblkgPSBlbGUucHN0eWxlKHBkYXNoICsgJ3RleHQtbWFyZ2luLXknKS5wZlZhbHVlO1xuICAgICAgdmFyIGlzRWRnZSA9IGVsZS5pc0VkZ2UoKTtcbiAgICAgIHZhciBoYWxpZ24gPSBlbGUucHN0eWxlKCd0ZXh0LWhhbGlnbicpLnZhbHVlO1xuICAgICAgdmFyIHZhbGlnbiA9IGVsZS5wc3R5bGUoJ3RleHQtdmFsaWduJykudmFsdWU7XG5cbiAgICAgIGlmIChpc0VkZ2UpIHtcbiAgICAgICAgaGFsaWduID0gJ2NlbnRlcic7XG4gICAgICAgIHZhbGlnbiA9ICdjZW50ZXInO1xuICAgICAgfVxuXG4gICAgICB0ZXh0WCArPSBtYXJnaW5YO1xuICAgICAgdGV4dFkgKz0gbWFyZ2luWTtcbiAgICAgIHZhciB0aGV0YTtcblxuICAgICAgaWYgKCFhcHBseVJvdGF0aW9uKSB7XG4gICAgICAgIHRoZXRhID0gMDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoZXRhID0gdGhpcy5nZXRUZXh0QW5nbGUoZWxlLCBwcmVmaXgpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhldGEgIT09IDApIHtcbiAgICAgICAgb3JnVGV4dFggPSB0ZXh0WDtcbiAgICAgICAgb3JnVGV4dFkgPSB0ZXh0WTtcbiAgICAgICAgY29udGV4dC50cmFuc2xhdGUob3JnVGV4dFgsIG9yZ1RleHRZKTtcbiAgICAgICAgY29udGV4dC5yb3RhdGUodGhldGEpO1xuICAgICAgICB0ZXh0WCA9IDA7XG4gICAgICAgIHRleHRZID0gMDtcbiAgICAgIH1cblxuICAgICAgc3dpdGNoICh2YWxpZ24pIHtcbiAgICAgICAgY2FzZSAndG9wJzpcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBjYXNlICdjZW50ZXInOlxuICAgICAgICAgIHRleHRZICs9IHRleHRIIC8gMjtcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBjYXNlICdib3R0b20nOlxuICAgICAgICAgIHRleHRZICs9IHRleHRIO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICB2YXIgYmFja2dyb3VuZE9wYWNpdHkgPSBlbGUucHN0eWxlKCd0ZXh0LWJhY2tncm91bmQtb3BhY2l0eScpLnZhbHVlO1xuICAgICAgdmFyIGJvcmRlck9wYWNpdHkgPSBlbGUucHN0eWxlKCd0ZXh0LWJvcmRlci1vcGFjaXR5JykudmFsdWU7XG4gICAgICB2YXIgdGV4dEJvcmRlcldpZHRoID0gZWxlLnBzdHlsZSgndGV4dC1ib3JkZXItd2lkdGgnKS5wZlZhbHVlO1xuICAgICAgdmFyIGJhY2tncm91bmRQYWRkaW5nID0gZWxlLnBzdHlsZSgndGV4dC1iYWNrZ3JvdW5kLXBhZGRpbmcnKS5wZlZhbHVlO1xuXG4gICAgICBpZiAoYmFja2dyb3VuZE9wYWNpdHkgPiAwIHx8IHRleHRCb3JkZXJXaWR0aCA+IDAgJiYgYm9yZGVyT3BhY2l0eSA+IDApIHtcbiAgICAgICAgdmFyIGJnWCA9IHRleHRYIC0gYmFja2dyb3VuZFBhZGRpbmc7XG5cbiAgICAgICAgc3dpdGNoIChoYWxpZ24pIHtcbiAgICAgICAgICBjYXNlICdsZWZ0JzpcbiAgICAgICAgICAgIGJnWCAtPSB0ZXh0VztcbiAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgY2FzZSAnY2VudGVyJzpcbiAgICAgICAgICAgIGJnWCAtPSB0ZXh0VyAvIDI7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBiZ1kgPSB0ZXh0WSAtIHRleHRIIC0gYmFja2dyb3VuZFBhZGRpbmc7XG4gICAgICAgIHZhciBiZ1cgPSB0ZXh0VyArIDIgKiBiYWNrZ3JvdW5kUGFkZGluZztcbiAgICAgICAgdmFyIGJnSCA9IHRleHRIICsgMiAqIGJhY2tncm91bmRQYWRkaW5nO1xuXG4gICAgICAgIGlmIChiYWNrZ3JvdW5kT3BhY2l0eSA+IDApIHtcbiAgICAgICAgICB2YXIgdGV4dEZpbGwgPSBjb250ZXh0LmZpbGxTdHlsZTtcbiAgICAgICAgICB2YXIgdGV4dEJhY2tncm91bmRDb2xvciA9IGVsZS5wc3R5bGUoJ3RleHQtYmFja2dyb3VuZC1jb2xvcicpLnZhbHVlO1xuICAgICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJ3JnYmEoJyArIHRleHRCYWNrZ3JvdW5kQ29sb3JbMF0gKyAnLCcgKyB0ZXh0QmFja2dyb3VuZENvbG9yWzFdICsgJywnICsgdGV4dEJhY2tncm91bmRDb2xvclsyXSArICcsJyArIGJhY2tncm91bmRPcGFjaXR5ICogcGFyZW50T3BhY2l0eSArICcpJztcbiAgICAgICAgICB2YXIgc3R5bGVTaGFwZSA9IGVsZS5wc3R5bGUoJ3RleHQtYmFja2dyb3VuZC1zaGFwZScpLnN0clZhbHVlO1xuXG4gICAgICAgICAgaWYgKHN0eWxlU2hhcGUuaW5kZXhPZigncm91bmQnKSA9PT0gMCkge1xuICAgICAgICAgICAgcm91bmRSZWN0KGNvbnRleHQsIGJnWCwgYmdZLCBiZ1csIGJnSCwgMik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnRleHQuZmlsbFJlY3QoYmdYLCBiZ1ksIGJnVywgYmdIKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9IHRleHRGaWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRleHRCb3JkZXJXaWR0aCA+IDAgJiYgYm9yZGVyT3BhY2l0eSA+IDApIHtcbiAgICAgICAgICB2YXIgdGV4dFN0cm9rZSA9IGNvbnRleHQuc3Ryb2tlU3R5bGU7XG4gICAgICAgICAgdmFyIHRleHRMaW5lV2lkdGggPSBjb250ZXh0LmxpbmVXaWR0aDtcbiAgICAgICAgICB2YXIgdGV4dEJvcmRlckNvbG9yID0gZWxlLnBzdHlsZSgndGV4dC1ib3JkZXItY29sb3InKS52YWx1ZTtcbiAgICAgICAgICB2YXIgdGV4dEJvcmRlclN0eWxlID0gZWxlLnBzdHlsZSgndGV4dC1ib3JkZXItc3R5bGUnKS52YWx1ZTtcbiAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJ3JnYmEoJyArIHRleHRCb3JkZXJDb2xvclswXSArICcsJyArIHRleHRCb3JkZXJDb2xvclsxXSArICcsJyArIHRleHRCb3JkZXJDb2xvclsyXSArICcsJyArIGJvcmRlck9wYWNpdHkgKiBwYXJlbnRPcGFjaXR5ICsgJyknO1xuICAgICAgICAgIGNvbnRleHQubGluZVdpZHRoID0gdGV4dEJvcmRlcldpZHRoO1xuXG4gICAgICAgICAgaWYgKGNvbnRleHQuc2V0TGluZURhc2gpIHtcbiAgICAgICAgICAgIC8vIGZvciB2ZXJ5IG91dG9mZGF0ZSBicm93c2Vyc1xuICAgICAgICAgICAgc3dpdGNoICh0ZXh0Qm9yZGVyU3R5bGUpIHtcbiAgICAgICAgICAgICAgY2FzZSAnZG90dGVkJzpcbiAgICAgICAgICAgICAgICBjb250ZXh0LnNldExpbmVEYXNoKFsxLCAxXSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgICAgY2FzZSAnZGFzaGVkJzpcbiAgICAgICAgICAgICAgICBjb250ZXh0LnNldExpbmVEYXNoKFs0LCAyXSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgICAgY2FzZSAnZG91YmxlJzpcbiAgICAgICAgICAgICAgICBjb250ZXh0LmxpbmVXaWR0aCA9IHRleHRCb3JkZXJXaWR0aCAvIDQ7IC8vIDUwJSByZXNlcnZlZCBmb3Igd2hpdGUgYmV0d2VlbiB0aGUgdHdvIGJvcmRlcnNcblxuICAgICAgICAgICAgICAgIGNvbnRleHQuc2V0TGluZURhc2goW10pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgIGNhc2UgJ3NvbGlkJzpcbiAgICAgICAgICAgICAgICBjb250ZXh0LnNldExpbmVEYXNoKFtdKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb250ZXh0LnN0cm9rZVJlY3QoYmdYLCBiZ1ksIGJnVywgYmdIKTtcblxuICAgICAgICAgIGlmICh0ZXh0Qm9yZGVyU3R5bGUgPT09ICdkb3VibGUnKSB7XG4gICAgICAgICAgICB2YXIgd2hpdGVXaWR0aCA9IHRleHRCb3JkZXJXaWR0aCAvIDI7XG4gICAgICAgICAgICBjb250ZXh0LnN0cm9rZVJlY3QoYmdYICsgd2hpdGVXaWR0aCwgYmdZICsgd2hpdGVXaWR0aCwgYmdXIC0gd2hpdGVXaWR0aCAqIDIsIGJnSCAtIHdoaXRlV2lkdGggKiAyKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoY29udGV4dC5zZXRMaW5lRGFzaCkge1xuICAgICAgICAgICAgLy8gZm9yIHZlcnkgb3V0b2ZkYXRlIGJyb3dzZXJzXG4gICAgICAgICAgICBjb250ZXh0LnNldExpbmVEYXNoKFtdKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb250ZXh0LmxpbmVXaWR0aCA9IHRleHRMaW5lV2lkdGg7XG4gICAgICAgICAgY29udGV4dC5zdHJva2VTdHlsZSA9IHRleHRTdHJva2U7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdmFyIGxpbmVXaWR0aCA9IDIgKiBlbGUucHN0eWxlKCd0ZXh0LW91dGxpbmUtd2lkdGgnKS5wZlZhbHVlOyAvLyAqMiBiL2MgdGhlIHN0cm9rZSBpcyBkcmF3biBjZW50cmVkIG9uIHRoZSBtaWRkbGVcblxuICAgICAgaWYgKGxpbmVXaWR0aCA+IDApIHtcbiAgICAgICAgY29udGV4dC5saW5lV2lkdGggPSBsaW5lV2lkdGg7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbGUucHN0eWxlKCd0ZXh0LXdyYXAnKS52YWx1ZSA9PT0gJ3dyYXAnKSB7XG4gICAgICAgIHZhciBsaW5lcyA9IGdldFByZWZpeGVkUHJvcGVydHkocnNjcmF0Y2gsICdsYWJlbFdyYXBDYWNoZWRMaW5lcycsIHByZWZpeCk7XG4gICAgICAgIHZhciBsaW5lSGVpZ2h0ID0gZ2V0UHJlZml4ZWRQcm9wZXJ0eShyc2NyYXRjaCwgJ2xhYmVsTGluZUhlaWdodCcsIHByZWZpeCk7XG4gICAgICAgIHZhciBoYWxmVGV4dFcgPSB0ZXh0VyAvIDI7XG4gICAgICAgIHZhciBqdXN0aWZpY2F0aW9uID0gdGhpcy5nZXRMYWJlbEp1c3RpZmljYXRpb24oZWxlKTtcblxuICAgICAgICBpZiAoanVzdGlmaWNhdGlvbiA9PT0gJ2F1dG8nKSA7IGVsc2UgaWYgKGhhbGlnbiA9PT0gJ2xlZnQnKSB7XG4gICAgICAgICAgLy8gYXV0byBqdXN0aWZpY2F0aW9uIDogcmlnaHRcbiAgICAgICAgICBpZiAoanVzdGlmaWNhdGlvbiA9PT0gJ2xlZnQnKSB7XG4gICAgICAgICAgICB0ZXh0WCArPSAtdGV4dFc7XG4gICAgICAgICAgfSBlbHNlIGlmIChqdXN0aWZpY2F0aW9uID09PSAnY2VudGVyJykge1xuICAgICAgICAgICAgdGV4dFggKz0gLWhhbGZUZXh0VztcbiAgICAgICAgICB9IC8vIGVsc2Ugc2FtZSBhcyBhdXRvXG5cbiAgICAgICAgfSBlbHNlIGlmIChoYWxpZ24gPT09ICdjZW50ZXInKSB7XG4gICAgICAgICAgLy8gYXV0byBqdXN0ZmljYXRpb24gOiBjZW50ZXJcbiAgICAgICAgICBpZiAoanVzdGlmaWNhdGlvbiA9PT0gJ2xlZnQnKSB7XG4gICAgICAgICAgICB0ZXh0WCArPSAtaGFsZlRleHRXO1xuICAgICAgICAgIH0gZWxzZSBpZiAoanVzdGlmaWNhdGlvbiA9PT0gJ3JpZ2h0Jykge1xuICAgICAgICAgICAgdGV4dFggKz0gaGFsZlRleHRXO1xuICAgICAgICAgIH0gLy8gZWxzZSBzYW1lIGFzIGF1dG9cblxuICAgICAgICB9IGVsc2UgaWYgKGhhbGlnbiA9PT0gJ3JpZ2h0Jykge1xuICAgICAgICAgIC8vIGF1dG8ganVzdGlmaWNhdGlvbiA6IGxlZnRcbiAgICAgICAgICBpZiAoanVzdGlmaWNhdGlvbiA9PT0gJ2NlbnRlcicpIHtcbiAgICAgICAgICAgIHRleHRYICs9IGhhbGZUZXh0VztcbiAgICAgICAgICB9IGVsc2UgaWYgKGp1c3RpZmljYXRpb24gPT09ICdyaWdodCcpIHtcbiAgICAgICAgICAgIHRleHRYICs9IHRleHRXO1xuICAgICAgICAgIH0gLy8gZWxzZSBzYW1lIGFzIGF1dG9cblxuICAgICAgICB9XG5cbiAgICAgICAgc3dpdGNoICh2YWxpZ24pIHtcbiAgICAgICAgICBjYXNlICd0b3AnOlxuICAgICAgICAgICAgdGV4dFkgLT0gKGxpbmVzLmxlbmd0aCAtIDEpICogbGluZUhlaWdodDtcbiAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgY2FzZSAnY2VudGVyJzpcbiAgICAgICAgICBjYXNlICdib3R0b20nOlxuICAgICAgICAgICAgdGV4dFkgLT0gKGxpbmVzLmxlbmd0aCAtIDEpICogbGluZUhlaWdodDtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yICh2YXIgbCA9IDA7IGwgPCBsaW5lcy5sZW5ndGg7IGwrKykge1xuICAgICAgICAgIGlmIChsaW5lV2lkdGggPiAwKSB7XG4gICAgICAgICAgICBjb250ZXh0LnN0cm9rZVRleHQobGluZXNbbF0sIHRleHRYLCB0ZXh0WSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29udGV4dC5maWxsVGV4dChsaW5lc1tsXSwgdGV4dFgsIHRleHRZKTtcbiAgICAgICAgICB0ZXh0WSArPSBsaW5lSGVpZ2h0O1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAobGluZVdpZHRoID4gMCkge1xuICAgICAgICAgIGNvbnRleHQuc3Ryb2tlVGV4dCh0ZXh0LCB0ZXh0WCwgdGV4dFkpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29udGV4dC5maWxsVGV4dCh0ZXh0LCB0ZXh0WCwgdGV4dFkpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhldGEgIT09IDApIHtcbiAgICAgICAgY29udGV4dC5yb3RhdGUoLXRoZXRhKTtcbiAgICAgICAgY29udGV4dC50cmFuc2xhdGUoLW9yZ1RleHRYLCAtb3JnVGV4dFkpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICAvKiBnbG9iYWwgUGF0aDJEICovXG4gIHZhciBDUnAkNSA9IHt9O1xuXG4gIENScCQ1LmRyYXdOb2RlID0gZnVuY3Rpb24gKGNvbnRleHQsIG5vZGUsIHNoaWZ0VG9PcmlnaW5XaXRoQmIpIHtcbiAgICB2YXIgZHJhd0xhYmVsID0gYXJndW1lbnRzLmxlbmd0aCA+IDMgJiYgYXJndW1lbnRzWzNdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbM10gOiB0cnVlO1xuICAgIHZhciBzaG91bGREcmF3T3ZlcmxheSA9IGFyZ3VtZW50cy5sZW5ndGggPiA0ICYmIGFyZ3VtZW50c1s0XSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzRdIDogdHJ1ZTtcbiAgICB2YXIgc2hvdWxkRHJhd09wYWNpdHkgPSBhcmd1bWVudHMubGVuZ3RoID4gNSAmJiBhcmd1bWVudHNbNV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1s1XSA6IHRydWU7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBub2RlV2lkdGgsIG5vZGVIZWlnaHQ7XG4gICAgdmFyIF9wID0gbm9kZS5fcHJpdmF0ZTtcbiAgICB2YXIgcnMgPSBfcC5yc2NyYXRjaDtcbiAgICB2YXIgcG9zID0gbm9kZS5wb3NpdGlvbigpO1xuXG4gICAgaWYgKCFudW1iZXIkMShwb3MueCkgfHwgIW51bWJlciQxKHBvcy55KSkge1xuICAgICAgcmV0dXJuOyAvLyBjYW4ndCBkcmF3IG5vZGUgd2l0aCB1bmRlZmluZWQgcG9zaXRpb25cbiAgICB9XG5cbiAgICBpZiAoc2hvdWxkRHJhd09wYWNpdHkgJiYgIW5vZGUudmlzaWJsZSgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGVsZU9wYWNpdHkgPSBzaG91bGREcmF3T3BhY2l0eSA/IG5vZGUuZWZmZWN0aXZlT3BhY2l0eSgpIDogMTtcbiAgICB2YXIgdXNlUGF0aHMgPSByLnVzZVBhdGhzKCk7XG4gICAgdmFyIHBhdGg7XG4gICAgdmFyIHBhdGhDYWNoZUhpdCA9IGZhbHNlO1xuICAgIHZhciBwYWRkaW5nID0gbm9kZS5wYWRkaW5nKCk7XG4gICAgbm9kZVdpZHRoID0gbm9kZS53aWR0aCgpICsgMiAqIHBhZGRpbmc7XG4gICAgbm9kZUhlaWdodCA9IG5vZGUuaGVpZ2h0KCkgKyAyICogcGFkZGluZzsgLy9cbiAgICAvLyBzZXR1cCBzaGlmdFxuXG4gICAgdmFyIGJiO1xuXG4gICAgaWYgKHNoaWZ0VG9PcmlnaW5XaXRoQmIpIHtcbiAgICAgIGJiID0gc2hpZnRUb09yaWdpbldpdGhCYjtcbiAgICAgIGNvbnRleHQudHJhbnNsYXRlKC1iYi54MSwgLWJiLnkxKTtcbiAgICB9IC8vXG4gICAgLy8gbG9hZCBiZyBpbWFnZVxuXG5cbiAgICB2YXIgYmdJbWdQcm9wID0gbm9kZS5wc3R5bGUoJ2JhY2tncm91bmQtaW1hZ2UnKTtcbiAgICB2YXIgdXJscyA9IGJnSW1nUHJvcC52YWx1ZTtcbiAgICB2YXIgdXJsRGVmaW5lZCA9IG5ldyBBcnJheSh1cmxzLmxlbmd0aCk7XG4gICAgdmFyIGltYWdlID0gbmV3IEFycmF5KHVybHMubGVuZ3RoKTtcbiAgICB2YXIgbnVtSW1hZ2VzID0gMDtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdXJscy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHVybCA9IHVybHNbaV07XG4gICAgICB2YXIgZGVmZCA9IHVybERlZmluZWRbaV0gPSB1cmwgIT0gbnVsbCAmJiB1cmwgIT09ICdub25lJztcblxuICAgICAgaWYgKGRlZmQpIHtcbiAgICAgICAgdmFyIGJnSW1nQ3Jvc3NPcmlnaW4gPSBub2RlLmN5KCkuc3R5bGUoKS5nZXRJbmRleGVkU3R5bGUobm9kZSwgJ2JhY2tncm91bmQtaW1hZ2UtY3Jvc3NvcmlnaW4nLCAndmFsdWUnLCBpKTtcbiAgICAgICAgbnVtSW1hZ2VzKys7IC8vIGdldCBpbWFnZSwgYW5kIGlmIG5vdCBsb2FkZWQgdGhlbiBhc2sgdG8gcmVkcmF3IHdoZW4gbGF0ZXIgbG9hZGVkXG5cbiAgICAgICAgaW1hZ2VbaV0gPSByLmdldENhY2hlZEltYWdlKHVybCwgYmdJbWdDcm9zc09yaWdpbiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIF9wLmJhY2tncm91bmRUaW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuICAgICAgICAgIG5vZGUuZW1pdEFuZE5vdGlmeSgnYmFja2dyb3VuZCcpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IC8vXG4gICAgLy8gc2V0dXAgc3R5bGVzXG5cblxuICAgIHZhciBkYXJrbmVzcyA9IG5vZGUucHN0eWxlKCdiYWNrZ3JvdW5kLWJsYWNrZW4nKS52YWx1ZTtcbiAgICB2YXIgYm9yZGVyV2lkdGggPSBub2RlLnBzdHlsZSgnYm9yZGVyLXdpZHRoJykucGZWYWx1ZTtcbiAgICB2YXIgYmdPcGFjaXR5ID0gbm9kZS5wc3R5bGUoJ2JhY2tncm91bmQtb3BhY2l0eScpLnZhbHVlICogZWxlT3BhY2l0eTtcbiAgICB2YXIgYm9yZGVyQ29sb3IgPSBub2RlLnBzdHlsZSgnYm9yZGVyLWNvbG9yJykudmFsdWU7XG4gICAgdmFyIGJvcmRlclN0eWxlID0gbm9kZS5wc3R5bGUoJ2JvcmRlci1zdHlsZScpLnZhbHVlO1xuICAgIHZhciBib3JkZXJPcGFjaXR5ID0gbm9kZS5wc3R5bGUoJ2JvcmRlci1vcGFjaXR5JykudmFsdWUgKiBlbGVPcGFjaXR5O1xuICAgIGNvbnRleHQubGluZUpvaW4gPSAnbWl0ZXInOyAvLyBzbyBib3JkZXJzIGFyZSBzcXVhcmUgd2l0aCB0aGUgbm9kZSBzaGFwZVxuXG4gICAgdmFyIHNldHVwU2hhcGVDb2xvciA9IGZ1bmN0aW9uIHNldHVwU2hhcGVDb2xvcigpIHtcbiAgICAgIHZhciBiZ09weSA9IGFyZ3VtZW50cy5sZW5ndGggPiAwICYmIGFyZ3VtZW50c1swXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzBdIDogYmdPcGFjaXR5O1xuICAgICAgci5lbGVGaWxsU3R5bGUoY29udGV4dCwgbm9kZSwgYmdPcHkpO1xuICAgIH07XG5cbiAgICB2YXIgc2V0dXBCb3JkZXJDb2xvciA9IGZ1bmN0aW9uIHNldHVwQm9yZGVyQ29sb3IoKSB7XG4gICAgICB2YXIgYmRyT3B5ID0gYXJndW1lbnRzLmxlbmd0aCA+IDAgJiYgYXJndW1lbnRzWzBdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMF0gOiBib3JkZXJPcGFjaXR5O1xuICAgICAgci5jb2xvclN0cm9rZVN0eWxlKGNvbnRleHQsIGJvcmRlckNvbG9yWzBdLCBib3JkZXJDb2xvclsxXSwgYm9yZGVyQ29sb3JbMl0sIGJkck9weSk7XG4gICAgfTsgLy9cbiAgICAvLyBzZXR1cCBzaGFwZVxuXG5cbiAgICB2YXIgc3R5bGVTaGFwZSA9IG5vZGUucHN0eWxlKCdzaGFwZScpLnN0clZhbHVlO1xuICAgIHZhciBzaGFwZVB0cyA9IG5vZGUucHN0eWxlKCdzaGFwZS1wb2x5Z29uLXBvaW50cycpLnBmVmFsdWU7XG5cbiAgICBpZiAodXNlUGF0aHMpIHtcbiAgICAgIGNvbnRleHQudHJhbnNsYXRlKHBvcy54LCBwb3MueSk7XG4gICAgICB2YXIgcGF0aENhY2hlID0gci5ub2RlUGF0aENhY2hlID0gci5ub2RlUGF0aENhY2hlIHx8IFtdO1xuICAgICAgdmFyIGtleSA9IGhhc2hTdHJpbmdzKHN0eWxlU2hhcGUgPT09ICdwb2x5Z29uJyA/IHN0eWxlU2hhcGUgKyAnLCcgKyBzaGFwZVB0cy5qb2luKCcsJykgOiBzdHlsZVNoYXBlLCAnJyArIG5vZGVIZWlnaHQsICcnICsgbm9kZVdpZHRoKTtcbiAgICAgIHZhciBjYWNoZWRQYXRoID0gcGF0aENhY2hlW2tleV07XG5cbiAgICAgIGlmIChjYWNoZWRQYXRoICE9IG51bGwpIHtcbiAgICAgICAgcGF0aCA9IGNhY2hlZFBhdGg7XG4gICAgICAgIHBhdGhDYWNoZUhpdCA9IHRydWU7XG4gICAgICAgIHJzLnBhdGhDYWNoZSA9IHBhdGg7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwYXRoID0gbmV3IFBhdGgyRCgpO1xuICAgICAgICBwYXRoQ2FjaGVba2V5XSA9IHJzLnBhdGhDYWNoZSA9IHBhdGg7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIGRyYXdTaGFwZSA9IGZ1bmN0aW9uIGRyYXdTaGFwZSgpIHtcbiAgICAgIGlmICghcGF0aENhY2hlSGl0KSB7XG4gICAgICAgIHZhciBucG9zID0gcG9zO1xuXG4gICAgICAgIGlmICh1c2VQYXRocykge1xuICAgICAgICAgIG5wb3MgPSB7XG4gICAgICAgICAgICB4OiAwLFxuICAgICAgICAgICAgeTogMFxuICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICByLm5vZGVTaGFwZXNbci5nZXROb2RlU2hhcGUobm9kZSldLmRyYXcocGF0aCB8fCBjb250ZXh0LCBucG9zLngsIG5wb3MueSwgbm9kZVdpZHRoLCBub2RlSGVpZ2h0KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHVzZVBhdGhzKSB7XG4gICAgICAgIGNvbnRleHQuZmlsbChwYXRoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnRleHQuZmlsbCgpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgZHJhd0ltYWdlcyA9IGZ1bmN0aW9uIGRyYXdJbWFnZXMoKSB7XG4gICAgICB2YXIgbm9kZU9wYWNpdHkgPSBhcmd1bWVudHMubGVuZ3RoID4gMCAmJiBhcmd1bWVudHNbMF0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1swXSA6IGVsZU9wYWNpdHk7XG4gICAgICB2YXIgaW5zaWRlID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiB0cnVlO1xuICAgICAgdmFyIHByZXZCZ2luZyA9IF9wLmJhY2tncm91bmRpbmc7XG4gICAgICB2YXIgdG90YWxDb21wbGV0ZWQgPSAwO1xuXG4gICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgaW1hZ2UubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciBiZ0NvbnRhaW5tZW50ID0gbm9kZS5jeSgpLnN0eWxlKCkuZ2V0SW5kZXhlZFN0eWxlKG5vZGUsICdiYWNrZ3JvdW5kLWltYWdlLWNvbnRhaW5tZW50JywgJ3ZhbHVlJywgX2kpO1xuXG4gICAgICAgIGlmIChpbnNpZGUgJiYgYmdDb250YWlubWVudCA9PT0gJ292ZXInIHx8ICFpbnNpZGUgJiYgYmdDb250YWlubWVudCA9PT0gJ2luc2lkZScpIHtcbiAgICAgICAgICB0b3RhbENvbXBsZXRlZCsrO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHVybERlZmluZWRbX2ldICYmIGltYWdlW19pXS5jb21wbGV0ZSAmJiAhaW1hZ2VbX2ldLmVycm9yKSB7XG4gICAgICAgICAgdG90YWxDb21wbGV0ZWQrKztcbiAgICAgICAgICByLmRyYXdJbnNjcmliZWRJbWFnZShjb250ZXh0LCBpbWFnZVtfaV0sIG5vZGUsIF9pLCBub2RlT3BhY2l0eSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgX3AuYmFja2dyb3VuZGluZyA9ICEodG90YWxDb21wbGV0ZWQgPT09IG51bUltYWdlcyk7XG5cbiAgICAgIGlmIChwcmV2QmdpbmcgIT09IF9wLmJhY2tncm91bmRpbmcpIHtcbiAgICAgICAgLy8gdXBkYXRlIHN0eWxlIGIvYyA6YmFja2dyb3VuZGluZyBzdGF0ZSBjaGFuZ2VkXG4gICAgICAgIG5vZGUudXBkYXRlU3R5bGUoZmFsc2UpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgZHJhd1BpZSA9IGZ1bmN0aW9uIGRyYXdQaWUoKSB7XG4gICAgICB2YXIgcmVkcmF3U2hhcGUgPSBhcmd1bWVudHMubGVuZ3RoID4gMCAmJiBhcmd1bWVudHNbMF0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1swXSA6IGZhbHNlO1xuICAgICAgdmFyIHBpZU9wYWNpdHkgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IGVsZU9wYWNpdHk7XG5cbiAgICAgIGlmIChyLmhhc1BpZShub2RlKSkge1xuICAgICAgICByLmRyYXdQaWUoY29udGV4dCwgbm9kZSwgcGllT3BhY2l0eSk7IC8vIHJlZHJhdy9yZXN0b3JlIHBhdGggaWYgc3RlcHMgYWZ0ZXIgcGllIG5lZWQgaXRcblxuICAgICAgICBpZiAocmVkcmF3U2hhcGUpIHtcbiAgICAgICAgICBpZiAoIXVzZVBhdGhzKSB7XG4gICAgICAgICAgICByLm5vZGVTaGFwZXNbci5nZXROb2RlU2hhcGUobm9kZSldLmRyYXcoY29udGV4dCwgcG9zLngsIHBvcy55LCBub2RlV2lkdGgsIG5vZGVIZWlnaHQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgZGFya2VuID0gZnVuY3Rpb24gZGFya2VuKCkge1xuICAgICAgdmFyIGRhcmtlbk9wYWNpdHkgPSBhcmd1bWVudHMubGVuZ3RoID4gMCAmJiBhcmd1bWVudHNbMF0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1swXSA6IGVsZU9wYWNpdHk7XG4gICAgICB2YXIgb3BhY2l0eSA9IChkYXJrbmVzcyA+IDAgPyBkYXJrbmVzcyA6IC1kYXJrbmVzcykgKiBkYXJrZW5PcGFjaXR5O1xuICAgICAgdmFyIGMgPSBkYXJrbmVzcyA+IDAgPyAwIDogMjU1O1xuXG4gICAgICBpZiAoZGFya25lc3MgIT09IDApIHtcbiAgICAgICAgci5jb2xvckZpbGxTdHlsZShjb250ZXh0LCBjLCBjLCBjLCBvcGFjaXR5KTtcblxuICAgICAgICBpZiAodXNlUGF0aHMpIHtcbiAgICAgICAgICBjb250ZXh0LmZpbGwocGF0aCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29udGV4dC5maWxsKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGRyYXdCb3JkZXIgPSBmdW5jdGlvbiBkcmF3Qm9yZGVyKCkge1xuICAgICAgaWYgKGJvcmRlcldpZHRoID4gMCkge1xuICAgICAgICBjb250ZXh0LmxpbmVXaWR0aCA9IGJvcmRlcldpZHRoO1xuICAgICAgICBjb250ZXh0LmxpbmVDYXAgPSAnYnV0dCc7XG5cbiAgICAgICAgaWYgKGNvbnRleHQuc2V0TGluZURhc2gpIHtcbiAgICAgICAgICAvLyBmb3IgdmVyeSBvdXRvZmRhdGUgYnJvd3NlcnNcbiAgICAgICAgICBzd2l0Y2ggKGJvcmRlclN0eWxlKSB7XG4gICAgICAgICAgICBjYXNlICdkb3R0ZWQnOlxuICAgICAgICAgICAgICBjb250ZXh0LnNldExpbmVEYXNoKFsxLCAxXSk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICdkYXNoZWQnOlxuICAgICAgICAgICAgICBjb250ZXh0LnNldExpbmVEYXNoKFs0LCAyXSk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICdzb2xpZCc6XG4gICAgICAgICAgICBjYXNlICdkb3VibGUnOlxuICAgICAgICAgICAgICBjb250ZXh0LnNldExpbmVEYXNoKFtdKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHVzZVBhdGhzKSB7XG4gICAgICAgICAgY29udGV4dC5zdHJva2UocGF0aCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29udGV4dC5zdHJva2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChib3JkZXJTdHlsZSA9PT0gJ2RvdWJsZScpIHtcbiAgICAgICAgICBjb250ZXh0LmxpbmVXaWR0aCA9IGJvcmRlcldpZHRoIC8gMztcbiAgICAgICAgICB2YXIgZ2NvID0gY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb247XG4gICAgICAgICAgY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSAnZGVzdGluYXRpb24tb3V0JztcblxuICAgICAgICAgIGlmICh1c2VQYXRocykge1xuICAgICAgICAgICAgY29udGV4dC5zdHJva2UocGF0aCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnRleHQuc3Ryb2tlKCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSBnY287XG4gICAgICAgIH0gLy8gcmVzZXQgaW4gY2FzZSB3ZSBjaGFuZ2VkIHRoZSBib3JkZXIgc3R5bGVcblxuXG4gICAgICAgIGlmIChjb250ZXh0LnNldExpbmVEYXNoKSB7XG4gICAgICAgICAgLy8gZm9yIHZlcnkgb3V0b2ZkYXRlIGJyb3dzZXJzXG4gICAgICAgICAgY29udGV4dC5zZXRMaW5lRGFzaChbXSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGRyYXdPdmVybGF5ID0gZnVuY3Rpb24gZHJhd092ZXJsYXkoKSB7XG4gICAgICBpZiAoc2hvdWxkRHJhd092ZXJsYXkpIHtcbiAgICAgICAgci5kcmF3Tm9kZU92ZXJsYXkoY29udGV4dCwgbm9kZSwgcG9zLCBub2RlV2lkdGgsIG5vZGVIZWlnaHQpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgZHJhd1VuZGVybGF5ID0gZnVuY3Rpb24gZHJhd1VuZGVybGF5KCkge1xuICAgICAgaWYgKHNob3VsZERyYXdPdmVybGF5KSB7XG4gICAgICAgIHIuZHJhd05vZGVVbmRlcmxheShjb250ZXh0LCBub2RlLCBwb3MsIG5vZGVXaWR0aCwgbm9kZUhlaWdodCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHZhciBkcmF3VGV4dCA9IGZ1bmN0aW9uIGRyYXdUZXh0KCkge1xuICAgICAgci5kcmF3RWxlbWVudFRleHQoY29udGV4dCwgbm9kZSwgbnVsbCwgZHJhd0xhYmVsKTtcbiAgICB9O1xuXG4gICAgdmFyIGdob3N0ID0gbm9kZS5wc3R5bGUoJ2dob3N0JykudmFsdWUgPT09ICd5ZXMnO1xuXG4gICAgaWYgKGdob3N0KSB7XG4gICAgICB2YXIgZ3ggPSBub2RlLnBzdHlsZSgnZ2hvc3Qtb2Zmc2V0LXgnKS5wZlZhbHVlO1xuICAgICAgdmFyIGd5ID0gbm9kZS5wc3R5bGUoJ2dob3N0LW9mZnNldC15JykucGZWYWx1ZTtcbiAgICAgIHZhciBnaG9zdE9wYWNpdHkgPSBub2RlLnBzdHlsZSgnZ2hvc3Qtb3BhY2l0eScpLnZhbHVlO1xuICAgICAgdmFyIGVmZkdob3N0T3BhY2l0eSA9IGdob3N0T3BhY2l0eSAqIGVsZU9wYWNpdHk7XG4gICAgICBjb250ZXh0LnRyYW5zbGF0ZShneCwgZ3kpO1xuICAgICAgc2V0dXBTaGFwZUNvbG9yKGdob3N0T3BhY2l0eSAqIGJnT3BhY2l0eSk7XG4gICAgICBkcmF3U2hhcGUoKTtcbiAgICAgIGRyYXdJbWFnZXMoZWZmR2hvc3RPcGFjaXR5LCB0cnVlKTtcbiAgICAgIHNldHVwQm9yZGVyQ29sb3IoZ2hvc3RPcGFjaXR5ICogYm9yZGVyT3BhY2l0eSk7XG4gICAgICBkcmF3Qm9yZGVyKCk7XG4gICAgICBkcmF3UGllKGRhcmtuZXNzICE9PSAwIHx8IGJvcmRlcldpZHRoICE9PSAwKTtcbiAgICAgIGRyYXdJbWFnZXMoZWZmR2hvc3RPcGFjaXR5LCBmYWxzZSk7XG4gICAgICBkYXJrZW4oZWZmR2hvc3RPcGFjaXR5KTtcbiAgICAgIGNvbnRleHQudHJhbnNsYXRlKC1neCwgLWd5KTtcbiAgICB9XG5cbiAgICBpZiAodXNlUGF0aHMpIHtcbiAgICAgIGNvbnRleHQudHJhbnNsYXRlKC1wb3MueCwgLXBvcy55KTtcbiAgICB9XG5cbiAgICBkcmF3VW5kZXJsYXkoKTtcblxuICAgIGlmICh1c2VQYXRocykge1xuICAgICAgY29udGV4dC50cmFuc2xhdGUocG9zLngsIHBvcy55KTtcbiAgICB9XG5cbiAgICBzZXR1cFNoYXBlQ29sb3IoKTtcbiAgICBkcmF3U2hhcGUoKTtcbiAgICBkcmF3SW1hZ2VzKGVsZU9wYWNpdHksIHRydWUpO1xuICAgIHNldHVwQm9yZGVyQ29sb3IoKTtcbiAgICBkcmF3Qm9yZGVyKCk7XG4gICAgZHJhd1BpZShkYXJrbmVzcyAhPT0gMCB8fCBib3JkZXJXaWR0aCAhPT0gMCk7XG4gICAgZHJhd0ltYWdlcyhlbGVPcGFjaXR5LCBmYWxzZSk7XG4gICAgZGFya2VuKCk7XG5cbiAgICBpZiAodXNlUGF0aHMpIHtcbiAgICAgIGNvbnRleHQudHJhbnNsYXRlKC1wb3MueCwgLXBvcy55KTtcbiAgICB9XG5cbiAgICBkcmF3VGV4dCgpO1xuICAgIGRyYXdPdmVybGF5KCk7IC8vXG4gICAgLy8gY2xlYW4gdXAgc2hpZnRcblxuICAgIGlmIChzaGlmdFRvT3JpZ2luV2l0aEJiKSB7XG4gICAgICBjb250ZXh0LnRyYW5zbGF0ZShiYi54MSwgYmIueTEpO1xuICAgIH1cbiAgfTtcblxuICB2YXIgZHJhd05vZGVPdmVybGF5VW5kZXJsYXkgPSBmdW5jdGlvbiBkcmF3Tm9kZU92ZXJsYXlVbmRlcmxheShvdmVybGF5T3JVbmRlcmxheSkge1xuICAgIGlmICghWydvdmVybGF5JywgJ3VuZGVybGF5J10uaW5jbHVkZXMob3ZlcmxheU9yVW5kZXJsYXkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc3RhdGUnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKGNvbnRleHQsIG5vZGUsIHBvcywgbm9kZVdpZHRoLCBub2RlSGVpZ2h0KSB7XG4gICAgICB2YXIgciA9IHRoaXM7XG5cbiAgICAgIGlmICghbm9kZS52aXNpYmxlKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgcGFkZGluZyA9IG5vZGUucHN0eWxlKFwiXCIuY29uY2F0KG92ZXJsYXlPclVuZGVybGF5LCBcIi1wYWRkaW5nXCIpKS5wZlZhbHVlO1xuICAgICAgdmFyIG9wYWNpdHkgPSBub2RlLnBzdHlsZShcIlwiLmNvbmNhdChvdmVybGF5T3JVbmRlcmxheSwgXCItb3BhY2l0eVwiKSkudmFsdWU7XG4gICAgICB2YXIgY29sb3IgPSBub2RlLnBzdHlsZShcIlwiLmNvbmNhdChvdmVybGF5T3JVbmRlcmxheSwgXCItY29sb3JcIikpLnZhbHVlO1xuICAgICAgdmFyIHNoYXBlID0gbm9kZS5wc3R5bGUoXCJcIi5jb25jYXQob3ZlcmxheU9yVW5kZXJsYXksIFwiLXNoYXBlXCIpKS52YWx1ZTtcblxuICAgICAgaWYgKG9wYWNpdHkgPiAwKSB7XG4gICAgICAgIHBvcyA9IHBvcyB8fCBub2RlLnBvc2l0aW9uKCk7XG5cbiAgICAgICAgaWYgKG5vZGVXaWR0aCA9PSBudWxsIHx8IG5vZGVIZWlnaHQgPT0gbnVsbCkge1xuICAgICAgICAgIHZhciBfcGFkZGluZyA9IG5vZGUucGFkZGluZygpO1xuXG4gICAgICAgICAgbm9kZVdpZHRoID0gbm9kZS53aWR0aCgpICsgMiAqIF9wYWRkaW5nO1xuICAgICAgICAgIG5vZGVIZWlnaHQgPSBub2RlLmhlaWdodCgpICsgMiAqIF9wYWRkaW5nO1xuICAgICAgICB9XG5cbiAgICAgICAgci5jb2xvckZpbGxTdHlsZShjb250ZXh0LCBjb2xvclswXSwgY29sb3JbMV0sIGNvbG9yWzJdLCBvcGFjaXR5KTtcbiAgICAgICAgci5ub2RlU2hhcGVzW3NoYXBlXS5kcmF3KGNvbnRleHQsIHBvcy54LCBwb3MueSwgbm9kZVdpZHRoICsgcGFkZGluZyAqIDIsIG5vZGVIZWlnaHQgKyBwYWRkaW5nICogMik7XG4gICAgICAgIGNvbnRleHQuZmlsbCgpO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgQ1JwJDUuZHJhd05vZGVPdmVybGF5ID0gZHJhd05vZGVPdmVybGF5VW5kZXJsYXkoJ292ZXJsYXknKTtcbiAgQ1JwJDUuZHJhd05vZGVVbmRlcmxheSA9IGRyYXdOb2RlT3ZlcmxheVVuZGVybGF5KCd1bmRlcmxheScpOyAvLyBkb2VzIHRoZSBub2RlIGhhdmUgYXQgbGVhc3Qgb25lIHBpZSBwaWVjZT9cblxuICBDUnAkNS5oYXNQaWUgPSBmdW5jdGlvbiAobm9kZSkge1xuICAgIG5vZGUgPSBub2RlWzBdOyAvLyBlbnN1cmUgZWxlIHJlZlxuXG4gICAgcmV0dXJuIG5vZGUuX3ByaXZhdGUuaGFzUGllO1xuICB9O1xuXG4gIENScCQ1LmRyYXdQaWUgPSBmdW5jdGlvbiAoY29udGV4dCwgbm9kZSwgbm9kZU9wYWNpdHksIHBvcykge1xuICAgIG5vZGUgPSBub2RlWzBdOyAvLyBlbnN1cmUgZWxlIHJlZlxuXG4gICAgcG9zID0gcG9zIHx8IG5vZGUucG9zaXRpb24oKTtcbiAgICB2YXIgY3lTdHlsZSA9IG5vZGUuY3koKS5zdHlsZSgpO1xuICAgIHZhciBwaWVTaXplID0gbm9kZS5wc3R5bGUoJ3BpZS1zaXplJyk7XG4gICAgdmFyIHggPSBwb3MueDtcbiAgICB2YXIgeSA9IHBvcy55O1xuICAgIHZhciBub2RlVyA9IG5vZGUud2lkdGgoKTtcbiAgICB2YXIgbm9kZUggPSBub2RlLmhlaWdodCgpO1xuICAgIHZhciByYWRpdXMgPSBNYXRoLm1pbihub2RlVywgbm9kZUgpIC8gMjsgLy8gbXVzdCBmaXQgaW4gbm9kZVxuXG4gICAgdmFyIGxhc3RQZXJjZW50ID0gMDsgLy8gd2hhdCAlIHRvIGNvbnRpbnVlIGRyYXdpbmcgcGllIHNsaWNlcyBmcm9tIG9uIFswLCAxXVxuXG4gICAgdmFyIHVzZVBhdGhzID0gdGhpcy51c2VQYXRocygpO1xuXG4gICAgaWYgKHVzZVBhdGhzKSB7XG4gICAgICB4ID0gMDtcbiAgICAgIHkgPSAwO1xuICAgIH1cblxuICAgIGlmIChwaWVTaXplLnVuaXRzID09PSAnJScpIHtcbiAgICAgIHJhZGl1cyA9IHJhZGl1cyAqIHBpZVNpemUucGZWYWx1ZTtcbiAgICB9IGVsc2UgaWYgKHBpZVNpemUucGZWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByYWRpdXMgPSBwaWVTaXplLnBmVmFsdWUgLyAyO1xuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAxOyBpIDw9IGN5U3R5bGUucGllQmFja2dyb3VuZE47IGkrKykge1xuICAgICAgLy8gMS4uTlxuICAgICAgdmFyIHNpemUgPSBub2RlLnBzdHlsZSgncGllLScgKyBpICsgJy1iYWNrZ3JvdW5kLXNpemUnKS52YWx1ZTtcbiAgICAgIHZhciBjb2xvciA9IG5vZGUucHN0eWxlKCdwaWUtJyArIGkgKyAnLWJhY2tncm91bmQtY29sb3InKS52YWx1ZTtcbiAgICAgIHZhciBvcGFjaXR5ID0gbm9kZS5wc3R5bGUoJ3BpZS0nICsgaSArICctYmFja2dyb3VuZC1vcGFjaXR5JykudmFsdWUgKiBub2RlT3BhY2l0eTtcbiAgICAgIHZhciBwZXJjZW50ID0gc2l6ZSAvIDEwMDsgLy8gbWFwIGludGVnZXIgcmFuZ2UgWzAsIDEwMF0gdG8gWzAsIDFdXG4gICAgICAvLyBwZXJjZW50IGNhbid0IHB1c2ggYmV5b25kIDFcblxuICAgICAgaWYgKHBlcmNlbnQgKyBsYXN0UGVyY2VudCA+IDEpIHtcbiAgICAgICAgcGVyY2VudCA9IDEgLSBsYXN0UGVyY2VudDtcbiAgICAgIH1cblxuICAgICAgdmFyIGFuZ2xlU3RhcnQgPSAxLjUgKiBNYXRoLlBJICsgMiAqIE1hdGguUEkgKiBsYXN0UGVyY2VudDsgLy8gc3RhcnQgYXQgMTIgbydjbG9jayBhbmQgZ28gY2xvY2t3aXNlXG5cbiAgICAgIHZhciBhbmdsZURlbHRhID0gMiAqIE1hdGguUEkgKiBwZXJjZW50O1xuICAgICAgdmFyIGFuZ2xlRW5kID0gYW5nbGVTdGFydCArIGFuZ2xlRGVsdGE7IC8vIGlnbm9yZSBpZlxuICAgICAgLy8gLSB6ZXJvIHNpemVcbiAgICAgIC8vIC0gd2UncmUgYWxyZWFkeSBiZXlvbmQgdGhlIGZ1bGwgY2lyY2xlXG4gICAgICAvLyAtIGFkZGluZyB0aGUgY3VycmVudCBzbGljZSB3b3VsZCBnbyBiZXlvbmQgdGhlIGZ1bGwgY2lyY2xlXG5cbiAgICAgIGlmIChzaXplID09PSAwIHx8IGxhc3RQZXJjZW50ID49IDEgfHwgbGFzdFBlcmNlbnQgKyBwZXJjZW50ID4gMSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29udGV4dC5iZWdpblBhdGgoKTtcbiAgICAgIGNvbnRleHQubW92ZVRvKHgsIHkpO1xuICAgICAgY29udGV4dC5hcmMoeCwgeSwgcmFkaXVzLCBhbmdsZVN0YXJ0LCBhbmdsZUVuZCk7XG4gICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICAgICAgdGhpcy5jb2xvckZpbGxTdHlsZShjb250ZXh0LCBjb2xvclswXSwgY29sb3JbMV0sIGNvbG9yWzJdLCBvcGFjaXR5KTtcbiAgICAgIGNvbnRleHQuZmlsbCgpO1xuICAgICAgbGFzdFBlcmNlbnQgKz0gcGVyY2VudDtcbiAgICB9XG4gIH07XG5cbiAgdmFyIENScCQ0ID0ge307XG4gIHZhciBtb3Rpb25CbHVyRGVsYXkgPSAxMDA7IC8vIHZhciBpc0ZpcmVmb3ggPSB0eXBlb2YgSW5zdGFsbFRyaWdnZXIgIT09ICd1bmRlZmluZWQnO1xuXG4gIENScCQ0LmdldFBpeGVsUmF0aW8gPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGNvbnRleHQgPSB0aGlzLmRhdGEuY29udGV4dHNbMF07XG5cbiAgICBpZiAodGhpcy5mb3JjZWRQaXhlbFJhdGlvICE9IG51bGwpIHtcbiAgICAgIHJldHVybiB0aGlzLmZvcmNlZFBpeGVsUmF0aW87XG4gICAgfVxuXG4gICAgdmFyIGJhY2tpbmdTdG9yZSA9IGNvbnRleHQuYmFja2luZ1N0b3JlUGl4ZWxSYXRpbyB8fCBjb250ZXh0LndlYmtpdEJhY2tpbmdTdG9yZVBpeGVsUmF0aW8gfHwgY29udGV4dC5tb3pCYWNraW5nU3RvcmVQaXhlbFJhdGlvIHx8IGNvbnRleHQubXNCYWNraW5nU3RvcmVQaXhlbFJhdGlvIHx8IGNvbnRleHQub0JhY2tpbmdTdG9yZVBpeGVsUmF0aW8gfHwgY29udGV4dC5iYWNraW5nU3RvcmVQaXhlbFJhdGlvIHx8IDE7XG4gICAgcmV0dXJuICh3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyB8fCAxKSAvIGJhY2tpbmdTdG9yZTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuICB9O1xuXG4gIENScCQ0LnBhaW50Q2FjaGUgPSBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgIHZhciBjYWNoZXMgPSB0aGlzLnBhaW50Q2FjaGVzID0gdGhpcy5wYWludENhY2hlcyB8fCBbXTtcbiAgICB2YXIgbmVlZFRvQ3JlYXRlQ2FjaGUgPSB0cnVlO1xuICAgIHZhciBjYWNoZTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2FjaGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjYWNoZSA9IGNhY2hlc1tpXTtcblxuICAgICAgaWYgKGNhY2hlLmNvbnRleHQgPT09IGNvbnRleHQpIHtcbiAgICAgICAgbmVlZFRvQ3JlYXRlQ2FjaGUgPSBmYWxzZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG5lZWRUb0NyZWF0ZUNhY2hlKSB7XG4gICAgICBjYWNoZSA9IHtcbiAgICAgICAgY29udGV4dDogY29udGV4dFxuICAgICAgfTtcbiAgICAgIGNhY2hlcy5wdXNoKGNhY2hlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY2FjaGU7XG4gIH07XG5cbiAgQ1JwJDQuY3JlYXRlR3JhZGllbnRTdHlsZUZvciA9IGZ1bmN0aW9uIChjb250ZXh0LCBzaGFwZVN0eWxlTmFtZSwgZWxlLCBmaWxsLCBvcGFjaXR5KSB7XG4gICAgdmFyIGdyYWRpZW50U3R5bGU7XG4gICAgdmFyIHVzZVBhdGhzID0gdGhpcy51c2VQYXRocygpO1xuICAgIHZhciBjb2xvcnMgPSBlbGUucHN0eWxlKHNoYXBlU3R5bGVOYW1lICsgJy1ncmFkaWVudC1zdG9wLWNvbG9ycycpLnZhbHVlLFxuICAgICAgICBwb3NpdGlvbnMgPSBlbGUucHN0eWxlKHNoYXBlU3R5bGVOYW1lICsgJy1ncmFkaWVudC1zdG9wLXBvc2l0aW9ucycpLnBmVmFsdWU7XG5cbiAgICBpZiAoZmlsbCA9PT0gJ3JhZGlhbC1ncmFkaWVudCcpIHtcbiAgICAgIGlmIChlbGUuaXNFZGdlKCkpIHtcbiAgICAgICAgdmFyIHN0YXJ0ID0gZWxlLnNvdXJjZUVuZHBvaW50KCksXG4gICAgICAgICAgICBlbmQgPSBlbGUudGFyZ2V0RW5kcG9pbnQoKSxcbiAgICAgICAgICAgIG1pZCA9IGVsZS5taWRwb2ludCgpO1xuICAgICAgICB2YXIgZDEgPSBkaXN0KHN0YXJ0LCBtaWQpO1xuICAgICAgICB2YXIgZDIgPSBkaXN0KGVuZCwgbWlkKTtcbiAgICAgICAgZ3JhZGllbnRTdHlsZSA9IGNvbnRleHQuY3JlYXRlUmFkaWFsR3JhZGllbnQobWlkLngsIG1pZC55LCAwLCBtaWQueCwgbWlkLnksIE1hdGgubWF4KGQxLCBkMikpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIHBvcyA9IHVzZVBhdGhzID8ge1xuICAgICAgICAgIHg6IDAsXG4gICAgICAgICAgeTogMFxuICAgICAgICB9IDogZWxlLnBvc2l0aW9uKCksXG4gICAgICAgICAgICB3aWR0aCA9IGVsZS5wYWRkZWRXaWR0aCgpLFxuICAgICAgICAgICAgaGVpZ2h0ID0gZWxlLnBhZGRlZEhlaWdodCgpO1xuICAgICAgICBncmFkaWVudFN0eWxlID0gY29udGV4dC5jcmVhdGVSYWRpYWxHcmFkaWVudChwb3MueCwgcG9zLnksIDAsIHBvcy54LCBwb3MueSwgTWF0aC5tYXgod2lkdGgsIGhlaWdodCkpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoZWxlLmlzRWRnZSgpKSB7XG4gICAgICAgIHZhciBfc3RhcnQgPSBlbGUuc291cmNlRW5kcG9pbnQoKSxcbiAgICAgICAgICAgIF9lbmQgPSBlbGUudGFyZ2V0RW5kcG9pbnQoKTtcblxuICAgICAgICBncmFkaWVudFN0eWxlID0gY29udGV4dC5jcmVhdGVMaW5lYXJHcmFkaWVudChfc3RhcnQueCwgX3N0YXJ0LnksIF9lbmQueCwgX2VuZC55KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBfcG9zID0gdXNlUGF0aHMgPyB7XG4gICAgICAgICAgeDogMCxcbiAgICAgICAgICB5OiAwXG4gICAgICAgIH0gOiBlbGUucG9zaXRpb24oKSxcbiAgICAgICAgICAgIF93aWR0aCA9IGVsZS5wYWRkZWRXaWR0aCgpLFxuICAgICAgICAgICAgX2hlaWdodCA9IGVsZS5wYWRkZWRIZWlnaHQoKSxcbiAgICAgICAgICAgIGhhbGZXaWR0aCA9IF93aWR0aCAvIDIsXG4gICAgICAgICAgICBoYWxmSGVpZ2h0ID0gX2hlaWdodCAvIDI7XG5cbiAgICAgICAgdmFyIGRpcmVjdGlvbiA9IGVsZS5wc3R5bGUoJ2JhY2tncm91bmQtZ3JhZGllbnQtZGlyZWN0aW9uJykudmFsdWU7XG5cbiAgICAgICAgc3dpdGNoIChkaXJlY3Rpb24pIHtcbiAgICAgICAgICBjYXNlICd0by1ib3R0b20nOlxuICAgICAgICAgICAgZ3JhZGllbnRTdHlsZSA9IGNvbnRleHQuY3JlYXRlTGluZWFyR3JhZGllbnQoX3Bvcy54LCBfcG9zLnkgLSBoYWxmSGVpZ2h0LCBfcG9zLngsIF9wb3MueSArIGhhbGZIZWlnaHQpO1xuICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICBjYXNlICd0by10b3AnOlxuICAgICAgICAgICAgZ3JhZGllbnRTdHlsZSA9IGNvbnRleHQuY3JlYXRlTGluZWFyR3JhZGllbnQoX3Bvcy54LCBfcG9zLnkgKyBoYWxmSGVpZ2h0LCBfcG9zLngsIF9wb3MueSAtIGhhbGZIZWlnaHQpO1xuICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICBjYXNlICd0by1sZWZ0JzpcbiAgICAgICAgICAgIGdyYWRpZW50U3R5bGUgPSBjb250ZXh0LmNyZWF0ZUxpbmVhckdyYWRpZW50KF9wb3MueCArIGhhbGZXaWR0aCwgX3Bvcy55LCBfcG9zLnggLSBoYWxmV2lkdGgsIF9wb3MueSk7XG4gICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgIGNhc2UgJ3RvLXJpZ2h0JzpcbiAgICAgICAgICAgIGdyYWRpZW50U3R5bGUgPSBjb250ZXh0LmNyZWF0ZUxpbmVhckdyYWRpZW50KF9wb3MueCAtIGhhbGZXaWR0aCwgX3Bvcy55LCBfcG9zLnggKyBoYWxmV2lkdGgsIF9wb3MueSk7XG4gICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgIGNhc2UgJ3RvLWJvdHRvbS1yaWdodCc6XG4gICAgICAgICAgY2FzZSAndG8tcmlnaHQtYm90dG9tJzpcbiAgICAgICAgICAgIGdyYWRpZW50U3R5bGUgPSBjb250ZXh0LmNyZWF0ZUxpbmVhckdyYWRpZW50KF9wb3MueCAtIGhhbGZXaWR0aCwgX3Bvcy55IC0gaGFsZkhlaWdodCwgX3Bvcy54ICsgaGFsZldpZHRoLCBfcG9zLnkgKyBoYWxmSGVpZ2h0KTtcbiAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgY2FzZSAndG8tdG9wLXJpZ2h0JzpcbiAgICAgICAgICBjYXNlICd0by1yaWdodC10b3AnOlxuICAgICAgICAgICAgZ3JhZGllbnRTdHlsZSA9IGNvbnRleHQuY3JlYXRlTGluZWFyR3JhZGllbnQoX3Bvcy54IC0gaGFsZldpZHRoLCBfcG9zLnkgKyBoYWxmSGVpZ2h0LCBfcG9zLnggKyBoYWxmV2lkdGgsIF9wb3MueSAtIGhhbGZIZWlnaHQpO1xuICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICBjYXNlICd0by1ib3R0b20tbGVmdCc6XG4gICAgICAgICAgY2FzZSAndG8tbGVmdC1ib3R0b20nOlxuICAgICAgICAgICAgZ3JhZGllbnRTdHlsZSA9IGNvbnRleHQuY3JlYXRlTGluZWFyR3JhZGllbnQoX3Bvcy54ICsgaGFsZldpZHRoLCBfcG9zLnkgLSBoYWxmSGVpZ2h0LCBfcG9zLnggLSBoYWxmV2lkdGgsIF9wb3MueSArIGhhbGZIZWlnaHQpO1xuICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICBjYXNlICd0by10b3AtbGVmdCc6XG4gICAgICAgICAgY2FzZSAndG8tbGVmdC10b3AnOlxuICAgICAgICAgICAgZ3JhZGllbnRTdHlsZSA9IGNvbnRleHQuY3JlYXRlTGluZWFyR3JhZGllbnQoX3Bvcy54ICsgaGFsZldpZHRoLCBfcG9zLnkgKyBoYWxmSGVpZ2h0LCBfcG9zLnggLSBoYWxmV2lkdGgsIF9wb3MueSAtIGhhbGZIZWlnaHQpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIWdyYWRpZW50U3R5bGUpIHJldHVybiBudWxsOyAvLyBpbnZhbGlkIGdyYWRpZW50IHN0eWxlXG5cbiAgICB2YXIgaGFzUG9zaXRpb25zID0gcG9zaXRpb25zLmxlbmd0aCA9PT0gY29sb3JzLmxlbmd0aDtcbiAgICB2YXIgbGVuZ3RoID0gY29sb3JzLmxlbmd0aDtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIGdyYWRpZW50U3R5bGUuYWRkQ29sb3JTdG9wKGhhc1Bvc2l0aW9ucyA/IHBvc2l0aW9uc1tpXSA6IGkgLyAobGVuZ3RoIC0gMSksICdyZ2JhKCcgKyBjb2xvcnNbaV1bMF0gKyAnLCcgKyBjb2xvcnNbaV1bMV0gKyAnLCcgKyBjb2xvcnNbaV1bMl0gKyAnLCcgKyBvcGFjaXR5ICsgJyknKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZ3JhZGllbnRTdHlsZTtcbiAgfTtcblxuICBDUnAkNC5ncmFkaWVudEZpbGxTdHlsZSA9IGZ1bmN0aW9uIChjb250ZXh0LCBlbGUsIGZpbGwsIG9wYWNpdHkpIHtcbiAgICB2YXIgZ3JhZGllbnRTdHlsZSA9IHRoaXMuY3JlYXRlR3JhZGllbnRTdHlsZUZvcihjb250ZXh0LCAnYmFja2dyb3VuZCcsIGVsZSwgZmlsbCwgb3BhY2l0eSk7XG4gICAgaWYgKCFncmFkaWVudFN0eWxlKSByZXR1cm4gbnVsbDsgLy8gZXJyb3JcblxuICAgIGNvbnRleHQuZmlsbFN0eWxlID0gZ3JhZGllbnRTdHlsZTtcbiAgfTtcblxuICBDUnAkNC5jb2xvckZpbGxTdHlsZSA9IGZ1bmN0aW9uIChjb250ZXh0LCByLCBnLCBiLCBhKSB7XG4gICAgY29udGV4dC5maWxsU3R5bGUgPSAncmdiYSgnICsgciArICcsJyArIGcgKyAnLCcgKyBiICsgJywnICsgYSArICcpJzsgLy8gdHVybiBvZmYgZm9yIG5vdywgc2VlbXMgY29udGV4dCBkb2VzIGl0cyBvd24gY2FjaGluZ1xuICAgIC8vIHZhciBjYWNoZSA9IHRoaXMucGFpbnRDYWNoZShjb250ZXh0KTtcbiAgICAvLyB2YXIgZmlsbFN0eWxlID0gJ3JnYmEoJyArIHIgKyAnLCcgKyBnICsgJywnICsgYiArICcsJyArIGEgKyAnKSc7XG4gICAgLy8gaWYoIGNhY2hlLmZpbGxTdHlsZSAhPT0gZmlsbFN0eWxlICl7XG4gICAgLy8gICBjb250ZXh0LmZpbGxTdHlsZSA9IGNhY2hlLmZpbGxTdHlsZSA9IGZpbGxTdHlsZTtcbiAgICAvLyB9XG4gIH07XG5cbiAgQ1JwJDQuZWxlRmlsbFN0eWxlID0gZnVuY3Rpb24gKGNvbnRleHQsIGVsZSwgb3BhY2l0eSkge1xuICAgIHZhciBiYWNrZ3JvdW5kRmlsbCA9IGVsZS5wc3R5bGUoJ2JhY2tncm91bmQtZmlsbCcpLnZhbHVlO1xuXG4gICAgaWYgKGJhY2tncm91bmRGaWxsID09PSAnbGluZWFyLWdyYWRpZW50JyB8fCBiYWNrZ3JvdW5kRmlsbCA9PT0gJ3JhZGlhbC1ncmFkaWVudCcpIHtcbiAgICAgIHRoaXMuZ3JhZGllbnRGaWxsU3R5bGUoY29udGV4dCwgZWxlLCBiYWNrZ3JvdW5kRmlsbCwgb3BhY2l0eSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBiYWNrZ3JvdW5kQ29sb3IgPSBlbGUucHN0eWxlKCdiYWNrZ3JvdW5kLWNvbG9yJykudmFsdWU7XG4gICAgICB0aGlzLmNvbG9yRmlsbFN0eWxlKGNvbnRleHQsIGJhY2tncm91bmRDb2xvclswXSwgYmFja2dyb3VuZENvbG9yWzFdLCBiYWNrZ3JvdW5kQ29sb3JbMl0sIG9wYWNpdHkpO1xuICAgIH1cbiAgfTtcblxuICBDUnAkNC5ncmFkaWVudFN0cm9rZVN0eWxlID0gZnVuY3Rpb24gKGNvbnRleHQsIGVsZSwgZmlsbCwgb3BhY2l0eSkge1xuICAgIHZhciBncmFkaWVudFN0eWxlID0gdGhpcy5jcmVhdGVHcmFkaWVudFN0eWxlRm9yKGNvbnRleHQsICdsaW5lJywgZWxlLCBmaWxsLCBvcGFjaXR5KTtcbiAgICBpZiAoIWdyYWRpZW50U3R5bGUpIHJldHVybiBudWxsOyAvLyBlcnJvclxuXG4gICAgY29udGV4dC5zdHJva2VTdHlsZSA9IGdyYWRpZW50U3R5bGU7XG4gIH07XG5cbiAgQ1JwJDQuY29sb3JTdHJva2VTdHlsZSA9IGZ1bmN0aW9uIChjb250ZXh0LCByLCBnLCBiLCBhKSB7XG4gICAgY29udGV4dC5zdHJva2VTdHlsZSA9ICdyZ2JhKCcgKyByICsgJywnICsgZyArICcsJyArIGIgKyAnLCcgKyBhICsgJyknOyAvLyB0dXJuIG9mZiBmb3Igbm93LCBzZWVtcyBjb250ZXh0IGRvZXMgaXRzIG93biBjYWNoaW5nXG4gICAgLy8gdmFyIGNhY2hlID0gdGhpcy5wYWludENhY2hlKGNvbnRleHQpO1xuICAgIC8vIHZhciBzdHJva2VTdHlsZSA9ICdyZ2JhKCcgKyByICsgJywnICsgZyArICcsJyArIGIgKyAnLCcgKyBhICsgJyknO1xuICAgIC8vIGlmKCBjYWNoZS5zdHJva2VTdHlsZSAhPT0gc3Ryb2tlU3R5bGUgKXtcbiAgICAvLyAgIGNvbnRleHQuc3Ryb2tlU3R5bGUgPSBjYWNoZS5zdHJva2VTdHlsZSA9IHN0cm9rZVN0eWxlO1xuICAgIC8vIH1cbiAgfTtcblxuICBDUnAkNC5lbGVTdHJva2VTdHlsZSA9IGZ1bmN0aW9uIChjb250ZXh0LCBlbGUsIG9wYWNpdHkpIHtcbiAgICB2YXIgbGluZUZpbGwgPSBlbGUucHN0eWxlKCdsaW5lLWZpbGwnKS52YWx1ZTtcblxuICAgIGlmIChsaW5lRmlsbCA9PT0gJ2xpbmVhci1ncmFkaWVudCcgfHwgbGluZUZpbGwgPT09ICdyYWRpYWwtZ3JhZGllbnQnKSB7XG4gICAgICB0aGlzLmdyYWRpZW50U3Ryb2tlU3R5bGUoY29udGV4dCwgZWxlLCBsaW5lRmlsbCwgb3BhY2l0eSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBsaW5lQ29sb3IgPSBlbGUucHN0eWxlKCdsaW5lLWNvbG9yJykudmFsdWU7XG4gICAgICB0aGlzLmNvbG9yU3Ryb2tlU3R5bGUoY29udGV4dCwgbGluZUNvbG9yWzBdLCBsaW5lQ29sb3JbMV0sIGxpbmVDb2xvclsyXSwgb3BhY2l0eSk7XG4gICAgfVxuICB9OyAvLyBSZXNpemUgY2FudmFzXG5cblxuICBDUnAkNC5tYXRjaENhbnZhc1NpemUgPSBmdW5jdGlvbiAoY29udGFpbmVyKSB7XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBkYXRhID0gci5kYXRhO1xuICAgIHZhciBiYiA9IHIuZmluZENvbnRhaW5lckNsaWVudENvb3JkcygpO1xuICAgIHZhciB3aWR0aCA9IGJiWzJdO1xuICAgIHZhciBoZWlnaHQgPSBiYlszXTtcbiAgICB2YXIgcGl4ZWxSYXRpbyA9IHIuZ2V0UGl4ZWxSYXRpbygpO1xuICAgIHZhciBtYlB4UmF0aW8gPSByLm1vdGlvbkJsdXJQeFJhdGlvO1xuXG4gICAgaWYgKGNvbnRhaW5lciA9PT0gci5kYXRhLmJ1ZmZlckNhbnZhc2VzW3IuTU9USU9OQkxVUl9CVUZGRVJfTk9ERV0gfHwgY29udGFpbmVyID09PSByLmRhdGEuYnVmZmVyQ2FudmFzZXNbci5NT1RJT05CTFVSX0JVRkZFUl9EUkFHXSkge1xuICAgICAgcGl4ZWxSYXRpbyA9IG1iUHhSYXRpbztcbiAgICB9XG5cbiAgICB2YXIgY2FudmFzV2lkdGggPSB3aWR0aCAqIHBpeGVsUmF0aW87XG4gICAgdmFyIGNhbnZhc0hlaWdodCA9IGhlaWdodCAqIHBpeGVsUmF0aW87XG4gICAgdmFyIGNhbnZhcztcblxuICAgIGlmIChjYW52YXNXaWR0aCA9PT0gci5jYW52YXNXaWR0aCAmJiBjYW52YXNIZWlnaHQgPT09IHIuY2FudmFzSGVpZ2h0KSB7XG4gICAgICByZXR1cm47IC8vIHNhdmUgY3ljbGVzIGlmIHNhbWVcbiAgICB9XG5cbiAgICByLmZvbnRDYWNoZXMgPSBudWxsOyAvLyByZXNpemluZyByZXNldHMgdGhlIHN0eWxlXG5cbiAgICB2YXIgY2FudmFzQ29udGFpbmVyID0gZGF0YS5jYW52YXNDb250YWluZXI7XG4gICAgY2FudmFzQ29udGFpbmVyLnN0eWxlLndpZHRoID0gd2lkdGggKyAncHgnO1xuICAgIGNhbnZhc0NvbnRhaW5lci5zdHlsZS5oZWlnaHQgPSBoZWlnaHQgKyAncHgnO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCByLkNBTlZBU19MQVlFUlM7IGkrKykge1xuICAgICAgY2FudmFzID0gZGF0YS5jYW52YXNlc1tpXTtcbiAgICAgIGNhbnZhcy53aWR0aCA9IGNhbnZhc1dpZHRoO1xuICAgICAgY2FudmFzLmhlaWdodCA9IGNhbnZhc0hlaWdodDtcbiAgICAgIGNhbnZhcy5zdHlsZS53aWR0aCA9IHdpZHRoICsgJ3B4JztcbiAgICAgIGNhbnZhcy5zdHlsZS5oZWlnaHQgPSBoZWlnaHQgKyAncHgnO1xuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgci5CVUZGRVJfQ09VTlQ7IGkrKykge1xuICAgICAgY2FudmFzID0gZGF0YS5idWZmZXJDYW52YXNlc1tpXTtcbiAgICAgIGNhbnZhcy53aWR0aCA9IGNhbnZhc1dpZHRoO1xuICAgICAgY2FudmFzLmhlaWdodCA9IGNhbnZhc0hlaWdodDtcbiAgICAgIGNhbnZhcy5zdHlsZS53aWR0aCA9IHdpZHRoICsgJ3B4JztcbiAgICAgIGNhbnZhcy5zdHlsZS5oZWlnaHQgPSBoZWlnaHQgKyAncHgnO1xuICAgIH1cblxuICAgIHIudGV4dHVyZU11bHQgPSAxO1xuXG4gICAgaWYgKHBpeGVsUmF0aW8gPD0gMSkge1xuICAgICAgY2FudmFzID0gZGF0YS5idWZmZXJDYW52YXNlc1tyLlRFWFRVUkVfQlVGRkVSXTtcbiAgICAgIHIudGV4dHVyZU11bHQgPSAyO1xuICAgICAgY2FudmFzLndpZHRoID0gY2FudmFzV2lkdGggKiByLnRleHR1cmVNdWx0O1xuICAgICAgY2FudmFzLmhlaWdodCA9IGNhbnZhc0hlaWdodCAqIHIudGV4dHVyZU11bHQ7XG4gICAgfVxuXG4gICAgci5jYW52YXNXaWR0aCA9IGNhbnZhc1dpZHRoO1xuICAgIHIuY2FudmFzSGVpZ2h0ID0gY2FudmFzSGVpZ2h0O1xuICB9O1xuXG4gIENScCQ0LnJlbmRlclRvID0gZnVuY3Rpb24gKGN4dCwgem9vbSwgcGFuLCBweFJhdGlvKSB7XG4gICAgdGhpcy5yZW5kZXIoe1xuICAgICAgZm9yY2VkQ29udGV4dDogY3h0LFxuICAgICAgZm9yY2VkWm9vbTogem9vbSxcbiAgICAgIGZvcmNlZFBhbjogcGFuLFxuICAgICAgZHJhd0FsbExheWVyczogdHJ1ZSxcbiAgICAgIGZvcmNlZFB4UmF0aW86IHB4UmF0aW9cbiAgICB9KTtcbiAgfTtcblxuICBDUnAkNC5yZW5kZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHN0YXRpY0VtcHR5T2JqZWN0KCk7XG4gICAgdmFyIGZvcmNlZENvbnRleHQgPSBvcHRpb25zLmZvcmNlZENvbnRleHQ7XG4gICAgdmFyIGRyYXdBbGxMYXllcnMgPSBvcHRpb25zLmRyYXdBbGxMYXllcnM7XG4gICAgdmFyIGRyYXdPbmx5Tm9kZUxheWVyID0gb3B0aW9ucy5kcmF3T25seU5vZGVMYXllcjtcbiAgICB2YXIgZm9yY2VkWm9vbSA9IG9wdGlvbnMuZm9yY2VkWm9vbTtcbiAgICB2YXIgZm9yY2VkUGFuID0gb3B0aW9ucy5mb3JjZWRQYW47XG4gICAgdmFyIHIgPSB0aGlzO1xuICAgIHZhciBwaXhlbFJhdGlvID0gb3B0aW9ucy5mb3JjZWRQeFJhdGlvID09PSB1bmRlZmluZWQgPyB0aGlzLmdldFBpeGVsUmF0aW8oKSA6IG9wdGlvbnMuZm9yY2VkUHhSYXRpbztcbiAgICB2YXIgY3kgPSByLmN5O1xuICAgIHZhciBkYXRhID0gci5kYXRhO1xuICAgIHZhciBuZWVkRHJhdyA9IGRhdGEuY2FudmFzTmVlZHNSZWRyYXc7XG4gICAgdmFyIHRleHR1cmVEcmF3ID0gci50ZXh0dXJlT25WaWV3cG9ydCAmJiAhZm9yY2VkQ29udGV4dCAmJiAoci5waW5jaGluZyB8fCByLmhvdmVyRGF0YS5kcmFnZ2luZyB8fCByLnN3aXBlUGFubmluZyB8fCByLmRhdGEud2hlZWxab29taW5nKTtcbiAgICB2YXIgbW90aW9uQmx1ciA9IG9wdGlvbnMubW90aW9uQmx1ciAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5tb3Rpb25CbHVyIDogci5tb3Rpb25CbHVyO1xuICAgIHZhciBtYlB4UmF0aW8gPSByLm1vdGlvbkJsdXJQeFJhdGlvO1xuICAgIHZhciBoYXNDb21wb3VuZE5vZGVzID0gY3kuaGFzQ29tcG91bmROb2RlcygpO1xuICAgIHZhciBpbk5vZGVEcmFnR2VzdHVyZSA9IHIuaG92ZXJEYXRhLmRyYWdnaW5nRWxlcztcbiAgICB2YXIgaW5Cb3hTZWxlY3Rpb24gPSByLmhvdmVyRGF0YS5zZWxlY3RpbmcgfHwgci50b3VjaERhdGEuc2VsZWN0aW5nID8gdHJ1ZSA6IGZhbHNlO1xuICAgIG1vdGlvbkJsdXIgPSBtb3Rpb25CbHVyICYmICFmb3JjZWRDb250ZXh0ICYmIHIubW90aW9uQmx1ckVuYWJsZWQgJiYgIWluQm94U2VsZWN0aW9uO1xuICAgIHZhciBtb3Rpb25CbHVyRmFkZUVmZmVjdCA9IG1vdGlvbkJsdXI7XG5cbiAgICBpZiAoIWZvcmNlZENvbnRleHQpIHtcbiAgICAgIGlmIChyLnByZXZQeFJhdGlvICE9PSBwaXhlbFJhdGlvKSB7XG4gICAgICAgIHIuaW52YWxpZGF0ZUNvbnRhaW5lckNsaWVudENvb3Jkc0NhY2hlKCk7XG4gICAgICAgIHIubWF0Y2hDYW52YXNTaXplKHIuY29udGFpbmVyKTtcbiAgICAgICAgci5yZWRyYXdIaW50KCdlbGVzJywgdHJ1ZSk7XG4gICAgICAgIHIucmVkcmF3SGludCgnZHJhZycsIHRydWUpO1xuICAgICAgfVxuXG4gICAgICByLnByZXZQeFJhdGlvID0gcGl4ZWxSYXRpbztcbiAgICB9XG5cbiAgICBpZiAoIWZvcmNlZENvbnRleHQgJiYgci5tb3Rpb25CbHVyVGltZW91dCkge1xuICAgICAgY2xlYXJUaW1lb3V0KHIubW90aW9uQmx1clRpbWVvdXQpO1xuICAgIH1cblxuICAgIGlmIChtb3Rpb25CbHVyKSB7XG4gICAgICBpZiAoci5tYkZyYW1lcyA9PSBudWxsKSB7XG4gICAgICAgIHIubWJGcmFtZXMgPSAwO1xuICAgICAgfVxuXG4gICAgICByLm1iRnJhbWVzKys7XG5cbiAgICAgIGlmIChyLm1iRnJhbWVzIDwgMykge1xuICAgICAgICAvLyBuZWVkIHNldmVyYWwgZnJhbWVzIGJlZm9yZSBldmVuIGhpZ2ggcXVhbGl0eSBtb3Rpb25ibHVyXG4gICAgICAgIG1vdGlvbkJsdXJGYWRlRWZmZWN0ID0gZmFsc2U7XG4gICAgICB9IC8vIGdvIHRvIGxvd2VyIHF1YWxpdHkgYmx1cnJ5IGZyYW1lcyB3aGVuIHNldmVyYWwgbS9iIGZyYW1lcyBoYXZlIGJlZW4gcmVuZGVyZWQgKGF2b2lkcyBmbGFzaGluZylcblxuXG4gICAgICBpZiAoci5tYkZyYW1lcyA+IHIubWluTWJMb3dRdWFsRnJhbWVzKSB7XG4gICAgICAgIC8vci5mdWxsUXVhbGl0eU1iID0gZmFsc2U7XG4gICAgICAgIHIubW90aW9uQmx1clB4UmF0aW8gPSByLm1iUHhSQmx1cnJ5O1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChyLmNsZWFyaW5nTW90aW9uQmx1cikge1xuICAgICAgci5tb3Rpb25CbHVyUHhSYXRpbyA9IDE7XG4gICAgfSAvLyBiL2MgZHJhd1RvQ29udGV4dCgpIG1heSBiZSBhc3luYyB3LnIudC4gcmVkcmF3KCksIGtlZXAgdHJhY2sgb2YgbGFzdCB0ZXh0dXJlIGZyYW1lXG4gICAgLy8gYmVjYXVzZSBhIHJvZ3VlIGFzeW5jIHRleHR1cmUgZnJhbWUgd291bGQgY2xlYXIgbmVlZERyYXdcblxuXG4gICAgaWYgKHIudGV4dHVyZURyYXdMYXN0RnJhbWUgJiYgIXRleHR1cmVEcmF3KSB7XG4gICAgICBuZWVkRHJhd1tyLk5PREVdID0gdHJ1ZTtcbiAgICAgIG5lZWREcmF3W3IuU0VMRUNUX0JPWF0gPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciBzdHlsZSA9IGN5LnN0eWxlKCk7XG4gICAgdmFyIHpvb20gPSBjeS56b29tKCk7XG4gICAgdmFyIGVmZmVjdGl2ZVpvb20gPSBmb3JjZWRab29tICE9PSB1bmRlZmluZWQgPyBmb3JjZWRab29tIDogem9vbTtcbiAgICB2YXIgcGFuID0gY3kucGFuKCk7XG4gICAgdmFyIGVmZmVjdGl2ZVBhbiA9IHtcbiAgICAgIHg6IHBhbi54LFxuICAgICAgeTogcGFuLnlcbiAgICB9O1xuICAgIHZhciB2cCA9IHtcbiAgICAgIHpvb206IHpvb20sXG4gICAgICBwYW46IHtcbiAgICAgICAgeDogcGFuLngsXG4gICAgICAgIHk6IHBhbi55XG4gICAgICB9XG4gICAgfTtcbiAgICB2YXIgcHJldlZwID0gci5wcmV2Vmlld3BvcnQ7XG4gICAgdmFyIHZpZXdwb3J0SXNEaWZmID0gcHJldlZwID09PSB1bmRlZmluZWQgfHwgdnAuem9vbSAhPT0gcHJldlZwLnpvb20gfHwgdnAucGFuLnggIT09IHByZXZWcC5wYW4ueCB8fCB2cC5wYW4ueSAhPT0gcHJldlZwLnBhbi55OyAvLyB3ZSB3YW50IHRoZSBsb3cgcXVhbGl0eSBtb3Rpb25ibHVyIG9ubHkgd2hlbiB0aGUgdmlld3BvcnQgaXMgYmVpbmcgbWFuaXB1bGF0ZWQgZXRjICh3aGVyZSBpdCdzIG5vdCBub3RpY2VkKVxuXG4gICAgaWYgKCF2aWV3cG9ydElzRGlmZiAmJiAhKGluTm9kZURyYWdHZXN0dXJlICYmICFoYXNDb21wb3VuZE5vZGVzKSkge1xuICAgICAgci5tb3Rpb25CbHVyUHhSYXRpbyA9IDE7XG4gICAgfVxuXG4gICAgaWYgKGZvcmNlZFBhbikge1xuICAgICAgZWZmZWN0aXZlUGFuID0gZm9yY2VkUGFuO1xuICAgIH0gLy8gYXBwbHkgcGl4ZWwgcmF0aW9cblxuXG4gICAgZWZmZWN0aXZlWm9vbSAqPSBwaXhlbFJhdGlvO1xuICAgIGVmZmVjdGl2ZVBhbi54ICo9IHBpeGVsUmF0aW87XG4gICAgZWZmZWN0aXZlUGFuLnkgKj0gcGl4ZWxSYXRpbztcbiAgICB2YXIgZWxlcyA9IHIuZ2V0Q2FjaGVkWlNvcnRlZEVsZXMoKTtcblxuICAgIGZ1bmN0aW9uIG1iY2xlYXIoY29udGV4dCwgeCwgeSwgdywgaCkge1xuICAgICAgdmFyIGdjbyA9IGNvbnRleHQuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uO1xuICAgICAgY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSAnZGVzdGluYXRpb24tb3V0JztcbiAgICAgIHIuY29sb3JGaWxsU3R5bGUoY29udGV4dCwgMjU1LCAyNTUsIDI1NSwgci5tb3Rpb25CbHVyVHJhbnNwYXJlbmN5KTtcbiAgICAgIGNvbnRleHQuZmlsbFJlY3QoeCwgeSwgdywgaCk7XG4gICAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9IGdjbztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzZXRDb250ZXh0VHJhbnNmb3JtKGNvbnRleHQsIGNsZWFyKSB7XG4gICAgICB2YXIgZVBhbiwgZVpvb20sIHcsIGg7XG5cbiAgICAgIGlmICghci5jbGVhcmluZ01vdGlvbkJsdXIgJiYgKGNvbnRleHQgPT09IGRhdGEuYnVmZmVyQ29udGV4dHNbci5NT1RJT05CTFVSX0JVRkZFUl9OT0RFXSB8fCBjb250ZXh0ID09PSBkYXRhLmJ1ZmZlckNvbnRleHRzW3IuTU9USU9OQkxVUl9CVUZGRVJfRFJBR10pKSB7XG4gICAgICAgIGVQYW4gPSB7XG4gICAgICAgICAgeDogcGFuLnggKiBtYlB4UmF0aW8sXG4gICAgICAgICAgeTogcGFuLnkgKiBtYlB4UmF0aW9cbiAgICAgICAgfTtcbiAgICAgICAgZVpvb20gPSB6b29tICogbWJQeFJhdGlvO1xuICAgICAgICB3ID0gci5jYW52YXNXaWR0aCAqIG1iUHhSYXRpbztcbiAgICAgICAgaCA9IHIuY2FudmFzSGVpZ2h0ICogbWJQeFJhdGlvO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZVBhbiA9IGVmZmVjdGl2ZVBhbjtcbiAgICAgICAgZVpvb20gPSBlZmZlY3RpdmVab29tO1xuICAgICAgICB3ID0gci5jYW52YXNXaWR0aDtcbiAgICAgICAgaCA9IHIuY2FudmFzSGVpZ2h0O1xuICAgICAgfVxuXG4gICAgICBjb250ZXh0LnNldFRyYW5zZm9ybSgxLCAwLCAwLCAxLCAwLCAwKTtcblxuICAgICAgaWYgKGNsZWFyID09PSAnbW90aW9uQmx1cicpIHtcbiAgICAgICAgbWJjbGVhcihjb250ZXh0LCAwLCAwLCB3LCBoKTtcbiAgICAgIH0gZWxzZSBpZiAoIWZvcmNlZENvbnRleHQgJiYgKGNsZWFyID09PSB1bmRlZmluZWQgfHwgY2xlYXIpKSB7XG4gICAgICAgIGNvbnRleHQuY2xlYXJSZWN0KDAsIDAsIHcsIGgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWRyYXdBbGxMYXllcnMpIHtcbiAgICAgICAgY29udGV4dC50cmFuc2xhdGUoZVBhbi54LCBlUGFuLnkpO1xuICAgICAgICBjb250ZXh0LnNjYWxlKGVab29tLCBlWm9vbSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChmb3JjZWRQYW4pIHtcbiAgICAgICAgY29udGV4dC50cmFuc2xhdGUoZm9yY2VkUGFuLngsIGZvcmNlZFBhbi55KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGZvcmNlZFpvb20pIHtcbiAgICAgICAgY29udGV4dC5zY2FsZShmb3JjZWRab29tLCBmb3JjZWRab29tKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIXRleHR1cmVEcmF3KSB7XG4gICAgICByLnRleHR1cmVEcmF3TGFzdEZyYW1lID0gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKHRleHR1cmVEcmF3KSB7XG4gICAgICByLnRleHR1cmVEcmF3TGFzdEZyYW1lID0gdHJ1ZTtcblxuICAgICAgaWYgKCFyLnRleHR1cmVDYWNoZSkge1xuICAgICAgICByLnRleHR1cmVDYWNoZSA9IHt9O1xuICAgICAgICByLnRleHR1cmVDYWNoZS5iYiA9IGN5Lm11dGFibGVFbGVtZW50cygpLmJvdW5kaW5nQm94KCk7XG4gICAgICAgIHIudGV4dHVyZUNhY2hlLnRleHR1cmUgPSByLmRhdGEuYnVmZmVyQ2FudmFzZXNbci5URVhUVVJFX0JVRkZFUl07XG4gICAgICAgIHZhciBjeHQgPSByLmRhdGEuYnVmZmVyQ29udGV4dHNbci5URVhUVVJFX0JVRkZFUl07XG4gICAgICAgIGN4dC5zZXRUcmFuc2Zvcm0oMSwgMCwgMCwgMSwgMCwgMCk7XG4gICAgICAgIGN4dC5jbGVhclJlY3QoMCwgMCwgci5jYW52YXNXaWR0aCAqIHIudGV4dHVyZU11bHQsIHIuY2FudmFzSGVpZ2h0ICogci50ZXh0dXJlTXVsdCk7XG4gICAgICAgIHIucmVuZGVyKHtcbiAgICAgICAgICBmb3JjZWRDb250ZXh0OiBjeHQsXG4gICAgICAgICAgZHJhd09ubHlOb2RlTGF5ZXI6IHRydWUsXG4gICAgICAgICAgZm9yY2VkUHhSYXRpbzogcGl4ZWxSYXRpbyAqIHIudGV4dHVyZU11bHRcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciB2cCA9IHIudGV4dHVyZUNhY2hlLnZpZXdwb3J0ID0ge1xuICAgICAgICAgIHpvb206IGN5Lnpvb20oKSxcbiAgICAgICAgICBwYW46IGN5LnBhbigpLFxuICAgICAgICAgIHdpZHRoOiByLmNhbnZhc1dpZHRoLFxuICAgICAgICAgIGhlaWdodDogci5jYW52YXNIZWlnaHRcbiAgICAgICAgfTtcbiAgICAgICAgdnAubXBhbiA9IHtcbiAgICAgICAgICB4OiAoMCAtIHZwLnBhbi54KSAvIHZwLnpvb20sXG4gICAgICAgICAgeTogKDAgLSB2cC5wYW4ueSkgLyB2cC56b29tXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIG5lZWREcmF3W3IuRFJBR10gPSBmYWxzZTtcbiAgICAgIG5lZWREcmF3W3IuTk9ERV0gPSBmYWxzZTtcbiAgICAgIHZhciBjb250ZXh0ID0gZGF0YS5jb250ZXh0c1tyLk5PREVdO1xuICAgICAgdmFyIHRleHR1cmUgPSByLnRleHR1cmVDYWNoZS50ZXh0dXJlO1xuICAgICAgdmFyIHZwID0gci50ZXh0dXJlQ2FjaGUudmlld3BvcnQ7XG4gICAgICBjb250ZXh0LnNldFRyYW5zZm9ybSgxLCAwLCAwLCAxLCAwLCAwKTtcblxuICAgICAgaWYgKG1vdGlvbkJsdXIpIHtcbiAgICAgICAgbWJjbGVhcihjb250ZXh0LCAwLCAwLCB2cC53aWR0aCwgdnAuaGVpZ2h0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnRleHQuY2xlYXJSZWN0KDAsIDAsIHZwLndpZHRoLCB2cC5oZWlnaHQpO1xuICAgICAgfVxuXG4gICAgICB2YXIgb3V0c2lkZUJnQ29sb3IgPSBzdHlsZS5jb3JlKCdvdXRzaWRlLXRleHR1cmUtYmctY29sb3InKS52YWx1ZTtcbiAgICAgIHZhciBvdXRzaWRlQmdPcGFjaXR5ID0gc3R5bGUuY29yZSgnb3V0c2lkZS10ZXh0dXJlLWJnLW9wYWNpdHknKS52YWx1ZTtcbiAgICAgIHIuY29sb3JGaWxsU3R5bGUoY29udGV4dCwgb3V0c2lkZUJnQ29sb3JbMF0sIG91dHNpZGVCZ0NvbG9yWzFdLCBvdXRzaWRlQmdDb2xvclsyXSwgb3V0c2lkZUJnT3BhY2l0eSk7XG4gICAgICBjb250ZXh0LmZpbGxSZWN0KDAsIDAsIHZwLndpZHRoLCB2cC5oZWlnaHQpO1xuICAgICAgdmFyIHpvb20gPSBjeS56b29tKCk7XG4gICAgICBzZXRDb250ZXh0VHJhbnNmb3JtKGNvbnRleHQsIGZhbHNlKTtcbiAgICAgIGNvbnRleHQuY2xlYXJSZWN0KHZwLm1wYW4ueCwgdnAubXBhbi55LCB2cC53aWR0aCAvIHZwLnpvb20gLyBwaXhlbFJhdGlvLCB2cC5oZWlnaHQgLyB2cC56b29tIC8gcGl4ZWxSYXRpbyk7XG4gICAgICBjb250ZXh0LmRyYXdJbWFnZSh0ZXh0dXJlLCB2cC5tcGFuLngsIHZwLm1wYW4ueSwgdnAud2lkdGggLyB2cC56b29tIC8gcGl4ZWxSYXRpbywgdnAuaGVpZ2h0IC8gdnAuem9vbSAvIHBpeGVsUmF0aW8pO1xuICAgIH0gZWxzZSBpZiAoci50ZXh0dXJlT25WaWV3cG9ydCAmJiAhZm9yY2VkQ29udGV4dCkge1xuICAgICAgLy8gY2xlYXIgdGhlIGNhY2hlIHNpbmNlIHdlIGRvbid0IG5lZWQgaXRcbiAgICAgIHIudGV4dHVyZUNhY2hlID0gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgZXh0ZW50ID0gY3kuZXh0ZW50KCk7XG4gICAgdmFyIHZwTWFuaXAgPSByLnBpbmNoaW5nIHx8IHIuaG92ZXJEYXRhLmRyYWdnaW5nIHx8IHIuc3dpcGVQYW5uaW5nIHx8IHIuZGF0YS53aGVlbFpvb21pbmcgfHwgci5ob3ZlckRhdGEuZHJhZ2dpbmdFbGVzIHx8IHIuY3kuYW5pbWF0ZWQoKTtcbiAgICB2YXIgaGlkZUVkZ2VzID0gci5oaWRlRWRnZXNPblZpZXdwb3J0ICYmIHZwTWFuaXA7XG4gICAgdmFyIG5lZWRNYkNsZWFyID0gW107XG4gICAgbmVlZE1iQ2xlYXJbci5OT0RFXSA9ICFuZWVkRHJhd1tyLk5PREVdICYmIG1vdGlvbkJsdXIgJiYgIXIuY2xlYXJlZEZvck1vdGlvbkJsdXJbci5OT0RFXSB8fCByLmNsZWFyaW5nTW90aW9uQmx1cjtcblxuICAgIGlmIChuZWVkTWJDbGVhcltyLk5PREVdKSB7XG4gICAgICByLmNsZWFyZWRGb3JNb3Rpb25CbHVyW3IuTk9ERV0gPSB0cnVlO1xuICAgIH1cblxuICAgIG5lZWRNYkNsZWFyW3IuRFJBR10gPSAhbmVlZERyYXdbci5EUkFHXSAmJiBtb3Rpb25CbHVyICYmICFyLmNsZWFyZWRGb3JNb3Rpb25CbHVyW3IuRFJBR10gfHwgci5jbGVhcmluZ01vdGlvbkJsdXI7XG5cbiAgICBpZiAobmVlZE1iQ2xlYXJbci5EUkFHXSkge1xuICAgICAgci5jbGVhcmVkRm9yTW90aW9uQmx1cltyLkRSQUddID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAobmVlZERyYXdbci5OT0RFXSB8fCBkcmF3QWxsTGF5ZXJzIHx8IGRyYXdPbmx5Tm9kZUxheWVyIHx8IG5lZWRNYkNsZWFyW3IuTk9ERV0pIHtcbiAgICAgIHZhciB1c2VCdWZmZXIgPSBtb3Rpb25CbHVyICYmICFuZWVkTWJDbGVhcltyLk5PREVdICYmIG1iUHhSYXRpbyAhPT0gMTtcbiAgICAgIHZhciBjb250ZXh0ID0gZm9yY2VkQ29udGV4dCB8fCAodXNlQnVmZmVyID8gci5kYXRhLmJ1ZmZlckNvbnRleHRzW3IuTU9USU9OQkxVUl9CVUZGRVJfTk9ERV0gOiBkYXRhLmNvbnRleHRzW3IuTk9ERV0pO1xuICAgICAgdmFyIGNsZWFyID0gbW90aW9uQmx1ciAmJiAhdXNlQnVmZmVyID8gJ21vdGlvbkJsdXInIDogdW5kZWZpbmVkO1xuICAgICAgc2V0Q29udGV4dFRyYW5zZm9ybShjb250ZXh0LCBjbGVhcik7XG5cbiAgICAgIGlmIChoaWRlRWRnZXMpIHtcbiAgICAgICAgci5kcmF3Q2FjaGVkTm9kZXMoY29udGV4dCwgZWxlcy5ub25kcmFnLCBwaXhlbFJhdGlvLCBleHRlbnQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgci5kcmF3TGF5ZXJlZEVsZW1lbnRzKGNvbnRleHQsIGVsZXMubm9uZHJhZywgcGl4ZWxSYXRpbywgZXh0ZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHIuZGVidWcpIHtcbiAgICAgICAgci5kcmF3RGVidWdQb2ludHMoY29udGV4dCwgZWxlcy5ub25kcmFnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFkcmF3QWxsTGF5ZXJzICYmICFtb3Rpb25CbHVyKSB7XG4gICAgICAgIG5lZWREcmF3W3IuTk9ERV0gPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIWRyYXdPbmx5Tm9kZUxheWVyICYmIChuZWVkRHJhd1tyLkRSQUddIHx8IGRyYXdBbGxMYXllcnMgfHwgbmVlZE1iQ2xlYXJbci5EUkFHXSkpIHtcbiAgICAgIHZhciB1c2VCdWZmZXIgPSBtb3Rpb25CbHVyICYmICFuZWVkTWJDbGVhcltyLkRSQUddICYmIG1iUHhSYXRpbyAhPT0gMTtcbiAgICAgIHZhciBjb250ZXh0ID0gZm9yY2VkQ29udGV4dCB8fCAodXNlQnVmZmVyID8gci5kYXRhLmJ1ZmZlckNvbnRleHRzW3IuTU9USU9OQkxVUl9CVUZGRVJfRFJBR10gOiBkYXRhLmNvbnRleHRzW3IuRFJBR10pO1xuICAgICAgc2V0Q29udGV4dFRyYW5zZm9ybShjb250ZXh0LCBtb3Rpb25CbHVyICYmICF1c2VCdWZmZXIgPyAnbW90aW9uQmx1cicgOiB1bmRlZmluZWQpO1xuXG4gICAgICBpZiAoaGlkZUVkZ2VzKSB7XG4gICAgICAgIHIuZHJhd0NhY2hlZE5vZGVzKGNvbnRleHQsIGVsZXMuZHJhZywgcGl4ZWxSYXRpbywgZXh0ZW50KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHIuZHJhd0NhY2hlZEVsZW1lbnRzKGNvbnRleHQsIGVsZXMuZHJhZywgcGl4ZWxSYXRpbywgZXh0ZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHIuZGVidWcpIHtcbiAgICAgICAgci5kcmF3RGVidWdQb2ludHMoY29udGV4dCwgZWxlcy5kcmFnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFkcmF3QWxsTGF5ZXJzICYmICFtb3Rpb25CbHVyKSB7XG4gICAgICAgIG5lZWREcmF3W3IuRFJBR10gPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoci5zaG93RnBzIHx8ICFkcmF3T25seU5vZGVMYXllciAmJiBuZWVkRHJhd1tyLlNFTEVDVF9CT1hdICYmICFkcmF3QWxsTGF5ZXJzKSB7XG4gICAgICB2YXIgY29udGV4dCA9IGZvcmNlZENvbnRleHQgfHwgZGF0YS5jb250ZXh0c1tyLlNFTEVDVF9CT1hdO1xuICAgICAgc2V0Q29udGV4dFRyYW5zZm9ybShjb250ZXh0KTtcblxuICAgICAgaWYgKHIuc2VsZWN0aW9uWzRdID09IDEgJiYgKHIuaG92ZXJEYXRhLnNlbGVjdGluZyB8fCByLnRvdWNoRGF0YS5zZWxlY3RpbmcpKSB7XG4gICAgICAgIHZhciB6b29tID0gci5jeS56b29tKCk7XG4gICAgICAgIHZhciBib3JkZXJXaWR0aCA9IHN0eWxlLmNvcmUoJ3NlbGVjdGlvbi1ib3gtYm9yZGVyLXdpZHRoJykudmFsdWUgLyB6b29tO1xuICAgICAgICBjb250ZXh0LmxpbmVXaWR0aCA9IGJvcmRlcldpZHRoO1xuICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICdyZ2JhKCcgKyBzdHlsZS5jb3JlKCdzZWxlY3Rpb24tYm94LWNvbG9yJykudmFsdWVbMF0gKyAnLCcgKyBzdHlsZS5jb3JlKCdzZWxlY3Rpb24tYm94LWNvbG9yJykudmFsdWVbMV0gKyAnLCcgKyBzdHlsZS5jb3JlKCdzZWxlY3Rpb24tYm94LWNvbG9yJykudmFsdWVbMl0gKyAnLCcgKyBzdHlsZS5jb3JlKCdzZWxlY3Rpb24tYm94LW9wYWNpdHknKS52YWx1ZSArICcpJztcbiAgICAgICAgY29udGV4dC5maWxsUmVjdChyLnNlbGVjdGlvblswXSwgci5zZWxlY3Rpb25bMV0sIHIuc2VsZWN0aW9uWzJdIC0gci5zZWxlY3Rpb25bMF0sIHIuc2VsZWN0aW9uWzNdIC0gci5zZWxlY3Rpb25bMV0pO1xuXG4gICAgICAgIGlmIChib3JkZXJXaWR0aCA+IDApIHtcbiAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJ3JnYmEoJyArIHN0eWxlLmNvcmUoJ3NlbGVjdGlvbi1ib3gtYm9yZGVyLWNvbG9yJykudmFsdWVbMF0gKyAnLCcgKyBzdHlsZS5jb3JlKCdzZWxlY3Rpb24tYm94LWJvcmRlci1jb2xvcicpLnZhbHVlWzFdICsgJywnICsgc3R5bGUuY29yZSgnc2VsZWN0aW9uLWJveC1ib3JkZXItY29sb3InKS52YWx1ZVsyXSArICcsJyArIHN0eWxlLmNvcmUoJ3NlbGVjdGlvbi1ib3gtb3BhY2l0eScpLnZhbHVlICsgJyknO1xuICAgICAgICAgIGNvbnRleHQuc3Ryb2tlUmVjdChyLnNlbGVjdGlvblswXSwgci5zZWxlY3Rpb25bMV0sIHIuc2VsZWN0aW9uWzJdIC0gci5zZWxlY3Rpb25bMF0sIHIuc2VsZWN0aW9uWzNdIC0gci5zZWxlY3Rpb25bMV0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChkYXRhLmJnQWN0aXZlUG9zaXN0aW9uICYmICFyLmhvdmVyRGF0YS5zZWxlY3RpbmcpIHtcbiAgICAgICAgdmFyIHpvb20gPSByLmN5Lnpvb20oKTtcbiAgICAgICAgdmFyIHBvcyA9IGRhdGEuYmdBY3RpdmVQb3Npc3Rpb247XG4gICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJ3JnYmEoJyArIHN0eWxlLmNvcmUoJ2FjdGl2ZS1iZy1jb2xvcicpLnZhbHVlWzBdICsgJywnICsgc3R5bGUuY29yZSgnYWN0aXZlLWJnLWNvbG9yJykudmFsdWVbMV0gKyAnLCcgKyBzdHlsZS5jb3JlKCdhY3RpdmUtYmctY29sb3InKS52YWx1ZVsyXSArICcsJyArIHN0eWxlLmNvcmUoJ2FjdGl2ZS1iZy1vcGFjaXR5JykudmFsdWUgKyAnKSc7XG4gICAgICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XG4gICAgICAgIGNvbnRleHQuYXJjKHBvcy54LCBwb3MueSwgc3R5bGUuY29yZSgnYWN0aXZlLWJnLXNpemUnKS5wZlZhbHVlIC8gem9vbSwgMCwgMiAqIE1hdGguUEkpO1xuICAgICAgICBjb250ZXh0LmZpbGwoKTtcbiAgICAgIH1cblxuICAgICAgdmFyIHRpbWVUb1JlbmRlciA9IHIubGFzdFJlZHJhd1RpbWU7XG5cbiAgICAgIGlmIChyLnNob3dGcHMgJiYgdGltZVRvUmVuZGVyKSB7XG4gICAgICAgIHRpbWVUb1JlbmRlciA9IE1hdGgucm91bmQodGltZVRvUmVuZGVyKTtcbiAgICAgICAgdmFyIGZwcyA9IE1hdGgucm91bmQoMTAwMCAvIHRpbWVUb1JlbmRlcik7XG4gICAgICAgIGNvbnRleHQuc2V0VHJhbnNmb3JtKDEsIDAsIDAsIDEsIDAsIDApO1xuICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICdyZ2JhKDI1NSwgMCwgMCwgMC43NSknO1xuICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJ3JnYmEoMjU1LCAwLCAwLCAwLjc1KSc7XG4gICAgICAgIGNvbnRleHQubGluZVdpZHRoID0gMTtcbiAgICAgICAgY29udGV4dC5maWxsVGV4dCgnMSBmcmFtZSA9ICcgKyB0aW1lVG9SZW5kZXIgKyAnIG1zID0gJyArIGZwcyArICcgZnBzJywgMCwgMjApO1xuICAgICAgICB2YXIgbWF4RnBzID0gNjA7XG4gICAgICAgIGNvbnRleHQuc3Ryb2tlUmVjdCgwLCAzMCwgMjUwLCAyMCk7XG4gICAgICAgIGNvbnRleHQuZmlsbFJlY3QoMCwgMzAsIDI1MCAqIE1hdGgubWluKGZwcyAvIG1heEZwcywgMSksIDIwKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFkcmF3QWxsTGF5ZXJzKSB7XG4gICAgICAgIG5lZWREcmF3W3IuU0VMRUNUX0JPWF0gPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9IC8vIG1vdGlvbmJsdXI6IGJsaXQgcmVuZGVyZWQgYmx1cnJ5IGZyYW1lc1xuXG5cbiAgICBpZiAobW90aW9uQmx1ciAmJiBtYlB4UmF0aW8gIT09IDEpIHtcbiAgICAgIHZhciBjeHROb2RlID0gZGF0YS5jb250ZXh0c1tyLk5PREVdO1xuICAgICAgdmFyIHR4dE5vZGUgPSByLmRhdGEuYnVmZmVyQ2FudmFzZXNbci5NT1RJT05CTFVSX0JVRkZFUl9OT0RFXTtcbiAgICAgIHZhciBjeHREcmFnID0gZGF0YS5jb250ZXh0c1tyLkRSQUddO1xuICAgICAgdmFyIHR4dERyYWcgPSByLmRhdGEuYnVmZmVyQ2FudmFzZXNbci5NT1RJT05CTFVSX0JVRkZFUl9EUkFHXTtcblxuICAgICAgdmFyIGRyYXdNb3Rpb25CbHVyID0gZnVuY3Rpb24gZHJhd01vdGlvbkJsdXIoY3h0LCB0eHQsIG5lZWRDbGVhcikge1xuICAgICAgICBjeHQuc2V0VHJhbnNmb3JtKDEsIDAsIDAsIDEsIDAsIDApO1xuXG4gICAgICAgIGlmIChuZWVkQ2xlYXIgfHwgIW1vdGlvbkJsdXJGYWRlRWZmZWN0KSB7XG4gICAgICAgICAgY3h0LmNsZWFyUmVjdCgwLCAwLCByLmNhbnZhc1dpZHRoLCByLmNhbnZhc0hlaWdodCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbWJjbGVhcihjeHQsIDAsIDAsIHIuY2FudmFzV2lkdGgsIHIuY2FudmFzSGVpZ2h0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBweHIgPSBtYlB4UmF0aW87XG4gICAgICAgIGN4dC5kcmF3SW1hZ2UodHh0LCAvLyBpbWdcbiAgICAgICAgMCwgMCwgLy8gc3gsIHN5XG4gICAgICAgIHIuY2FudmFzV2lkdGggKiBweHIsIHIuY2FudmFzSGVpZ2h0ICogcHhyLCAvLyBzdywgc2hcbiAgICAgICAgMCwgMCwgLy8geCwgeVxuICAgICAgICByLmNhbnZhc1dpZHRoLCByLmNhbnZhc0hlaWdodCAvLyB3LCBoXG4gICAgICAgICk7XG4gICAgICB9O1xuXG4gICAgICBpZiAobmVlZERyYXdbci5OT0RFXSB8fCBuZWVkTWJDbGVhcltyLk5PREVdKSB7XG4gICAgICAgIGRyYXdNb3Rpb25CbHVyKGN4dE5vZGUsIHR4dE5vZGUsIG5lZWRNYkNsZWFyW3IuTk9ERV0pO1xuICAgICAgICBuZWVkRHJhd1tyLk5PREVdID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlmIChuZWVkRHJhd1tyLkRSQUddIHx8IG5lZWRNYkNsZWFyW3IuRFJBR10pIHtcbiAgICAgICAgZHJhd01vdGlvbkJsdXIoY3h0RHJhZywgdHh0RHJhZywgbmVlZE1iQ2xlYXJbci5EUkFHXSk7XG4gICAgICAgIG5lZWREcmF3W3IuRFJBR10gPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByLnByZXZWaWV3cG9ydCA9IHZwO1xuXG4gICAgaWYgKHIuY2xlYXJpbmdNb3Rpb25CbHVyKSB7XG4gICAgICByLmNsZWFyaW5nTW90aW9uQmx1ciA9IGZhbHNlO1xuICAgICAgci5tb3Rpb25CbHVyQ2xlYXJlZCA9IHRydWU7XG4gICAgICByLm1vdGlvbkJsdXIgPSB0cnVlO1xuICAgIH1cblxuICAgIGlmIChtb3Rpb25CbHVyKSB7XG4gICAgICByLm1vdGlvbkJsdXJUaW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHIubW90aW9uQmx1clRpbWVvdXQgPSBudWxsO1xuICAgICAgICByLmNsZWFyZWRGb3JNb3Rpb25CbHVyW3IuTk9ERV0gPSBmYWxzZTtcbiAgICAgICAgci5jbGVhcmVkRm9yTW90aW9uQmx1cltyLkRSQUddID0gZmFsc2U7XG4gICAgICAgIHIubW90aW9uQmx1ciA9IGZhbHNlO1xuICAgICAgICByLmNsZWFyaW5nTW90aW9uQmx1ciA9ICF0ZXh0dXJlRHJhdztcbiAgICAgICAgci5tYkZyYW1lcyA9IDA7XG4gICAgICAgIG5lZWREcmF3W3IuTk9ERV0gPSB0cnVlO1xuICAgICAgICBuZWVkRHJhd1tyLkRSQUddID0gdHJ1ZTtcbiAgICAgICAgci5yZWRyYXcoKTtcbiAgICAgIH0sIG1vdGlvbkJsdXJEZWxheSk7XG4gICAgfVxuXG4gICAgaWYgKCFmb3JjZWRDb250ZXh0KSB7XG4gICAgICBjeS5lbWl0KCdyZW5kZXInKTtcbiAgICB9XG4gIH07XG5cbiAgdmFyIENScCQzID0ge307IC8vIEBPIFBvbHlnb24gZHJhd2luZ1xuXG4gIENScCQzLmRyYXdQb2x5Z29uUGF0aCA9IGZ1bmN0aW9uIChjb250ZXh0LCB4LCB5LCB3aWR0aCwgaGVpZ2h0LCBwb2ludHMpIHtcbiAgICB2YXIgaGFsZlcgPSB3aWR0aCAvIDI7XG4gICAgdmFyIGhhbGZIID0gaGVpZ2h0IC8gMjtcblxuICAgIGlmIChjb250ZXh0LmJlZ2luUGF0aCkge1xuICAgICAgY29udGV4dC5iZWdpblBhdGgoKTtcbiAgICB9XG5cbiAgICBjb250ZXh0Lm1vdmVUbyh4ICsgaGFsZlcgKiBwb2ludHNbMF0sIHkgKyBoYWxmSCAqIHBvaW50c1sxXSk7XG5cbiAgICBmb3IgKHZhciBpID0gMTsgaSA8IHBvaW50cy5sZW5ndGggLyAyOyBpKyspIHtcbiAgICAgIGNvbnRleHQubGluZVRvKHggKyBoYWxmVyAqIHBvaW50c1tpICogMl0sIHkgKyBoYWxmSCAqIHBvaW50c1tpICogMiArIDFdKTtcbiAgICB9XG5cbiAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICB9O1xuXG4gIENScCQzLmRyYXdSb3VuZFBvbHlnb25QYXRoID0gZnVuY3Rpb24gKGNvbnRleHQsIHgsIHksIHdpZHRoLCBoZWlnaHQsIHBvaW50cykge1xuICAgIHZhciBoYWxmVyA9IHdpZHRoIC8gMjtcbiAgICB2YXIgaGFsZkggPSBoZWlnaHQgLyAyO1xuICAgIHZhciBjb3JuZXJSYWRpdXMgPSBnZXRSb3VuZFBvbHlnb25SYWRpdXMod2lkdGgsIGhlaWdodCk7XG5cbiAgICBpZiAoY29udGV4dC5iZWdpblBhdGgpIHtcbiAgICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XG4gICAgfVxuXG4gICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IHBvaW50cy5sZW5ndGggLyA0OyBfaSsrKSB7XG4gICAgICB2YXIgc291cmNlVXYgPSB2b2lkIDAsXG4gICAgICAgICAgZGVzdFV2ID0gdm9pZCAwO1xuXG4gICAgICBpZiAoX2kgPT09IDApIHtcbiAgICAgICAgc291cmNlVXYgPSBwb2ludHMubGVuZ3RoIC0gMjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNvdXJjZVV2ID0gX2kgKiA0IC0gMjtcbiAgICAgIH1cblxuICAgICAgZGVzdFV2ID0gX2kgKiA0ICsgMjtcbiAgICAgIHZhciBweCA9IHggKyBoYWxmVyAqIHBvaW50c1tfaSAqIDRdO1xuICAgICAgdmFyIHB5ID0geSArIGhhbGZIICogcG9pbnRzW19pICogNCArIDFdO1xuICAgICAgdmFyIGNvc1RoZXRhID0gLXBvaW50c1tzb3VyY2VVdl0gKiBwb2ludHNbZGVzdFV2XSAtIHBvaW50c1tzb3VyY2VVdiArIDFdICogcG9pbnRzW2Rlc3RVdiArIDFdO1xuICAgICAgdmFyIG9mZnNldCA9IGNvcm5lclJhZGl1cyAvIE1hdGgudGFuKE1hdGguYWNvcyhjb3NUaGV0YSkgLyAyKTtcbiAgICAgIHZhciBjcDB4ID0gcHggLSBvZmZzZXQgKiBwb2ludHNbc291cmNlVXZdO1xuICAgICAgdmFyIGNwMHkgPSBweSAtIG9mZnNldCAqIHBvaW50c1tzb3VyY2VVdiArIDFdO1xuICAgICAgdmFyIGNwMXggPSBweCArIG9mZnNldCAqIHBvaW50c1tkZXN0VXZdO1xuICAgICAgdmFyIGNwMXkgPSBweSArIG9mZnNldCAqIHBvaW50c1tkZXN0VXYgKyAxXTtcblxuICAgICAgaWYgKF9pID09PSAwKSB7XG4gICAgICAgIGNvbnRleHQubW92ZVRvKGNwMHgsIGNwMHkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29udGV4dC5saW5lVG8oY3AweCwgY3AweSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnRleHQuYXJjVG8ocHgsIHB5LCBjcDF4LCBjcDF5LCBjb3JuZXJSYWRpdXMpO1xuICAgIH1cblxuICAgIGNvbnRleHQuY2xvc2VQYXRoKCk7XG4gIH07IC8vIFJvdW5kIHJlY3RhbmdsZSBkcmF3aW5nXG5cblxuICBDUnAkMy5kcmF3Um91bmRSZWN0YW5nbGVQYXRoID0gZnVuY3Rpb24gKGNvbnRleHQsIHgsIHksIHdpZHRoLCBoZWlnaHQpIHtcbiAgICB2YXIgaGFsZldpZHRoID0gd2lkdGggLyAyO1xuICAgIHZhciBoYWxmSGVpZ2h0ID0gaGVpZ2h0IC8gMjtcbiAgICB2YXIgY29ybmVyUmFkaXVzID0gZ2V0Um91bmRSZWN0YW5nbGVSYWRpdXMod2lkdGgsIGhlaWdodCk7XG5cbiAgICBpZiAoY29udGV4dC5iZWdpblBhdGgpIHtcbiAgICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XG4gICAgfSAvLyBTdGFydCBhdCB0b3AgbWlkZGxlXG5cblxuICAgIGNvbnRleHQubW92ZVRvKHgsIHkgLSBoYWxmSGVpZ2h0KTsgLy8gQXJjIGZyb20gbWlkZGxlIHRvcCB0byByaWdodCBzaWRlXG5cbiAgICBjb250ZXh0LmFyY1RvKHggKyBoYWxmV2lkdGgsIHkgLSBoYWxmSGVpZ2h0LCB4ICsgaGFsZldpZHRoLCB5LCBjb3JuZXJSYWRpdXMpOyAvLyBBcmMgZnJvbSByaWdodCBzaWRlIHRvIGJvdHRvbVxuXG4gICAgY29udGV4dC5hcmNUbyh4ICsgaGFsZldpZHRoLCB5ICsgaGFsZkhlaWdodCwgeCwgeSArIGhhbGZIZWlnaHQsIGNvcm5lclJhZGl1cyk7IC8vIEFyYyBmcm9tIGJvdHRvbSB0byBsZWZ0IHNpZGVcblxuICAgIGNvbnRleHQuYXJjVG8oeCAtIGhhbGZXaWR0aCwgeSArIGhhbGZIZWlnaHQsIHggLSBoYWxmV2lkdGgsIHksIGNvcm5lclJhZGl1cyk7IC8vIEFyYyBmcm9tIGxlZnQgc2lkZSB0byB0b3BCb3JkZXJcblxuICAgIGNvbnRleHQuYXJjVG8oeCAtIGhhbGZXaWR0aCwgeSAtIGhhbGZIZWlnaHQsIHgsIHkgLSBoYWxmSGVpZ2h0LCBjb3JuZXJSYWRpdXMpOyAvLyBKb2luIGxpbmVcblxuICAgIGNvbnRleHQubGluZVRvKHgsIHkgLSBoYWxmSGVpZ2h0KTtcbiAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICB9O1xuXG4gIENScCQzLmRyYXdCb3R0b21Sb3VuZFJlY3RhbmdsZVBhdGggPSBmdW5jdGlvbiAoY29udGV4dCwgeCwgeSwgd2lkdGgsIGhlaWdodCkge1xuICAgIHZhciBoYWxmV2lkdGggPSB3aWR0aCAvIDI7XG4gICAgdmFyIGhhbGZIZWlnaHQgPSBoZWlnaHQgLyAyO1xuICAgIHZhciBjb3JuZXJSYWRpdXMgPSBnZXRSb3VuZFJlY3RhbmdsZVJhZGl1cyh3aWR0aCwgaGVpZ2h0KTtcblxuICAgIGlmIChjb250ZXh0LmJlZ2luUGF0aCkge1xuICAgICAgY29udGV4dC5iZWdpblBhdGgoKTtcbiAgICB9IC8vIFN0YXJ0IGF0IHRvcCBtaWRkbGVcblxuXG4gICAgY29udGV4dC5tb3ZlVG8oeCwgeSAtIGhhbGZIZWlnaHQpO1xuICAgIGNvbnRleHQubGluZVRvKHggKyBoYWxmV2lkdGgsIHkgLSBoYWxmSGVpZ2h0KTtcbiAgICBjb250ZXh0LmxpbmVUbyh4ICsgaGFsZldpZHRoLCB5KTtcbiAgICBjb250ZXh0LmFyY1RvKHggKyBoYWxmV2lkdGgsIHkgKyBoYWxmSGVpZ2h0LCB4LCB5ICsgaGFsZkhlaWdodCwgY29ybmVyUmFkaXVzKTtcbiAgICBjb250ZXh0LmFyY1RvKHggLSBoYWxmV2lkdGgsIHkgKyBoYWxmSGVpZ2h0LCB4IC0gaGFsZldpZHRoLCB5LCBjb3JuZXJSYWRpdXMpO1xuICAgIGNvbnRleHQubGluZVRvKHggLSBoYWxmV2lkdGgsIHkgLSBoYWxmSGVpZ2h0KTtcbiAgICBjb250ZXh0LmxpbmVUbyh4LCB5IC0gaGFsZkhlaWdodCk7XG4gICAgY29udGV4dC5jbG9zZVBhdGgoKTtcbiAgfTtcblxuICBDUnAkMy5kcmF3Q3V0UmVjdGFuZ2xlUGF0aCA9IGZ1bmN0aW9uIChjb250ZXh0LCB4LCB5LCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgdmFyIGhhbGZXaWR0aCA9IHdpZHRoIC8gMjtcbiAgICB2YXIgaGFsZkhlaWdodCA9IGhlaWdodCAvIDI7XG4gICAgdmFyIGNvcm5lckxlbmd0aCA9IGdldEN1dFJlY3RhbmdsZUNvcm5lckxlbmd0aCgpO1xuXG4gICAgaWYgKGNvbnRleHQuYmVnaW5QYXRoKSB7XG4gICAgICBjb250ZXh0LmJlZ2luUGF0aCgpO1xuICAgIH1cblxuICAgIGNvbnRleHQubW92ZVRvKHggLSBoYWxmV2lkdGggKyBjb3JuZXJMZW5ndGgsIHkgLSBoYWxmSGVpZ2h0KTtcbiAgICBjb250ZXh0LmxpbmVUbyh4ICsgaGFsZldpZHRoIC0gY29ybmVyTGVuZ3RoLCB5IC0gaGFsZkhlaWdodCk7XG4gICAgY29udGV4dC5saW5lVG8oeCArIGhhbGZXaWR0aCwgeSAtIGhhbGZIZWlnaHQgKyBjb3JuZXJMZW5ndGgpO1xuICAgIGNvbnRleHQubGluZVRvKHggKyBoYWxmV2lkdGgsIHkgKyBoYWxmSGVpZ2h0IC0gY29ybmVyTGVuZ3RoKTtcbiAgICBjb250ZXh0LmxpbmVUbyh4ICsgaGFsZldpZHRoIC0gY29ybmVyTGVuZ3RoLCB5ICsgaGFsZkhlaWdodCk7XG4gICAgY29udGV4dC5saW5lVG8oeCAtIGhhbGZXaWR0aCArIGNvcm5lckxlbmd0aCwgeSArIGhhbGZIZWlnaHQpO1xuICAgIGNvbnRleHQubGluZVRvKHggLSBoYWxmV2lkdGgsIHkgKyBoYWxmSGVpZ2h0IC0gY29ybmVyTGVuZ3RoKTtcbiAgICBjb250ZXh0LmxpbmVUbyh4IC0gaGFsZldpZHRoLCB5IC0gaGFsZkhlaWdodCArIGNvcm5lckxlbmd0aCk7XG4gICAgY29udGV4dC5jbG9zZVBhdGgoKTtcbiAgfTtcblxuICBDUnAkMy5kcmF3QmFycmVsUGF0aCA9IGZ1bmN0aW9uIChjb250ZXh0LCB4LCB5LCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgdmFyIGhhbGZXaWR0aCA9IHdpZHRoIC8gMjtcbiAgICB2YXIgaGFsZkhlaWdodCA9IGhlaWdodCAvIDI7XG4gICAgdmFyIHhCZWdpbiA9IHggLSBoYWxmV2lkdGg7XG4gICAgdmFyIHhFbmQgPSB4ICsgaGFsZldpZHRoO1xuICAgIHZhciB5QmVnaW4gPSB5IC0gaGFsZkhlaWdodDtcbiAgICB2YXIgeUVuZCA9IHkgKyBoYWxmSGVpZ2h0O1xuICAgIHZhciBiYXJyZWxDdXJ2ZUNvbnN0YW50cyA9IGdldEJhcnJlbEN1cnZlQ29uc3RhbnRzKHdpZHRoLCBoZWlnaHQpO1xuICAgIHZhciB3T2Zmc2V0ID0gYmFycmVsQ3VydmVDb25zdGFudHMud2lkdGhPZmZzZXQ7XG4gICAgdmFyIGhPZmZzZXQgPSBiYXJyZWxDdXJ2ZUNvbnN0YW50cy5oZWlnaHRPZmZzZXQ7XG4gICAgdmFyIGN0cmxQdFhPZmZzZXQgPSBiYXJyZWxDdXJ2ZUNvbnN0YW50cy5jdHJsUHRPZmZzZXRQY3QgKiB3T2Zmc2V0O1xuXG4gICAgaWYgKGNvbnRleHQuYmVnaW5QYXRoKSB7XG4gICAgICBjb250ZXh0LmJlZ2luUGF0aCgpO1xuICAgIH1cblxuICAgIGNvbnRleHQubW92ZVRvKHhCZWdpbiwgeUJlZ2luICsgaE9mZnNldCk7XG4gICAgY29udGV4dC5saW5lVG8oeEJlZ2luLCB5RW5kIC0gaE9mZnNldCk7XG4gICAgY29udGV4dC5xdWFkcmF0aWNDdXJ2ZVRvKHhCZWdpbiArIGN0cmxQdFhPZmZzZXQsIHlFbmQsIHhCZWdpbiArIHdPZmZzZXQsIHlFbmQpO1xuICAgIGNvbnRleHQubGluZVRvKHhFbmQgLSB3T2Zmc2V0LCB5RW5kKTtcbiAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8oeEVuZCAtIGN0cmxQdFhPZmZzZXQsIHlFbmQsIHhFbmQsIHlFbmQgLSBoT2Zmc2V0KTtcbiAgICBjb250ZXh0LmxpbmVUbyh4RW5kLCB5QmVnaW4gKyBoT2Zmc2V0KTtcbiAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8oeEVuZCAtIGN0cmxQdFhPZmZzZXQsIHlCZWdpbiwgeEVuZCAtIHdPZmZzZXQsIHlCZWdpbik7XG4gICAgY29udGV4dC5saW5lVG8oeEJlZ2luICsgd09mZnNldCwgeUJlZ2luKTtcbiAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8oeEJlZ2luICsgY3RybFB0WE9mZnNldCwgeUJlZ2luLCB4QmVnaW4sIHlCZWdpbiArIGhPZmZzZXQpO1xuICAgIGNvbnRleHQuY2xvc2VQYXRoKCk7XG4gIH07XG5cbiAgdmFyIHNpbjAgPSBNYXRoLnNpbigwKTtcbiAgdmFyIGNvczAgPSBNYXRoLmNvcygwKTtcbiAgdmFyIHNpbiA9IHt9O1xuICB2YXIgY29zID0ge307XG4gIHZhciBlbGxpcHNlU3RlcFNpemUgPSBNYXRoLlBJIC8gNDA7XG5cbiAgZm9yICh2YXIgaSA9IDAgKiBNYXRoLlBJOyBpIDwgMiAqIE1hdGguUEk7IGkgKz0gZWxsaXBzZVN0ZXBTaXplKSB7XG4gICAgc2luW2ldID0gTWF0aC5zaW4oaSk7XG4gICAgY29zW2ldID0gTWF0aC5jb3MoaSk7XG4gIH1cblxuICBDUnAkMy5kcmF3RWxsaXBzZVBhdGggPSBmdW5jdGlvbiAoY29udGV4dCwgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCkge1xuICAgIGlmIChjb250ZXh0LmJlZ2luUGF0aCkge1xuICAgICAgY29udGV4dC5iZWdpblBhdGgoKTtcbiAgICB9XG5cbiAgICBpZiAoY29udGV4dC5lbGxpcHNlKSB7XG4gICAgICBjb250ZXh0LmVsbGlwc2UoY2VudGVyWCwgY2VudGVyWSwgd2lkdGggLyAyLCBoZWlnaHQgLyAyLCAwLCAwLCAyICogTWF0aC5QSSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciB4UG9zLCB5UG9zO1xuICAgICAgdmFyIHJ3ID0gd2lkdGggLyAyO1xuICAgICAgdmFyIHJoID0gaGVpZ2h0IC8gMjtcblxuICAgICAgZm9yICh2YXIgaSA9IDAgKiBNYXRoLlBJOyBpIDwgMiAqIE1hdGguUEk7IGkgKz0gZWxsaXBzZVN0ZXBTaXplKSB7XG4gICAgICAgIHhQb3MgPSBjZW50ZXJYIC0gcncgKiBzaW5baV0gKiBzaW4wICsgcncgKiBjb3NbaV0gKiBjb3MwO1xuICAgICAgICB5UG9zID0gY2VudGVyWSArIHJoICogY29zW2ldICogc2luMCArIHJoICogc2luW2ldICogY29zMDtcblxuICAgICAgICBpZiAoaSA9PT0gMCkge1xuICAgICAgICAgIGNvbnRleHQubW92ZVRvKHhQb3MsIHlQb3MpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnRleHQubGluZVRvKHhQb3MsIHlQb3MpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29udGV4dC5jbG9zZVBhdGgoKTtcbiAgfTtcblxuICAvKiBnbG9iYWwgYXRvYiwgQXJyYXlCdWZmZXIsIFVpbnQ4QXJyYXksIEJsb2IgKi9cbiAgdmFyIENScCQyID0ge307XG5cbiAgQ1JwJDIuY3JlYXRlQnVmZmVyID0gZnVuY3Rpb24gKHcsIGgpIHtcbiAgICB2YXIgYnVmZmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcblxuICAgIGJ1ZmZlci53aWR0aCA9IHc7XG4gICAgYnVmZmVyLmhlaWdodCA9IGg7XG4gICAgcmV0dXJuIFtidWZmZXIsIGJ1ZmZlci5nZXRDb250ZXh0KCcyZCcpXTtcbiAgfTtcblxuICBDUnAkMi5idWZmZXJDYW52YXNJbWFnZSA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGN5ID0gdGhpcy5jeTtcbiAgICB2YXIgZWxlcyA9IGN5Lm11dGFibGVFbGVtZW50cygpO1xuICAgIHZhciBiYiA9IGVsZXMuYm91bmRpbmdCb3goKTtcbiAgICB2YXIgY3RyUmVjdCA9IHRoaXMuZmluZENvbnRhaW5lckNsaWVudENvb3JkcygpO1xuICAgIHZhciB3aWR0aCA9IG9wdGlvbnMuZnVsbCA/IE1hdGguY2VpbChiYi53KSA6IGN0clJlY3RbMl07XG4gICAgdmFyIGhlaWdodCA9IG9wdGlvbnMuZnVsbCA/IE1hdGguY2VpbChiYi5oKSA6IGN0clJlY3RbM107XG4gICAgdmFyIHNwZWNkTWF4RGltcyA9IG51bWJlciQxKG9wdGlvbnMubWF4V2lkdGgpIHx8IG51bWJlciQxKG9wdGlvbnMubWF4SGVpZ2h0KTtcbiAgICB2YXIgcHhSYXRpbyA9IHRoaXMuZ2V0UGl4ZWxSYXRpbygpO1xuICAgIHZhciBzY2FsZSA9IDE7XG5cbiAgICBpZiAob3B0aW9ucy5zY2FsZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB3aWR0aCAqPSBvcHRpb25zLnNjYWxlO1xuICAgICAgaGVpZ2h0ICo9IG9wdGlvbnMuc2NhbGU7XG4gICAgICBzY2FsZSA9IG9wdGlvbnMuc2NhbGU7XG4gICAgfSBlbHNlIGlmIChzcGVjZE1heERpbXMpIHtcbiAgICAgIHZhciBtYXhTY2FsZVcgPSBJbmZpbml0eTtcbiAgICAgIHZhciBtYXhTY2FsZUggPSBJbmZpbml0eTtcblxuICAgICAgaWYgKG51bWJlciQxKG9wdGlvbnMubWF4V2lkdGgpKSB7XG4gICAgICAgIG1heFNjYWxlVyA9IHNjYWxlICogb3B0aW9ucy5tYXhXaWR0aCAvIHdpZHRoO1xuICAgICAgfVxuXG4gICAgICBpZiAobnVtYmVyJDEob3B0aW9ucy5tYXhIZWlnaHQpKSB7XG4gICAgICAgIG1heFNjYWxlSCA9IHNjYWxlICogb3B0aW9ucy5tYXhIZWlnaHQgLyBoZWlnaHQ7XG4gICAgICB9XG5cbiAgICAgIHNjYWxlID0gTWF0aC5taW4obWF4U2NhbGVXLCBtYXhTY2FsZUgpO1xuICAgICAgd2lkdGggKj0gc2NhbGU7XG4gICAgICBoZWlnaHQgKj0gc2NhbGU7XG4gICAgfVxuXG4gICAgaWYgKCFzcGVjZE1heERpbXMpIHtcbiAgICAgIHdpZHRoICo9IHB4UmF0aW87XG4gICAgICBoZWlnaHQgKj0gcHhSYXRpbztcbiAgICAgIHNjYWxlICo9IHB4UmF0aW87XG4gICAgfVxuXG4gICAgdmFyIGJ1ZmZDYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuXG4gICAgYnVmZkNhbnZhcy53aWR0aCA9IHdpZHRoO1xuICAgIGJ1ZmZDYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xuICAgIGJ1ZmZDYW52YXMuc3R5bGUud2lkdGggPSB3aWR0aCArICdweCc7XG4gICAgYnVmZkNhbnZhcy5zdHlsZS5oZWlnaHQgPSBoZWlnaHQgKyAncHgnO1xuICAgIHZhciBidWZmQ3h0ID0gYnVmZkNhbnZhcy5nZXRDb250ZXh0KCcyZCcpOyAvLyBSYXN0ZXJpemUgdGhlIGxheWVycywgYnV0IG9ubHkgaWYgY29udGFpbmVyIGhhcyBub256ZXJvIHNpemVcblxuICAgIGlmICh3aWR0aCA+IDAgJiYgaGVpZ2h0ID4gMCkge1xuICAgICAgYnVmZkN4dC5jbGVhclJlY3QoMCwgMCwgd2lkdGgsIGhlaWdodCk7XG4gICAgICBidWZmQ3h0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9ICdzb3VyY2Utb3Zlcic7XG4gICAgICB2YXIgenNvcnRlZEVsZXMgPSB0aGlzLmdldENhY2hlZFpTb3J0ZWRFbGVzKCk7XG5cbiAgICAgIGlmIChvcHRpb25zLmZ1bGwpIHtcbiAgICAgICAgLy8gZHJhdyB0aGUgZnVsbCBib3VuZHMgb2YgdGhlIGdyYXBoXG4gICAgICAgIGJ1ZmZDeHQudHJhbnNsYXRlKC1iYi54MSAqIHNjYWxlLCAtYmIueTEgKiBzY2FsZSk7XG4gICAgICAgIGJ1ZmZDeHQuc2NhbGUoc2NhbGUsIHNjYWxlKTtcbiAgICAgICAgdGhpcy5kcmF3RWxlbWVudHMoYnVmZkN4dCwgenNvcnRlZEVsZXMpO1xuICAgICAgICBidWZmQ3h0LnNjYWxlKDEgLyBzY2FsZSwgMSAvIHNjYWxlKTtcbiAgICAgICAgYnVmZkN4dC50cmFuc2xhdGUoYmIueDEgKiBzY2FsZSwgYmIueTEgKiBzY2FsZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBkcmF3IHRoZSBjdXJyZW50IHZpZXdcbiAgICAgICAgdmFyIHBhbiA9IGN5LnBhbigpO1xuICAgICAgICB2YXIgdHJhbnNsYXRpb24gPSB7XG4gICAgICAgICAgeDogcGFuLnggKiBzY2FsZSxcbiAgICAgICAgICB5OiBwYW4ueSAqIHNjYWxlXG4gICAgICAgIH07XG4gICAgICAgIHNjYWxlICo9IGN5Lnpvb20oKTtcbiAgICAgICAgYnVmZkN4dC50cmFuc2xhdGUodHJhbnNsYXRpb24ueCwgdHJhbnNsYXRpb24ueSk7XG4gICAgICAgIGJ1ZmZDeHQuc2NhbGUoc2NhbGUsIHNjYWxlKTtcbiAgICAgICAgdGhpcy5kcmF3RWxlbWVudHMoYnVmZkN4dCwgenNvcnRlZEVsZXMpO1xuICAgICAgICBidWZmQ3h0LnNjYWxlKDEgLyBzY2FsZSwgMSAvIHNjYWxlKTtcbiAgICAgICAgYnVmZkN4dC50cmFuc2xhdGUoLXRyYW5zbGF0aW9uLngsIC10cmFuc2xhdGlvbi55KTtcbiAgICAgIH0gLy8gbmVlZCB0byBmaWxsIGJnIGF0IGVuZCBsaWtlIHRoaXMgaW4gb3JkZXIgdG8gZmlsbCBjbGVhcmVkIHRyYW5zcGFyZW50IHBpeGVscyBpbiBqcGdzXG5cblxuICAgICAgaWYgKG9wdGlvbnMuYmcpIHtcbiAgICAgICAgYnVmZkN4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSAnZGVzdGluYXRpb24tb3Zlcic7XG4gICAgICAgIGJ1ZmZDeHQuZmlsbFN0eWxlID0gb3B0aW9ucy5iZztcbiAgICAgICAgYnVmZkN4dC5yZWN0KDAsIDAsIHdpZHRoLCBoZWlnaHQpO1xuICAgICAgICBidWZmQ3h0LmZpbGwoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gYnVmZkNhbnZhcztcbiAgfTtcblxuICBmdW5jdGlvbiBiNjRUb0Jsb2IoYjY0LCBtaW1lVHlwZSkge1xuICAgIHZhciBieXRlcyA9IGF0b2IoYjY0KTtcbiAgICB2YXIgYnVmZiA9IG5ldyBBcnJheUJ1ZmZlcihieXRlcy5sZW5ndGgpO1xuICAgIHZhciBidWZmVWludDggPSBuZXcgVWludDhBcnJheShidWZmKTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGJ1ZmZVaW50OFtpXSA9IGJ5dGVzLmNoYXJDb2RlQXQoaSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBCbG9iKFtidWZmXSwge1xuICAgICAgdHlwZTogbWltZVR5cGVcbiAgICB9KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGI2NFVyaVRvQjY0KGI2NHVyaSkge1xuICAgIHZhciBpID0gYjY0dXJpLmluZGV4T2YoJywnKTtcbiAgICByZXR1cm4gYjY0dXJpLnN1YnN0cihpICsgMSk7XG4gIH1cblxuICBmdW5jdGlvbiBvdXRwdXQob3B0aW9ucywgY2FudmFzLCBtaW1lVHlwZSkge1xuICAgIHZhciBnZXRCNjRVcmkgPSBmdW5jdGlvbiBnZXRCNjRVcmkoKSB7XG4gICAgICByZXR1cm4gY2FudmFzLnRvRGF0YVVSTChtaW1lVHlwZSwgb3B0aW9ucy5xdWFsaXR5KTtcbiAgICB9O1xuXG4gICAgc3dpdGNoIChvcHRpb25zLm91dHB1dCkge1xuICAgICAgY2FzZSAnYmxvYi1wcm9taXNlJzpcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlJDEoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjYW52YXMudG9CbG9iKGZ1bmN0aW9uIChibG9iKSB7XG4gICAgICAgICAgICAgIGlmIChibG9iICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICByZXNvbHZlKGJsb2IpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoJ2BjYW52YXMudG9CbG9iKClgIHNlbnQgYSBudWxsIHZhbHVlIGluIGl0cyBjYWxsYmFjaycpKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgbWltZVR5cGUsIG9wdGlvbnMucXVhbGl0eSk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICBjYXNlICdibG9iJzpcbiAgICAgICAgcmV0dXJuIGI2NFRvQmxvYihiNjRVcmlUb0I2NChnZXRCNjRVcmkoKSksIG1pbWVUeXBlKTtcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGI2NFVyaVRvQjY0KGdldEI2NFVyaSgpKTtcblxuICAgICAgY2FzZSAnYmFzZTY0dXJpJzpcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBnZXRCNjRVcmkoKTtcbiAgICB9XG4gIH1cblxuICBDUnAkMi5wbmcgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHJldHVybiBvdXRwdXQob3B0aW9ucywgdGhpcy5idWZmZXJDYW52YXNJbWFnZShvcHRpb25zKSwgJ2ltYWdlL3BuZycpO1xuICB9O1xuXG4gIENScCQyLmpwZyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgcmV0dXJuIG91dHB1dChvcHRpb25zLCB0aGlzLmJ1ZmZlckNhbnZhc0ltYWdlKG9wdGlvbnMpLCAnaW1hZ2UvanBlZycpO1xuICB9O1xuXG4gIHZhciBDUnAkMSA9IHt9O1xuXG4gIENScCQxLm5vZGVTaGFwZUltcGwgPSBmdW5jdGlvbiAobmFtZSwgY29udGV4dCwgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCwgcG9pbnRzKSB7XG4gICAgc3dpdGNoIChuYW1lKSB7XG4gICAgICBjYXNlICdlbGxpcHNlJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuZHJhd0VsbGlwc2VQYXRoKGNvbnRleHQsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQpO1xuXG4gICAgICBjYXNlICdwb2x5Z29uJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuZHJhd1BvbHlnb25QYXRoKGNvbnRleHQsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQsIHBvaW50cyk7XG5cbiAgICAgIGNhc2UgJ3JvdW5kLXBvbHlnb24nOlxuICAgICAgICByZXR1cm4gdGhpcy5kcmF3Um91bmRQb2x5Z29uUGF0aChjb250ZXh0LCBjZW50ZXJYLCBjZW50ZXJZLCB3aWR0aCwgaGVpZ2h0LCBwb2ludHMpO1xuXG4gICAgICBjYXNlICdyb3VuZHJlY3RhbmdsZSc6XG4gICAgICBjYXNlICdyb3VuZC1yZWN0YW5nbGUnOlxuICAgICAgICByZXR1cm4gdGhpcy5kcmF3Um91bmRSZWN0YW5nbGVQYXRoKGNvbnRleHQsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQpO1xuXG4gICAgICBjYXNlICdjdXRyZWN0YW5nbGUnOlxuICAgICAgY2FzZSAnY3V0LXJlY3RhbmdsZSc6XG4gICAgICAgIHJldHVybiB0aGlzLmRyYXdDdXRSZWN0YW5nbGVQYXRoKGNvbnRleHQsIGNlbnRlclgsIGNlbnRlclksIHdpZHRoLCBoZWlnaHQpO1xuXG4gICAgICBjYXNlICdib3R0b21yb3VuZHJlY3RhbmdsZSc6XG4gICAgICBjYXNlICdib3R0b20tcm91bmQtcmVjdGFuZ2xlJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuZHJhd0JvdHRvbVJvdW5kUmVjdGFuZ2xlUGF0aChjb250ZXh0LCBjZW50ZXJYLCBjZW50ZXJZLCB3aWR0aCwgaGVpZ2h0KTtcblxuICAgICAgY2FzZSAnYmFycmVsJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuZHJhd0JhcnJlbFBhdGgoY29udGV4dCwgY2VudGVyWCwgY2VudGVyWSwgd2lkdGgsIGhlaWdodCk7XG4gICAgfVxuICB9O1xuXG4gIHZhciBDUiA9IENhbnZhc1JlbmRlcmVyO1xuICB2YXIgQ1JwID0gQ2FudmFzUmVuZGVyZXIucHJvdG90eXBlO1xuICBDUnAuQ0FOVkFTX0xBWUVSUyA9IDM7IC8vXG5cbiAgQ1JwLlNFTEVDVF9CT1ggPSAwO1xuICBDUnAuRFJBRyA9IDE7XG4gIENScC5OT0RFID0gMjtcbiAgQ1JwLkJVRkZFUl9DT1VOVCA9IDM7IC8vXG5cbiAgQ1JwLlRFWFRVUkVfQlVGRkVSID0gMDtcbiAgQ1JwLk1PVElPTkJMVVJfQlVGRkVSX05PREUgPSAxO1xuICBDUnAuTU9USU9OQkxVUl9CVUZGRVJfRFJBRyA9IDI7XG5cbiAgZnVuY3Rpb24gQ2FudmFzUmVuZGVyZXIob3B0aW9ucykge1xuICAgIHZhciByID0gdGhpcztcbiAgICByLmRhdGEgPSB7XG4gICAgICBjYW52YXNlczogbmV3IEFycmF5KENScC5DQU5WQVNfTEFZRVJTKSxcbiAgICAgIGNvbnRleHRzOiBuZXcgQXJyYXkoQ1JwLkNBTlZBU19MQVlFUlMpLFxuICAgICAgY2FudmFzTmVlZHNSZWRyYXc6IG5ldyBBcnJheShDUnAuQ0FOVkFTX0xBWUVSUyksXG4gICAgICBidWZmZXJDYW52YXNlczogbmV3IEFycmF5KENScC5CVUZGRVJfQ09VTlQpLFxuICAgICAgYnVmZmVyQ29udGV4dHM6IG5ldyBBcnJheShDUnAuQ0FOVkFTX0xBWUVSUylcbiAgICB9O1xuICAgIHZhciB0YXBIbE9mZkF0dHIgPSAnLXdlYmtpdC10YXAtaGlnaGxpZ2h0LWNvbG9yJztcbiAgICB2YXIgdGFwSGxPZmZTdHlsZSA9ICdyZ2JhKDAsMCwwLDApJztcbiAgICByLmRhdGEuY2FudmFzQ29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcblxuICAgIHZhciBjb250YWluZXJTdHlsZSA9IHIuZGF0YS5jYW52YXNDb250YWluZXIuc3R5bGU7XG4gICAgci5kYXRhLmNhbnZhc0NvbnRhaW5lci5zdHlsZVt0YXBIbE9mZkF0dHJdID0gdGFwSGxPZmZTdHlsZTtcbiAgICBjb250YWluZXJTdHlsZS5wb3NpdGlvbiA9ICdyZWxhdGl2ZSc7XG4gICAgY29udGFpbmVyU3R5bGUuekluZGV4ID0gJzAnO1xuICAgIGNvbnRhaW5lclN0eWxlLm92ZXJmbG93ID0gJ2hpZGRlbic7XG4gICAgdmFyIGNvbnRhaW5lciA9IG9wdGlvbnMuY3kuY29udGFpbmVyKCk7XG4gICAgY29udGFpbmVyLmFwcGVuZENoaWxkKHIuZGF0YS5jYW52YXNDb250YWluZXIpO1xuICAgIGNvbnRhaW5lci5zdHlsZVt0YXBIbE9mZkF0dHJdID0gdGFwSGxPZmZTdHlsZTtcbiAgICB2YXIgc3R5bGVNYXAgPSB7XG4gICAgICAnLXdlYmtpdC11c2VyLXNlbGVjdCc6ICdub25lJyxcbiAgICAgICctbW96LXVzZXItc2VsZWN0JzogJy1tb3otbm9uZScsXG4gICAgICAndXNlci1zZWxlY3QnOiAnbm9uZScsXG4gICAgICAnLXdlYmtpdC10YXAtaGlnaGxpZ2h0LWNvbG9yJzogJ3JnYmEoMCwwLDAsMCknLFxuICAgICAgJ291dGxpbmUtc3R5bGUnOiAnbm9uZSdcbiAgICB9O1xuXG4gICAgaWYgKG1zKCkpIHtcbiAgICAgIHN0eWxlTWFwWyctbXMtdG91Y2gtYWN0aW9uJ10gPSAnbm9uZSc7XG4gICAgICBzdHlsZU1hcFsndG91Y2gtYWN0aW9uJ10gPSAnbm9uZSc7XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBDUnAuQ0FOVkFTX0xBWUVSUzsgaSsrKSB7XG4gICAgICB2YXIgY2FudmFzID0gci5kYXRhLmNhbnZhc2VzW2ldID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcblxuICAgICAgci5kYXRhLmNvbnRleHRzW2ldID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgICBPYmplY3Qua2V5cyhzdHlsZU1hcCkuZm9yRWFjaChmdW5jdGlvbiAoaykge1xuICAgICAgICBjYW52YXMuc3R5bGVba10gPSBzdHlsZU1hcFtrXTtcbiAgICAgIH0pO1xuICAgICAgY2FudmFzLnN0eWxlLnBvc2l0aW9uID0gJ2Fic29sdXRlJztcbiAgICAgIGNhbnZhcy5zZXRBdHRyaWJ1dGUoJ2RhdGEtaWQnLCAnbGF5ZXInICsgaSk7XG4gICAgICBjYW52YXMuc3R5bGUuekluZGV4ID0gU3RyaW5nKENScC5DQU5WQVNfTEFZRVJTIC0gaSk7XG4gICAgICByLmRhdGEuY2FudmFzQ29udGFpbmVyLmFwcGVuZENoaWxkKGNhbnZhcyk7XG4gICAgICByLmRhdGEuY2FudmFzTmVlZHNSZWRyYXdbaV0gPSBmYWxzZTtcbiAgICB9XG5cbiAgICByLmRhdGEudG9wQ2FudmFzID0gci5kYXRhLmNhbnZhc2VzWzBdO1xuICAgIHIuZGF0YS5jYW52YXNlc1tDUnAuTk9ERV0uc2V0QXR0cmlidXRlKCdkYXRhLWlkJywgJ2xheWVyJyArIENScC5OT0RFICsgJy1ub2RlJyk7XG4gICAgci5kYXRhLmNhbnZhc2VzW0NScC5TRUxFQ1RfQk9YXS5zZXRBdHRyaWJ1dGUoJ2RhdGEtaWQnLCAnbGF5ZXInICsgQ1JwLlNFTEVDVF9CT1ggKyAnLXNlbGVjdGJveCcpO1xuICAgIHIuZGF0YS5jYW52YXNlc1tDUnAuRFJBR10uc2V0QXR0cmlidXRlKCdkYXRhLWlkJywgJ2xheWVyJyArIENScC5EUkFHICsgJy1kcmFnJyk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IENScC5CVUZGRVJfQ09VTlQ7IGkrKykge1xuICAgICAgci5kYXRhLmJ1ZmZlckNhbnZhc2VzW2ldID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcblxuICAgICAgci5kYXRhLmJ1ZmZlckNvbnRleHRzW2ldID0gci5kYXRhLmJ1ZmZlckNhbnZhc2VzW2ldLmdldENvbnRleHQoJzJkJyk7XG4gICAgICByLmRhdGEuYnVmZmVyQ2FudmFzZXNbaV0uc3R5bGUucG9zaXRpb24gPSAnYWJzb2x1dGUnO1xuICAgICAgci5kYXRhLmJ1ZmZlckNhbnZhc2VzW2ldLnNldEF0dHJpYnV0ZSgnZGF0YS1pZCcsICdidWZmZXInICsgaSk7XG4gICAgICByLmRhdGEuYnVmZmVyQ2FudmFzZXNbaV0uc3R5bGUuekluZGV4ID0gU3RyaW5nKC1pIC0gMSk7XG4gICAgICByLmRhdGEuYnVmZmVyQ2FudmFzZXNbaV0uc3R5bGUudmlzaWJpbGl0eSA9ICdoaWRkZW4nOyAvL3IuZGF0YS5jYW52YXNDb250YWluZXIuYXBwZW5kQ2hpbGQoci5kYXRhLmJ1ZmZlckNhbnZhc2VzW2ldKTtcbiAgICB9XG5cbiAgICByLnBhdGhzRW5hYmxlZCA9IHRydWU7XG4gICAgdmFyIGVtcHR5QmIgPSBtYWtlQm91bmRpbmdCb3goKTtcblxuICAgIHZhciBnZXRCb3hDZW50ZXIgPSBmdW5jdGlvbiBnZXRCb3hDZW50ZXIoYmIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHg6IChiYi54MSArIGJiLngyKSAvIDIsXG4gICAgICAgIHk6IChiYi55MSArIGJiLnkyKSAvIDJcbiAgICAgIH07XG4gICAgfTtcblxuICAgIHZhciBnZXRDZW50ZXJPZmZzZXQgPSBmdW5jdGlvbiBnZXRDZW50ZXJPZmZzZXQoYmIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHg6IC1iYi53IC8gMixcbiAgICAgICAgeTogLWJiLmggLyAyXG4gICAgICB9O1xuICAgIH07XG5cbiAgICB2YXIgYmFja2dyb3VuZFRpbWVzdGFtcEhhc0NoYW5nZWQgPSBmdW5jdGlvbiBiYWNrZ3JvdW5kVGltZXN0YW1wSGFzQ2hhbmdlZChlbGUpIHtcbiAgICAgIHZhciBfcCA9IGVsZVswXS5fcHJpdmF0ZTtcbiAgICAgIHZhciBzYW1lID0gX3Aub2xkQmFja2dyb3VuZFRpbWVzdGFtcCA9PT0gX3AuYmFja2dyb3VuZFRpbWVzdGFtcDtcbiAgICAgIHJldHVybiAhc2FtZTtcbiAgICB9O1xuXG4gICAgdmFyIGdldFN0eWxlS2V5ID0gZnVuY3Rpb24gZ2V0U3R5bGVLZXkoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlWzBdLl9wcml2YXRlLm5vZGVLZXk7XG4gICAgfTtcblxuICAgIHZhciBnZXRMYWJlbEtleSA9IGZ1bmN0aW9uIGdldExhYmVsS2V5KGVsZSkge1xuICAgICAgcmV0dXJuIGVsZVswXS5fcHJpdmF0ZS5sYWJlbFN0eWxlS2V5O1xuICAgIH07XG5cbiAgICB2YXIgZ2V0U291cmNlTGFiZWxLZXkgPSBmdW5jdGlvbiBnZXRTb3VyY2VMYWJlbEtleShlbGUpIHtcbiAgICAgIHJldHVybiBlbGVbMF0uX3ByaXZhdGUuc291cmNlTGFiZWxTdHlsZUtleTtcbiAgICB9O1xuXG4gICAgdmFyIGdldFRhcmdldExhYmVsS2V5ID0gZnVuY3Rpb24gZ2V0VGFyZ2V0TGFiZWxLZXkoZWxlKSB7XG4gICAgICByZXR1cm4gZWxlWzBdLl9wcml2YXRlLnRhcmdldExhYmVsU3R5bGVLZXk7XG4gICAgfTtcblxuICAgIHZhciBkcmF3RWxlbWVudCA9IGZ1bmN0aW9uIGRyYXdFbGVtZW50KGNvbnRleHQsIGVsZSwgYmIsIHNjYWxlZExhYmVsU2hvd24sIHVzZUVsZU9wYWNpdHkpIHtcbiAgICAgIHJldHVybiByLmRyYXdFbGVtZW50KGNvbnRleHQsIGVsZSwgYmIsIGZhbHNlLCBmYWxzZSwgdXNlRWxlT3BhY2l0eSk7XG4gICAgfTtcblxuICAgIHZhciBkcmF3TGFiZWwgPSBmdW5jdGlvbiBkcmF3TGFiZWwoY29udGV4dCwgZWxlLCBiYiwgc2NhbGVkTGFiZWxTaG93biwgdXNlRWxlT3BhY2l0eSkge1xuICAgICAgcmV0dXJuIHIuZHJhd0VsZW1lbnRUZXh0KGNvbnRleHQsIGVsZSwgYmIsIHNjYWxlZExhYmVsU2hvd24sICdtYWluJywgdXNlRWxlT3BhY2l0eSk7XG4gICAgfTtcblxuICAgIHZhciBkcmF3U291cmNlTGFiZWwgPSBmdW5jdGlvbiBkcmF3U291cmNlTGFiZWwoY29udGV4dCwgZWxlLCBiYiwgc2NhbGVkTGFiZWxTaG93biwgdXNlRWxlT3BhY2l0eSkge1xuICAgICAgcmV0dXJuIHIuZHJhd0VsZW1lbnRUZXh0KGNvbnRleHQsIGVsZSwgYmIsIHNjYWxlZExhYmVsU2hvd24sICdzb3VyY2UnLCB1c2VFbGVPcGFjaXR5KTtcbiAgICB9O1xuXG4gICAgdmFyIGRyYXdUYXJnZXRMYWJlbCA9IGZ1bmN0aW9uIGRyYXdUYXJnZXRMYWJlbChjb250ZXh0LCBlbGUsIGJiLCBzY2FsZWRMYWJlbFNob3duLCB1c2VFbGVPcGFjaXR5KSB7XG4gICAgICByZXR1cm4gci5kcmF3RWxlbWVudFRleHQoY29udGV4dCwgZWxlLCBiYiwgc2NhbGVkTGFiZWxTaG93biwgJ3RhcmdldCcsIHVzZUVsZU9wYWNpdHkpO1xuICAgIH07XG5cbiAgICB2YXIgZ2V0RWxlbWVudEJveCA9IGZ1bmN0aW9uIGdldEVsZW1lbnRCb3goZWxlKSB7XG4gICAgICBlbGUuYm91bmRpbmdCb3goKTtcbiAgICAgIHJldHVybiBlbGVbMF0uX3ByaXZhdGUuYm9keUJvdW5kcztcbiAgICB9O1xuXG4gICAgdmFyIGdldExhYmVsQm94ID0gZnVuY3Rpb24gZ2V0TGFiZWxCb3goZWxlKSB7XG4gICAgICBlbGUuYm91bmRpbmdCb3goKTtcbiAgICAgIHJldHVybiBlbGVbMF0uX3ByaXZhdGUubGFiZWxCb3VuZHMubWFpbiB8fCBlbXB0eUJiO1xuICAgIH07XG5cbiAgICB2YXIgZ2V0U291cmNlTGFiZWxCb3ggPSBmdW5jdGlvbiBnZXRTb3VyY2VMYWJlbEJveChlbGUpIHtcbiAgICAgIGVsZS5ib3VuZGluZ0JveCgpO1xuICAgICAgcmV0dXJuIGVsZVswXS5fcHJpdmF0ZS5sYWJlbEJvdW5kcy5zb3VyY2UgfHwgZW1wdHlCYjtcbiAgICB9O1xuXG4gICAgdmFyIGdldFRhcmdldExhYmVsQm94ID0gZnVuY3Rpb24gZ2V0VGFyZ2V0TGFiZWxCb3goZWxlKSB7XG4gICAgICBlbGUuYm91bmRpbmdCb3goKTtcbiAgICAgIHJldHVybiBlbGVbMF0uX3ByaXZhdGUubGFiZWxCb3VuZHMudGFyZ2V0IHx8IGVtcHR5QmI7XG4gICAgfTtcblxuICAgIHZhciBpc0xhYmVsVmlzaWJsZUF0U2NhbGUgPSBmdW5jdGlvbiBpc0xhYmVsVmlzaWJsZUF0U2NhbGUoZWxlLCBzY2FsZWRMYWJlbFNob3duKSB7XG4gICAgICByZXR1cm4gc2NhbGVkTGFiZWxTaG93bjtcbiAgICB9O1xuXG4gICAgdmFyIGdldEVsZW1lbnRSb3RhdGlvblBvaW50ID0gZnVuY3Rpb24gZ2V0RWxlbWVudFJvdGF0aW9uUG9pbnQoZWxlKSB7XG4gICAgICByZXR1cm4gZ2V0Qm94Q2VudGVyKGdldEVsZW1lbnRCb3goZWxlKSk7XG4gICAgfTtcblxuICAgIHZhciBhZGRUZXh0TWFyZ2luID0gZnVuY3Rpb24gYWRkVGV4dE1hcmdpbihwcmVmaXgsIHB0LCBlbGUpIHtcbiAgICAgIHZhciBwcmUgPSBwcmVmaXggPyBwcmVmaXggKyAnLScgOiAnJztcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHg6IHB0LnggKyBlbGUucHN0eWxlKHByZSArICd0ZXh0LW1hcmdpbi14JykucGZWYWx1ZSxcbiAgICAgICAgeTogcHQueSArIGVsZS5wc3R5bGUocHJlICsgJ3RleHQtbWFyZ2luLXknKS5wZlZhbHVlXG4gICAgICB9O1xuICAgIH07XG5cbiAgICB2YXIgZ2V0UnNQdCA9IGZ1bmN0aW9uIGdldFJzUHQoZWxlLCB4LCB5KSB7XG4gICAgICB2YXIgcnMgPSBlbGVbMF0uX3ByaXZhdGUucnNjcmF0Y2g7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB4OiByc1t4XSxcbiAgICAgICAgeTogcnNbeV1cbiAgICAgIH07XG4gICAgfTtcblxuICAgIHZhciBnZXRMYWJlbFJvdGF0aW9uUG9pbnQgPSBmdW5jdGlvbiBnZXRMYWJlbFJvdGF0aW9uUG9pbnQoZWxlKSB7XG4gICAgICByZXR1cm4gYWRkVGV4dE1hcmdpbignJywgZ2V0UnNQdChlbGUsICdsYWJlbFgnLCAnbGFiZWxZJyksIGVsZSk7XG4gICAgfTtcblxuICAgIHZhciBnZXRTb3VyY2VMYWJlbFJvdGF0aW9uUG9pbnQgPSBmdW5jdGlvbiBnZXRTb3VyY2VMYWJlbFJvdGF0aW9uUG9pbnQoZWxlKSB7XG4gICAgICByZXR1cm4gYWRkVGV4dE1hcmdpbignc291cmNlJywgZ2V0UnNQdChlbGUsICdzb3VyY2VMYWJlbFgnLCAnc291cmNlTGFiZWxZJyksIGVsZSk7XG4gICAgfTtcblxuICAgIHZhciBnZXRUYXJnZXRMYWJlbFJvdGF0aW9uUG9pbnQgPSBmdW5jdGlvbiBnZXRUYXJnZXRMYWJlbFJvdGF0aW9uUG9pbnQoZWxlKSB7XG4gICAgICByZXR1cm4gYWRkVGV4dE1hcmdpbigndGFyZ2V0JywgZ2V0UnNQdChlbGUsICd0YXJnZXRMYWJlbFgnLCAndGFyZ2V0TGFiZWxZJyksIGVsZSk7XG4gICAgfTtcblxuICAgIHZhciBnZXRFbGVtZW50Um90YXRpb25PZmZzZXQgPSBmdW5jdGlvbiBnZXRFbGVtZW50Um90YXRpb25PZmZzZXQoZWxlKSB7XG4gICAgICByZXR1cm4gZ2V0Q2VudGVyT2Zmc2V0KGdldEVsZW1lbnRCb3goZWxlKSk7XG4gICAgfTtcblxuICAgIHZhciBnZXRTb3VyY2VMYWJlbFJvdGF0aW9uT2Zmc2V0ID0gZnVuY3Rpb24gZ2V0U291cmNlTGFiZWxSb3RhdGlvbk9mZnNldChlbGUpIHtcbiAgICAgIHJldHVybiBnZXRDZW50ZXJPZmZzZXQoZ2V0U291cmNlTGFiZWxCb3goZWxlKSk7XG4gICAgfTtcblxuICAgIHZhciBnZXRUYXJnZXRMYWJlbFJvdGF0aW9uT2Zmc2V0ID0gZnVuY3Rpb24gZ2V0VGFyZ2V0TGFiZWxSb3RhdGlvbk9mZnNldChlbGUpIHtcbiAgICAgIHJldHVybiBnZXRDZW50ZXJPZmZzZXQoZ2V0VGFyZ2V0TGFiZWxCb3goZWxlKSk7XG4gICAgfTtcblxuICAgIHZhciBnZXRMYWJlbFJvdGF0aW9uT2Zmc2V0ID0gZnVuY3Rpb24gZ2V0TGFiZWxSb3RhdGlvbk9mZnNldChlbGUpIHtcbiAgICAgIHZhciBiYiA9IGdldExhYmVsQm94KGVsZSk7XG4gICAgICB2YXIgcCA9IGdldENlbnRlck9mZnNldChnZXRMYWJlbEJveChlbGUpKTtcblxuICAgICAgaWYgKGVsZS5pc05vZGUoKSkge1xuICAgICAgICBzd2l0Y2ggKGVsZS5wc3R5bGUoJ3RleHQtaGFsaWduJykudmFsdWUpIHtcbiAgICAgICAgICBjYXNlICdsZWZ0JzpcbiAgICAgICAgICAgIHAueCA9IC1iYi53O1xuICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICBjYXNlICdyaWdodCc6XG4gICAgICAgICAgICBwLnggPSAwO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBzd2l0Y2ggKGVsZS5wc3R5bGUoJ3RleHQtdmFsaWduJykudmFsdWUpIHtcbiAgICAgICAgICBjYXNlICd0b3AnOlxuICAgICAgICAgICAgcC55ID0gLWJiLmg7XG4gICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgIGNhc2UgJ2JvdHRvbSc6XG4gICAgICAgICAgICBwLnkgPSAwO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHA7XG4gICAgfTtcblxuICAgIHZhciBlbGVUeHJDYWNoZSA9IHIuZGF0YS5lbGVUeHJDYWNoZSA9IG5ldyBFbGVtZW50VGV4dHVyZUNhY2hlKHIsIHtcbiAgICAgIGdldEtleTogZ2V0U3R5bGVLZXksXG4gICAgICBkb2VzRWxlSW52YWxpZGF0ZUtleTogYmFja2dyb3VuZFRpbWVzdGFtcEhhc0NoYW5nZWQsXG4gICAgICBkcmF3RWxlbWVudDogZHJhd0VsZW1lbnQsXG4gICAgICBnZXRCb3VuZGluZ0JveDogZ2V0RWxlbWVudEJveCxcbiAgICAgIGdldFJvdGF0aW9uUG9pbnQ6IGdldEVsZW1lbnRSb3RhdGlvblBvaW50LFxuICAgICAgZ2V0Um90YXRpb25PZmZzZXQ6IGdldEVsZW1lbnRSb3RhdGlvbk9mZnNldCxcbiAgICAgIGFsbG93RWRnZVR4ckNhY2hpbmc6IGZhbHNlLFxuICAgICAgYWxsb3dQYXJlbnRUeHJDYWNoaW5nOiBmYWxzZVxuICAgIH0pO1xuICAgIHZhciBsYmxUeHJDYWNoZSA9IHIuZGF0YS5sYmxUeHJDYWNoZSA9IG5ldyBFbGVtZW50VGV4dHVyZUNhY2hlKHIsIHtcbiAgICAgIGdldEtleTogZ2V0TGFiZWxLZXksXG4gICAgICBkcmF3RWxlbWVudDogZHJhd0xhYmVsLFxuICAgICAgZ2V0Qm91bmRpbmdCb3g6IGdldExhYmVsQm94LFxuICAgICAgZ2V0Um90YXRpb25Qb2ludDogZ2V0TGFiZWxSb3RhdGlvblBvaW50LFxuICAgICAgZ2V0Um90YXRpb25PZmZzZXQ6IGdldExhYmVsUm90YXRpb25PZmZzZXQsXG4gICAgICBpc1Zpc2libGU6IGlzTGFiZWxWaXNpYmxlQXRTY2FsZVxuICAgIH0pO1xuICAgIHZhciBzbGJUeHJDYWNoZSA9IHIuZGF0YS5zbGJUeHJDYWNoZSA9IG5ldyBFbGVtZW50VGV4dHVyZUNhY2hlKHIsIHtcbiAgICAgIGdldEtleTogZ2V0U291cmNlTGFiZWxLZXksXG4gICAgICBkcmF3RWxlbWVudDogZHJhd1NvdXJjZUxhYmVsLFxuICAgICAgZ2V0Qm91bmRpbmdCb3g6IGdldFNvdXJjZUxhYmVsQm94LFxuICAgICAgZ2V0Um90YXRpb25Qb2ludDogZ2V0U291cmNlTGFiZWxSb3RhdGlvblBvaW50LFxuICAgICAgZ2V0Um90YXRpb25PZmZzZXQ6IGdldFNvdXJjZUxhYmVsUm90YXRpb25PZmZzZXQsXG4gICAgICBpc1Zpc2libGU6IGlzTGFiZWxWaXNpYmxlQXRTY2FsZVxuICAgIH0pO1xuICAgIHZhciB0bGJUeHJDYWNoZSA9IHIuZGF0YS50bGJUeHJDYWNoZSA9IG5ldyBFbGVtZW50VGV4dHVyZUNhY2hlKHIsIHtcbiAgICAgIGdldEtleTogZ2V0VGFyZ2V0TGFiZWxLZXksXG4gICAgICBkcmF3RWxlbWVudDogZHJhd1RhcmdldExhYmVsLFxuICAgICAgZ2V0Qm91bmRpbmdCb3g6IGdldFRhcmdldExhYmVsQm94LFxuICAgICAgZ2V0Um90YXRpb25Qb2ludDogZ2V0VGFyZ2V0TGFiZWxSb3RhdGlvblBvaW50LFxuICAgICAgZ2V0Um90YXRpb25PZmZzZXQ6IGdldFRhcmdldExhYmVsUm90YXRpb25PZmZzZXQsXG4gICAgICBpc1Zpc2libGU6IGlzTGFiZWxWaXNpYmxlQXRTY2FsZVxuICAgIH0pO1xuICAgIHZhciBseXJUeHJDYWNoZSA9IHIuZGF0YS5seXJUeHJDYWNoZSA9IG5ldyBMYXllcmVkVGV4dHVyZUNhY2hlKHIpO1xuICAgIHIub25VcGRhdGVFbGVDYWxjcyhmdW5jdGlvbiBpbnZhbGlkYXRlVGV4dHVyZUNhY2hlcyh3aWxsRHJhdywgZWxlcykge1xuICAgICAgLy8gZWFjaCBjYWNoZSBzaG91bGQgY2hlY2sgZm9yIHN1Yi1rZXkgZGlmZiB0byBzZWUgdGhhdCB0aGUgdXBkYXRlIGFmZmVjdHMgdGhhdCBjYWNoZSBwYXJ0aWN1bGFybHlcbiAgICAgIGVsZVR4ckNhY2hlLmludmFsaWRhdGVFbGVtZW50cyhlbGVzKTtcbiAgICAgIGxibFR4ckNhY2hlLmludmFsaWRhdGVFbGVtZW50cyhlbGVzKTtcbiAgICAgIHNsYlR4ckNhY2hlLmludmFsaWRhdGVFbGVtZW50cyhlbGVzKTtcbiAgICAgIHRsYlR4ckNhY2hlLmludmFsaWRhdGVFbGVtZW50cyhlbGVzKTsgLy8gYW55IGNoYW5nZSBpbnZhbGlkYXRlcyB0aGUgbGF5ZXJzXG5cbiAgICAgIGx5clR4ckNhY2hlLmludmFsaWRhdGVFbGVtZW50cyhlbGVzKTsgLy8gdXBkYXRlIHRoZSBvbGQgYmcgdGltZXN0YW1wIHNvIGRpZmZzIGNhbiBiZSBkb25lIGluIHRoZSBlbGUgdHhyIGNhY2hlc1xuXG4gICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgZWxlcy5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIF9wID0gZWxlc1tfaV0uX3ByaXZhdGU7XG4gICAgICAgIF9wLm9sZEJhY2tncm91bmRUaW1lc3RhbXAgPSBfcC5iYWNrZ3JvdW5kVGltZXN0YW1wO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIHJlZmluZUluTGF5ZXJzID0gZnVuY3Rpb24gcmVmaW5lSW5MYXllcnMocmVxcykge1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZXFzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGx5clR4ckNhY2hlLmVucXVldWVFbGVtZW50UmVmaW5lbWVudChyZXFzW2ldLmVsZSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIGVsZVR4ckNhY2hlLm9uRGVxdWV1ZShyZWZpbmVJbkxheWVycyk7XG4gICAgbGJsVHhyQ2FjaGUub25EZXF1ZXVlKHJlZmluZUluTGF5ZXJzKTtcbiAgICBzbGJUeHJDYWNoZS5vbkRlcXVldWUocmVmaW5lSW5MYXllcnMpO1xuICAgIHRsYlR4ckNhY2hlLm9uRGVxdWV1ZShyZWZpbmVJbkxheWVycyk7XG4gIH1cblxuICBDUnAucmVkcmF3SGludCA9IGZ1bmN0aW9uIChncm91cCwgYm9vbCkge1xuICAgIHZhciByID0gdGhpcztcblxuICAgIHN3aXRjaCAoZ3JvdXApIHtcbiAgICAgIGNhc2UgJ2VsZXMnOlxuICAgICAgICByLmRhdGEuY2FudmFzTmVlZHNSZWRyYXdbQ1JwLk5PREVdID0gYm9vbDtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ2RyYWcnOlxuICAgICAgICByLmRhdGEuY2FudmFzTmVlZHNSZWRyYXdbQ1JwLkRSQUddID0gYm9vbDtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ3NlbGVjdCc6XG4gICAgICAgIHIuZGF0YS5jYW52YXNOZWVkc1JlZHJhd1tDUnAuU0VMRUNUX0JPWF0gPSBib29sO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH07IC8vIHdoZXRoZXIgdG8gdXNlIFBhdGgyRCBjYWNoaW5nIGZvciBkcmF3aW5nXG5cblxuICB2YXIgcGF0aHNJbXBsZCA9IHR5cGVvZiBQYXRoMkQgIT09ICd1bmRlZmluZWQnO1xuXG4gIENScC5wYXRoMmRFbmFibGVkID0gZnVuY3Rpb24gKG9uKSB7XG4gICAgaWYgKG9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB0aGlzLnBhdGhzRW5hYmxlZDtcbiAgICB9XG5cbiAgICB0aGlzLnBhdGhzRW5hYmxlZCA9IG9uID8gdHJ1ZSA6IGZhbHNlO1xuICB9O1xuXG4gIENScC51c2VQYXRocyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gcGF0aHNJbXBsZCAmJiB0aGlzLnBhdGhzRW5hYmxlZDtcbiAgfTtcblxuICBDUnAuc2V0SW1nU21vb3RoaW5nID0gZnVuY3Rpb24gKGNvbnRleHQsIGJvb2wpIHtcbiAgICBpZiAoY29udGV4dC5pbWFnZVNtb290aGluZ0VuYWJsZWQgIT0gbnVsbCkge1xuICAgICAgY29udGV4dC5pbWFnZVNtb290aGluZ0VuYWJsZWQgPSBib29sO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb250ZXh0LndlYmtpdEltYWdlU21vb3RoaW5nRW5hYmxlZCA9IGJvb2w7XG4gICAgICBjb250ZXh0Lm1vekltYWdlU21vb3RoaW5nRW5hYmxlZCA9IGJvb2w7XG4gICAgICBjb250ZXh0Lm1zSW1hZ2VTbW9vdGhpbmdFbmFibGVkID0gYm9vbDtcbiAgICB9XG4gIH07XG5cbiAgQ1JwLmdldEltZ1Ntb290aGluZyA9IGZ1bmN0aW9uIChjb250ZXh0KSB7XG4gICAgaWYgKGNvbnRleHQuaW1hZ2VTbW9vdGhpbmdFbmFibGVkICE9IG51bGwpIHtcbiAgICAgIHJldHVybiBjb250ZXh0LmltYWdlU21vb3RoaW5nRW5hYmxlZDtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGNvbnRleHQud2Via2l0SW1hZ2VTbW9vdGhpbmdFbmFibGVkIHx8IGNvbnRleHQubW96SW1hZ2VTbW9vdGhpbmdFbmFibGVkIHx8IGNvbnRleHQubXNJbWFnZVNtb290aGluZ0VuYWJsZWQ7XG4gICAgfVxuICB9O1xuXG4gIENScC5tYWtlT2Zmc2NyZWVuQ2FudmFzID0gZnVuY3Rpb24gKHdpZHRoLCBoZWlnaHQpIHtcbiAgICB2YXIgY2FudmFzO1xuXG4gICAgaWYgKCh0eXBlb2YgT2Zmc2NyZWVuQ2FudmFzID09PSBcInVuZGVmaW5lZFwiID8gXCJ1bmRlZmluZWRcIiA6IF90eXBlb2YoT2Zmc2NyZWVuQ2FudmFzKSkgIT09IChcInVuZGVmaW5lZFwiICkpIHtcbiAgICAgIGNhbnZhcyA9IG5ldyBPZmZzY3JlZW5DYW52YXMod2lkdGgsIGhlaWdodCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cbiAgICAgIGNhbnZhcy53aWR0aCA9IHdpZHRoO1xuICAgICAgY2FudmFzLmhlaWdodCA9IGhlaWdodDtcbiAgICB9XG5cbiAgICByZXR1cm4gY2FudmFzO1xuICB9O1xuXG4gIFtDUnAkYSwgQ1JwJDksIENScCQ4LCBDUnAkNywgQ1JwJDYsIENScCQ1LCBDUnAkNCwgQ1JwJDMsIENScCQyLCBDUnAkMV0uZm9yRWFjaChmdW5jdGlvbiAocHJvcHMpIHtcbiAgICBleHRlbmQoQ1JwLCBwcm9wcyk7XG4gIH0pO1xuXG4gIHZhciByZW5kZXJlciA9IFt7XG4gICAgbmFtZTogJ251bGwnLFxuICAgIGltcGw6IE51bGxSZW5kZXJlclxuICB9LCB7XG4gICAgbmFtZTogJ2Jhc2UnLFxuICAgIGltcGw6IEJSXG4gIH0sIHtcbiAgICBuYW1lOiAnY2FudmFzJyxcbiAgICBpbXBsOiBDUlxuICB9XTtcblxuICB2YXIgaW5jRXh0cyA9IFt7XG4gICAgdHlwZTogJ2xheW91dCcsXG4gICAgZXh0ZW5zaW9uczogbGF5b3V0XG4gIH0sIHtcbiAgICB0eXBlOiAncmVuZGVyZXInLFxuICAgIGV4dGVuc2lvbnM6IHJlbmRlcmVyXG4gIH1dO1xuXG4gIHZhciBleHRlbnNpb25zID0ge307IC8vIHJlZ2lzdGVyZWQgbW9kdWxlcyBmb3IgZXh0ZW5zaW9ucywgaW5kZXhlZCBieSBuYW1lXG5cbiAgdmFyIG1vZHVsZXMgPSB7fTtcblxuICBmdW5jdGlvbiBzZXRFeHRlbnNpb24odHlwZSwgbmFtZSwgcmVnaXN0cmFudCkge1xuICAgIHZhciBleHQgPSByZWdpc3RyYW50O1xuXG4gICAgdmFyIG92ZXJyaWRlRXJyID0gZnVuY3Rpb24gb3ZlcnJpZGVFcnIoZmllbGQpIHtcbiAgICAgIHdhcm4oJ0NhbiBub3QgcmVnaXN0ZXIgYCcgKyBuYW1lICsgJ2AgZm9yIGAnICsgdHlwZSArICdgIHNpbmNlIGAnICsgZmllbGQgKyAnYCBhbHJlYWR5IGV4aXN0cyBpbiB0aGUgcHJvdG90eXBlIGFuZCBjYW4gbm90IGJlIG92ZXJyaWRkZW4nKTtcbiAgICB9O1xuXG4gICAgaWYgKHR5cGUgPT09ICdjb3JlJykge1xuICAgICAgaWYgKENvcmUucHJvdG90eXBlW25hbWVdKSB7XG4gICAgICAgIHJldHVybiBvdmVycmlkZUVycihuYW1lKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIENvcmUucHJvdG90eXBlW25hbWVdID0gcmVnaXN0cmFudDtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdjb2xsZWN0aW9uJykge1xuICAgICAgaWYgKENvbGxlY3Rpb24ucHJvdG90eXBlW25hbWVdKSB7XG4gICAgICAgIHJldHVybiBvdmVycmlkZUVycihuYW1lKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIENvbGxlY3Rpb24ucHJvdG90eXBlW25hbWVdID0gcmVnaXN0cmFudDtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdsYXlvdXQnKSB7XG4gICAgICAvLyBmaWxsIGluIG1pc3NpbmcgbGF5b3V0IGZ1bmN0aW9ucyBpbiB0aGUgcHJvdG90eXBlXG4gICAgICB2YXIgTGF5b3V0ID0gZnVuY3Rpb24gTGF5b3V0KG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICAgICAgcmVnaXN0cmFudC5jYWxsKHRoaXMsIG9wdGlvbnMpOyAvLyBtYWtlIHN1cmUgbGF5b3V0IGhhcyBfcHJpdmF0ZSBmb3IgdXNlIHcvIHN0ZCBhcGlzIGxpa2UgLm9uKClcblxuICAgICAgICBpZiAoIXBsYWluT2JqZWN0KHRoaXMuX3ByaXZhdGUpKSB7XG4gICAgICAgICAgdGhpcy5fcHJpdmF0ZSA9IHt9O1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fcHJpdmF0ZS5jeSA9IG9wdGlvbnMuY3k7XG4gICAgICAgIHRoaXMuX3ByaXZhdGUubGlzdGVuZXJzID0gW107XG4gICAgICAgIHRoaXMuY3JlYXRlRW1pdHRlcigpO1xuICAgICAgfTtcblxuICAgICAgdmFyIGxheW91dFByb3RvID0gTGF5b3V0LnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUocmVnaXN0cmFudC5wcm90b3R5cGUpO1xuICAgICAgdmFyIG9wdExheW91dEZucyA9IFtdO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG9wdExheW91dEZucy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgZm5OYW1lID0gb3B0TGF5b3V0Rm5zW2ldO1xuXG4gICAgICAgIGxheW91dFByb3RvW2ZuTmFtZV0gPSBsYXlvdXRQcm90b1tmbk5hbWVdIHx8IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfTtcbiAgICAgIH0gLy8gZWl0aGVyIC5zdGFydCgpIG9yIC5ydW4oKSBpcyBkZWZpbmVkLCBzbyBhdXRvZ2VuIHRoZSBvdGhlclxuXG5cbiAgICAgIGlmIChsYXlvdXRQcm90by5zdGFydCAmJiAhbGF5b3V0UHJvdG8ucnVuKSB7XG4gICAgICAgIGxheW91dFByb3RvLnJ1biA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICB0aGlzLnN0YXJ0KCk7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgICB9IGVsc2UgaWYgKCFsYXlvdXRQcm90by5zdGFydCAmJiBsYXlvdXRQcm90by5ydW4pIHtcbiAgICAgICAgbGF5b3V0UHJvdG8uc3RhcnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgdGhpcy5ydW4oKTtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgdmFyIHJlZ1N0b3AgPSByZWdpc3RyYW50LnByb3RvdHlwZS5zdG9wO1xuXG4gICAgICBsYXlvdXRQcm90by5zdG9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgb3B0cyA9IHRoaXMub3B0aW9ucztcblxuICAgICAgICBpZiAob3B0cyAmJiBvcHRzLmFuaW1hdGUpIHtcbiAgICAgICAgICB2YXIgYW5pcyA9IHRoaXMuYW5pbWF0aW9ucztcblxuICAgICAgICAgIGlmIChhbmlzKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgYW5pcy5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgICAgYW5pc1tfaV0uc3RvcCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyZWdTdG9wKSB7XG4gICAgICAgICAgcmVnU3RvcC5jYWxsKHRoaXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuZW1pdCgnbGF5b3V0c3RvcCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9O1xuXG4gICAgICBpZiAoIWxheW91dFByb3RvLmRlc3Ryb3kpIHtcbiAgICAgICAgbGF5b3V0UHJvdG8uZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgbGF5b3V0UHJvdG8uY3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wcml2YXRlLmN5O1xuICAgICAgfTtcblxuICAgICAgdmFyIGdldEN5ID0gZnVuY3Rpb24gZ2V0Q3kobGF5b3V0KSB7XG4gICAgICAgIHJldHVybiBsYXlvdXQuX3ByaXZhdGUuY3k7XG4gICAgICB9O1xuXG4gICAgICB2YXIgZW1pdHRlck9wdHMgPSB7XG4gICAgICAgIGFkZEV2ZW50RmllbGRzOiBmdW5jdGlvbiBhZGRFdmVudEZpZWxkcyhsYXlvdXQsIGV2dCkge1xuICAgICAgICAgIGV2dC5sYXlvdXQgPSBsYXlvdXQ7XG4gICAgICAgICAgZXZ0LmN5ID0gZ2V0Q3kobGF5b3V0KTtcbiAgICAgICAgICBldnQudGFyZ2V0ID0gbGF5b3V0O1xuICAgICAgICB9LFxuICAgICAgICBidWJibGU6IGZ1bmN0aW9uIGJ1YmJsZSgpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgcGFyZW50OiBmdW5jdGlvbiBwYXJlbnQobGF5b3V0KSB7XG4gICAgICAgICAgcmV0dXJuIGdldEN5KGxheW91dCk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICBleHRlbmQobGF5b3V0UHJvdG8sIHtcbiAgICAgICAgY3JlYXRlRW1pdHRlcjogZnVuY3Rpb24gY3JlYXRlRW1pdHRlcigpIHtcbiAgICAgICAgICB0aGlzLl9wcml2YXRlLmVtaXR0ZXIgPSBuZXcgRW1pdHRlcihlbWl0dGVyT3B0cywgdGhpcyk7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG4gICAgICAgIGVtaXR0ZXI6IGZ1bmN0aW9uIGVtaXR0ZXIoKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMuX3ByaXZhdGUuZW1pdHRlcjtcbiAgICAgICAgfSxcbiAgICAgICAgb246IGZ1bmN0aW9uIG9uKGV2dCwgY2IpIHtcbiAgICAgICAgICB0aGlzLmVtaXR0ZXIoKS5vbihldnQsIGNiKTtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcbiAgICAgICAgb25lOiBmdW5jdGlvbiBvbmUoZXZ0LCBjYikge1xuICAgICAgICAgIHRoaXMuZW1pdHRlcigpLm9uZShldnQsIGNiKTtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcbiAgICAgICAgb25jZTogZnVuY3Rpb24gb25jZShldnQsIGNiKSB7XG4gICAgICAgICAgdGhpcy5lbWl0dGVyKCkub25lKGV2dCwgY2IpO1xuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuICAgICAgICByZW1vdmVMaXN0ZW5lcjogZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXIoZXZ0LCBjYikge1xuICAgICAgICAgIHRoaXMuZW1pdHRlcigpLnJlbW92ZUxpc3RlbmVyKGV2dCwgY2IpO1xuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuICAgICAgICByZW1vdmVBbGxMaXN0ZW5lcnM6IGZ1bmN0aW9uIHJlbW92ZUFsbExpc3RlbmVycygpIHtcbiAgICAgICAgICB0aGlzLmVtaXR0ZXIoKS5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcbiAgICAgICAgZW1pdDogZnVuY3Rpb24gZW1pdChldnQsIHBhcmFtcykge1xuICAgICAgICAgIHRoaXMuZW1pdHRlcigpLmVtaXQoZXZ0LCBwYXJhbXMpO1xuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGRlZmluZS5ldmVudEFsaWFzZXNPbihsYXlvdXRQcm90byk7XG4gICAgICBleHQgPSBMYXlvdXQ7IC8vIHJlcGxhY2Ugd2l0aCBvdXIgd3JhcHBlZCBsYXlvdXRcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdyZW5kZXJlcicgJiYgbmFtZSAhPT0gJ251bGwnICYmIG5hbWUgIT09ICdiYXNlJykge1xuICAgICAgLy8gdXNlciByZWdpc3RlcmVkIHJlbmRlcmVycyBpbmhlcml0IGZyb20gYmFzZVxuICAgICAgdmFyIEJhc2VSZW5kZXJlciA9IGdldEV4dGVuc2lvbigncmVuZGVyZXInLCAnYmFzZScpO1xuICAgICAgdmFyIGJQcm90byA9IEJhc2VSZW5kZXJlci5wcm90b3R5cGU7XG4gICAgICB2YXIgUmVnaXN0cmFudFJlbmRlcmVyID0gcmVnaXN0cmFudDtcbiAgICAgIHZhciByUHJvdG8gPSByZWdpc3RyYW50LnByb3RvdHlwZTtcblxuICAgICAgdmFyIFJlbmRlcmVyID0gZnVuY3Rpb24gUmVuZGVyZXIoKSB7XG4gICAgICAgIEJhc2VSZW5kZXJlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICBSZWdpc3RyYW50UmVuZGVyZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgIH07XG5cbiAgICAgIHZhciBwcm90byA9IFJlbmRlcmVyLnByb3RvdHlwZTtcblxuICAgICAgZm9yICh2YXIgcE5hbWUgaW4gYlByb3RvKSB7XG4gICAgICAgIHZhciBwVmFsID0gYlByb3RvW3BOYW1lXTtcbiAgICAgICAgdmFyIGV4aXN0c0luUiA9IHJQcm90b1twTmFtZV0gIT0gbnVsbDtcblxuICAgICAgICBpZiAoZXhpc3RzSW5SKSB7XG4gICAgICAgICAgcmV0dXJuIG92ZXJyaWRlRXJyKHBOYW1lKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHByb3RvW3BOYW1lXSA9IHBWYWw7IC8vIHRha2UgaW1wbCBmcm9tIGJhc2VcbiAgICAgIH1cblxuICAgICAgZm9yICh2YXIgX3BOYW1lIGluIHJQcm90bykge1xuICAgICAgICBwcm90b1tfcE5hbWVdID0gclByb3RvW19wTmFtZV07IC8vIHRha2UgaW1wbCBmcm9tIHJlZ2lzdHJhbnRcbiAgICAgIH1cblxuICAgICAgYlByb3RvLmNsaWVudEZ1bmN0aW9ucy5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgIHByb3RvW25hbWVdID0gcHJvdG9bbmFtZV0gfHwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGVycm9yKCdSZW5kZXJlciBkb2VzIG5vdCBpbXBsZW1lbnQgYHJlbmRlcmVyLicgKyBuYW1lICsgJygpYCBvbiBpdHMgcHJvdG90eXBlJyk7XG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICAgIGV4dCA9IFJlbmRlcmVyO1xuICAgIH0gZWxzZSBpZiAodHlwZSA9PT0gJ19fcHJvdG9fXycgfHwgdHlwZSA9PT0gJ2NvbnN0cnVjdG9yJyB8fCB0eXBlID09PSAncHJvdG90eXBlJykge1xuICAgICAgLy8gdG8gYXZvaWQgcG90ZW50aWFsIHByb3RvdHlwZSBwb2xsdXRpb25cbiAgICAgIHJldHVybiBlcnJvcih0eXBlICsgJyBpcyBhbiBpbGxlZ2FsIHR5cGUgdG8gYmUgcmVnaXN0ZXJlZCwgcG9zc2libHkgbGVhZCB0byBwcm90b3R5cGUgcG9sbHV0aW9ucycpO1xuICAgIH1cblxuICAgIHJldHVybiBzZXRNYXAoe1xuICAgICAgbWFwOiBleHRlbnNpb25zLFxuICAgICAga2V5czogW3R5cGUsIG5hbWVdLFxuICAgICAgdmFsdWU6IGV4dFxuICAgIH0pO1xuICB9XG5cbiAgZnVuY3Rpb24gZ2V0RXh0ZW5zaW9uKHR5cGUsIG5hbWUpIHtcbiAgICByZXR1cm4gZ2V0TWFwKHtcbiAgICAgIG1hcDogZXh0ZW5zaW9ucyxcbiAgICAgIGtleXM6IFt0eXBlLCBuYW1lXVxuICAgIH0pO1xuICB9XG5cbiAgZnVuY3Rpb24gc2V0TW9kdWxlKHR5cGUsIG5hbWUsIG1vZHVsZVR5cGUsIG1vZHVsZU5hbWUsIHJlZ2lzdHJhbnQpIHtcbiAgICByZXR1cm4gc2V0TWFwKHtcbiAgICAgIG1hcDogbW9kdWxlcyxcbiAgICAgIGtleXM6IFt0eXBlLCBuYW1lLCBtb2R1bGVUeXBlLCBtb2R1bGVOYW1lXSxcbiAgICAgIHZhbHVlOiByZWdpc3RyYW50XG4gICAgfSk7XG4gIH1cblxuICBmdW5jdGlvbiBnZXRNb2R1bGUodHlwZSwgbmFtZSwgbW9kdWxlVHlwZSwgbW9kdWxlTmFtZSkge1xuICAgIHJldHVybiBnZXRNYXAoe1xuICAgICAgbWFwOiBtb2R1bGVzLFxuICAgICAga2V5czogW3R5cGUsIG5hbWUsIG1vZHVsZVR5cGUsIG1vZHVsZU5hbWVdXG4gICAgfSk7XG4gIH1cblxuICB2YXIgZXh0ZW5zaW9uID0gZnVuY3Rpb24gZXh0ZW5zaW9uKCkge1xuICAgIC8vIGUuZy4gZXh0ZW5zaW9uKCdyZW5kZXJlcicsICdzdmcnKVxuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAyKSB7XG4gICAgICByZXR1cm4gZ2V0RXh0ZW5zaW9uLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgfSAvLyBlLmcuIGV4dGVuc2lvbigncmVuZGVyZXInLCAnc3ZnJywgeyAuLi4gfSlcbiAgICBlbHNlIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAzKSB7XG4gICAgICByZXR1cm4gc2V0RXh0ZW5zaW9uLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgfSAvLyBlLmcuIGV4dGVuc2lvbigncmVuZGVyZXInLCAnc3ZnJywgJ25vZGVTaGFwZScsICdlbGxpcHNlJylcbiAgICBlbHNlIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSA0KSB7XG4gICAgICByZXR1cm4gZ2V0TW9kdWxlLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgfSAvLyBlLmcuIGV4dGVuc2lvbigncmVuZGVyZXInLCAnc3ZnJywgJ25vZGVTaGFwZScsICdlbGxpcHNlJywgeyAuLi4gfSlcbiAgICBlbHNlIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSA1KSB7XG4gICAgICByZXR1cm4gc2V0TW9kdWxlLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGVycm9yKCdJbnZhbGlkIGV4dGVuc2lvbiBhY2Nlc3Mgc3ludGF4Jyk7XG4gICAgfVxuICB9OyAvLyBhbGxvd3MgYSBjb3JlIGluc3RhbmNlIHRvIGFjY2VzcyBleHRlbnNpb25zIGludGVybmFsbHlcblxuXG4gIENvcmUucHJvdG90eXBlLmV4dGVuc2lvbiA9IGV4dGVuc2lvbjsgLy8gaW5jbHVkZWQgZXh0ZW5zaW9uc1xuXG4gIGluY0V4dHMuZm9yRWFjaChmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICBncm91cC5leHRlbnNpb25zLmZvckVhY2goZnVuY3Rpb24gKGV4dCkge1xuICAgICAgc2V0RXh0ZW5zaW9uKGdyb3VwLnR5cGUsIGV4dC5uYW1lLCBleHQuaW1wbCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vICh1c2VmdWwgZm9yIGluaXQpXG5cbiAgdmFyIFN0eWxlc2hlZXQgPSBmdW5jdGlvbiBTdHlsZXNoZWV0KCkge1xuICAgIGlmICghKHRoaXMgaW5zdGFuY2VvZiBTdHlsZXNoZWV0KSkge1xuICAgICAgcmV0dXJuIG5ldyBTdHlsZXNoZWV0KCk7XG4gICAgfVxuXG4gICAgdGhpcy5sZW5ndGggPSAwO1xuICB9O1xuXG4gIHZhciBzaGVldGZuID0gU3R5bGVzaGVldC5wcm90b3R5cGU7XG5cbiAgc2hlZXRmbi5pbnN0YW5jZVN0cmluZyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gJ3N0eWxlc2hlZXQnO1xuICB9OyAvLyBqdXN0IHN0b3JlIHRoZSBzZWxlY3RvciB0byBiZSBwYXJzZWQgbGF0ZXJcblxuXG4gIHNoZWV0Zm4uc2VsZWN0b3IgPSBmdW5jdGlvbiAoc2VsZWN0b3IpIHtcbiAgICB2YXIgaSA9IHRoaXMubGVuZ3RoKys7XG4gICAgdGhpc1tpXSA9IHtcbiAgICAgIHNlbGVjdG9yOiBzZWxlY3RvcixcbiAgICAgIHByb3BlcnRpZXM6IFtdXG4gICAgfTtcbiAgICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbiAgfTsgLy8ganVzdCBzdG9yZSB0aGUgcHJvcGVydHkgdG8gYmUgcGFyc2VkIGxhdGVyXG5cblxuICBzaGVldGZuLmNzcyA9IGZ1bmN0aW9uIChuYW1lLCB2YWx1ZSkge1xuICAgIHZhciBpID0gdGhpcy5sZW5ndGggLSAxO1xuXG4gICAgaWYgKHN0cmluZyhuYW1lKSkge1xuICAgICAgdGhpc1tpXS5wcm9wZXJ0aWVzLnB1c2goe1xuICAgICAgICBuYW1lOiBuYW1lLFxuICAgICAgICB2YWx1ZTogdmFsdWVcbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAocGxhaW5PYmplY3QobmFtZSkpIHtcbiAgICAgIHZhciBtYXAgPSBuYW1lO1xuICAgICAgdmFyIHByb3BOYW1lcyA9IE9iamVjdC5rZXlzKG1hcCk7XG5cbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgcHJvcE5hbWVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHZhciBrZXkgPSBwcm9wTmFtZXNbal07XG4gICAgICAgIHZhciBtYXBWYWwgPSBtYXBba2V5XTtcblxuICAgICAgICBpZiAobWFwVmFsID09IG51bGwpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBwcm9wID0gU3R5bGUucHJvcGVydGllc1trZXldIHx8IFN0eWxlLnByb3BlcnRpZXNbZGFzaDJjYW1lbChrZXkpXTtcblxuICAgICAgICBpZiAocHJvcCA9PSBudWxsKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgX25hbWUgPSBwcm9wLm5hbWU7XG4gICAgICAgIHZhciBfdmFsdWUgPSBtYXBWYWw7XG4gICAgICAgIHRoaXNbaV0ucHJvcGVydGllcy5wdXNoKHtcbiAgICAgICAgICBuYW1lOiBfbmFtZSxcbiAgICAgICAgICB2YWx1ZTogX3ZhbHVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzOyAvLyBjaGFpbmluZ1xuICB9O1xuXG4gIHNoZWV0Zm4uc3R5bGUgPSBzaGVldGZuLmNzczsgLy8gZ2VuZXJhdGUgYSByZWFsIHN0eWxlIG9iamVjdCBmcm9tIHRoZSBkdW1teSBzdHlsZXNoZWV0XG5cbiAgc2hlZXRmbi5nZW5lcmF0ZVN0eWxlID0gZnVuY3Rpb24gKGN5KSB7XG4gICAgdmFyIHN0eWxlID0gbmV3IFN0eWxlKGN5KTtcbiAgICByZXR1cm4gdGhpcy5hcHBlbmRUb1N0eWxlKHN0eWxlKTtcbiAgfTsgLy8gYXBwZW5kIGEgZHVtbXkgc3R5bGVzaGVldCBvYmplY3Qgb24gYSByZWFsIHN0eWxlIG9iamVjdFxuXG5cbiAgc2hlZXRmbi5hcHBlbmRUb1N0eWxlID0gZnVuY3Rpb24gKHN0eWxlKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgY29udGV4dCA9IHRoaXNbaV07XG4gICAgICB2YXIgc2VsZWN0b3IgPSBjb250ZXh0LnNlbGVjdG9yO1xuICAgICAgdmFyIHByb3BzID0gY29udGV4dC5wcm9wZXJ0aWVzO1xuICAgICAgc3R5bGUuc2VsZWN0b3Ioc2VsZWN0b3IpOyAvLyBhcHBseSBzZWxlY3RvclxuXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHByb3BzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHZhciBwcm9wID0gcHJvcHNbal07XG4gICAgICAgIHN0eWxlLmNzcyhwcm9wLm5hbWUsIHByb3AudmFsdWUpOyAvLyBhcHBseSBwcm9wZXJ0eVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBzdHlsZTtcbiAgfTtcblxuICB2YXIgdmVyc2lvbiA9IFwiMy4yNi4wXCI7XG5cbiAgdmFyIGN5dG9zY2FwZSA9IGZ1bmN0aW9uIGN5dG9zY2FwZShvcHRpb25zKSB7XG4gICAgLy8gaWYgbm8gb3B0aW9ucyBzcGVjaWZpZWQsIHVzZSBkZWZhdWx0XG4gICAgaWYgKG9wdGlvbnMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgb3B0aW9ucyA9IHt9O1xuICAgIH0gLy8gY3JlYXRlIGluc3RhbmNlXG5cblxuICAgIGlmIChwbGFpbk9iamVjdChvcHRpb25zKSkge1xuICAgICAgcmV0dXJuIG5ldyBDb3JlKG9wdGlvbnMpO1xuICAgIH0gLy8gYWxsb3cgZm9yIHJlZ2lzdHJhdGlvbiBvZiBleHRlbnNpb25zXG4gICAgZWxzZSBpZiAoc3RyaW5nKG9wdGlvbnMpKSB7XG4gICAgICByZXR1cm4gZXh0ZW5zaW9uLmFwcGx5KGV4dGVuc2lvbiwgYXJndW1lbnRzKTtcbiAgICB9XG4gIH07IC8vIGUuZy4gY3l0b3NjYXBlLnVzZSggcmVxdWlyZSgnY3l0b3NjYXBlLWZvbycpLCBiYXIgKVxuXG5cbiAgY3l0b3NjYXBlLnVzZSA9IGZ1bmN0aW9uIChleHQpIHtcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7IC8vIGFyZ3MgdG8gcGFzcyB0byBleHRcblxuICAgIGFyZ3MudW5zaGlmdChjeXRvc2NhcGUpOyAvLyBjeXRvc2NhcGUgaXMgZmlyc3QgYXJnIHRvIGV4dFxuXG4gICAgZXh0LmFwcGx5KG51bGwsIGFyZ3MpO1xuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIGN5dG9zY2FwZS53YXJuaW5ncyA9IGZ1bmN0aW9uIChib29sKSB7XG4gICAgcmV0dXJuIHdhcm5pbmdzKGJvb2wpO1xuICB9OyAvLyByZXBsYWNlZCBieSBidWlsZCBzeXN0ZW1cblxuXG4gIGN5dG9zY2FwZS52ZXJzaW9uID0gdmVyc2lvbjsgLy8gZXhwb3NlIHB1YmxpYyBhcGlzIChtb3N0bHkgZm9yIGV4dGVuc2lvbnMpXG5cbiAgY3l0b3NjYXBlLnN0eWxlc2hlZXQgPSBjeXRvc2NhcGUuU3R5bGVzaGVldCA9IFN0eWxlc2hlZXQ7XG5cbiAgcmV0dXJuIGN5dG9zY2FwZTtcblxufSkpO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../../node_modules/cytoscape/dist/cytoscape.umd.js\n");
+
+/***/ }),
+
+/***/ "../../../node_modules/dayjs/dayjs.min.js":
+/*!************************************************!*\
+ !*** ../../../node_modules/dayjs/dayjs.min.js ***!
+ \************************************************/
+/***/ (function(module) {
+
+eval("!function(t,e){ true?module.exports=e():0}(this,(function(){\"use strict\";var t=1e3,e=6e4,n=36e5,r=\"millisecond\",i=\"second\",s=\"minute\",u=\"hour\",a=\"day\",o=\"week\",c=\"month\",f=\"quarter\",h=\"year\",d=\"date\",l=\"Invalid Date\",$=/^(\\d{4})[-/]?(\\d{1,2})?[-/]?(\\d{0,2})[Tt\\s]*(\\d{1,2})?:?(\\d{1,2})?:?(\\d{1,2})?[.:]?(\\d+)?$/,y=/\\[([^\\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:\"en\",weekdays:\"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday\".split(\"_\"),months:\"January_February_March_April_May_June_July_August_September_October_November_December\".split(\"_\"),ordinal:function(t){var e=[\"th\",\"st\",\"nd\",\"rd\"],n=t%100;return\"[\"+t+(e[(n-20)%10]||e[n]||e[0])+\"]\"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:\"\"+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?\"+\":\"-\")+m(r,2,\"0\")+\":\"+m(i,2,\"0\")},m:function t(e,n){if(e.date()1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},w=function(t,e){if(p(t))return t.clone();var n=\"object\"==typeof e?e:{};return n.date=t,n.args=arguments,new b(n)},O=v;O.l=S,O.i=p,O.w=function(t,e){return w(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var b=function(){function M(t){this.$L=S(t.locale,null,!0),this.parse(t)}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(O.u(e))return new Date;if(e instanceof Date)return new Date(e);if(\"string\"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||\"0\").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.$x=t.x||{},this.init()},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return O},m.isValid=function(){return!(this.$d.toString()===l)},m.isSame=function(t,e){var n=w(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return w(t)68?1900:2e3)};var a=function(e){return function(t){this[e]=+t}},f=[/[+-]\\d\\d:?(\\d\\d)?|Z/,function(e){(this.zone||(this.zone={})).offset=function(e){if(!e)return 0;if(\"Z\"===e)return 0;var t=e.match(/([+-]|\\d\\d)/g),n=60*t[1]+(+t[2]||0);return 0===n?0:\"+\"===t[0]?-n:n}(e)}],h=function(e){var t=o[e];return t&&(t.indexOf?t:t.s.concat(t.f))},u=function(e,t){var n,r=o.meridiem;if(r){for(var i=1;i<=24;i+=1)if(e.indexOf(r(i,0,t))>-1){n=i>12;break}}else n=e===(t?\"pm\":\"PM\");return n},d={A:[i,function(e){this.afternoon=u(e,!1)}],a:[i,function(e){this.afternoon=u(e,!0)}],S:[/\\d/,function(e){this.milliseconds=100*+e}],SS:[n,function(e){this.milliseconds=10*+e}],SSS:[/\\d{3}/,function(e){this.milliseconds=+e}],s:[r,a(\"seconds\")],ss:[r,a(\"seconds\")],m:[r,a(\"minutes\")],mm:[r,a(\"minutes\")],H:[r,a(\"hours\")],h:[r,a(\"hours\")],HH:[r,a(\"hours\")],hh:[r,a(\"hours\")],D:[r,a(\"day\")],DD:[n,a(\"day\")],Do:[i,function(e){var t=o.ordinal,n=e.match(/\\d+/);if(this.day=n[0],t)for(var r=1;r<=31;r+=1)t(r).replace(/\\[|\\]/g,\"\")===e&&(this.day=r)}],M:[r,a(\"month\")],MM:[n,a(\"month\")],MMM:[i,function(e){var t=h(\"months\"),n=(h(\"monthsShort\")||t.map((function(e){return e.slice(0,3)}))).indexOf(e)+1;if(n<1)throw new Error;this.month=n%12||n}],MMMM:[i,function(e){var t=h(\"months\").indexOf(e)+1;if(t<1)throw new Error;this.month=t%12||t}],Y:[/[+-]?\\d+/,a(\"year\")],YY:[n,function(e){this.year=s(e)}],YYYY:[/\\d{4}/,a(\"year\")],Z:f,ZZ:f};function c(n){var r,i;r=n,i=o&&o.formats;for(var s=(n=r.replace(/(\\[[^\\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var o=r&&r.toUpperCase();return n||i[r]||e[r]||i[o].replace(/(\\[[^\\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))).match(t),a=s.length,f=0;f-1)return new Date((\"X\"===t?1e3:1)*e);var r=c(t)(e),i=r.year,o=r.month,s=r.day,a=r.hours,f=r.minutes,h=r.seconds,u=r.milliseconds,d=r.zone,l=new Date,m=s||(i||o?1:l.getDate()),M=i||l.getFullYear(),Y=0;i&&!o||(Y=o>0?o-1:l.getMonth());var p=a||0,v=f||0,D=h||0,g=u||0;return d?new Date(Date.UTC(M,Y,m,p,v,D,g+60*d.offset*1e3)):n?new Date(Date.UTC(M,Y,m,p,v,D,g)):new Date(M,Y,m,p,v,D,g)}catch(e){return new Date(\"\")}}(t,a,r),this.init(),d&&!0!==d&&(this.$L=this.locale(d).$L),u&&t!=this.format(a)&&(this.$d=new Date(\"\")),o={}}else if(a instanceof Array)for(var l=a.length,m=1;m<=l;m+=1){s[1]=a[m-1];var M=n.apply(this,s);if(M.isValid()){this.$d=M.$d,this.$L=M.$L,this.init();break}m===l&&(this.$d=new Date(\"\"))}else i.call(this,e)}}}));//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2RheWpzL3BsdWdpbi9jdXN0b21QYXJzZUZvcm1hdC5qcy5qcyIsIm1hcHBpbmdzIjoiQUFBQSxlQUFlLEtBQW9ELG9CQUFvQixDQUF3SSxDQUFDLGtCQUFrQixhQUFhLE9BQU8sd0hBQXdILCtFQUErRSxJQUFJLHdEQUF3RCxlQUFlLDhCQUE4QixrQkFBa0IsbUJBQW1CLFlBQVksc0NBQXNDLHlCQUF5QixzQkFBc0IsZUFBZSxvQkFBb0IsbURBQW1ELCtCQUErQixJQUFJLGdCQUFnQixXQUFXLHdDQUF3QyxpQkFBaUIsbUJBQW1CLE1BQU0sWUFBWSxNQUFNLGdDQUFnQyxPQUFPLE9BQU8seUJBQXlCLFNBQVMsSUFBSSxpQkFBaUIsdUJBQXVCLG1CQUFtQix1QkFBdUIsc0JBQXNCLHlCQUF5QixvQkFBb0Isd0JBQXdCLFdBQVcsRUFBRSxjQUFjLHFCQUFxQix1TUFBdU0saUNBQWlDLCtCQUErQixNQUFNLGlEQUFpRCx3REFBd0QsMERBQTBELG9CQUFvQixpQkFBaUIsdUJBQXVCLG1CQUFtQixzQkFBc0IsK0JBQStCLHVCQUF1QixtQkFBbUIsNkNBQTZDLGVBQWUsWUFBWSxFQUFFLHVCQUF1QixjQUFjLFFBQVEsbUJBQW1CLDRDQUE0QyxJQUFJLEdBQUcsSUFBSSxxQkFBcUIseUJBQXlCLHFGQUFxRixxQkFBcUIsR0FBRyw0QkFBNEIsSUFBSSxNQUFNLHNDQUFzQyxRQUFRLGlCQUFpQiwwQkFBMEIsbUJBQW1CLFlBQVksU0FBUyxJQUFJLE1BQU0sV0FBVyxrQ0FBa0MsS0FBSyxxREFBcUQsK0JBQStCLG1CQUFtQixrQkFBa0IsZUFBZSxjQUFjLDhEQUE4RCxPQUFPLHVCQUF1Qix5RUFBeUUsNEJBQTRCLG9CQUFvQiw4QkFBOEIsVUFBVSxXQUFXLHVCQUF1QiwwQ0FBMEMsd0VBQXdFLElBQUksOERBQThELG1LQUFtSyxnQ0FBZ0MsZ0NBQWdDLHVIQUF1SCxTQUFTLHFCQUFxQiw2R0FBNkcsa0RBQWtELEtBQUssTUFBTSxZQUFZLHNCQUFzQixnQkFBZ0Isc0NBQXNDLE1BQU0sOEJBQThCLHNCQUFzQiIsInNvdXJjZXMiOlsid2VicGFjazovLy8uLi8uLi8uLi9ub2RlX21vZHVsZXMvZGF5anMvcGx1Z2luL2N1c3RvbVBhcnNlRm9ybWF0LmpzP2RiODQiXSwic291cmNlc0NvbnRlbnQiOlsiIWZ1bmN0aW9uKGUsdCl7XCJvYmplY3RcIj09dHlwZW9mIGV4cG9ydHMmJlwidW5kZWZpbmVkXCIhPXR5cGVvZiBtb2R1bGU/bW9kdWxlLmV4cG9ydHM9dCgpOlwiZnVuY3Rpb25cIj09dHlwZW9mIGRlZmluZSYmZGVmaW5lLmFtZD9kZWZpbmUodCk6KGU9XCJ1bmRlZmluZWRcIiE9dHlwZW9mIGdsb2JhbFRoaXM/Z2xvYmFsVGhpczplfHxzZWxmKS5kYXlqc19wbHVnaW5fY3VzdG9tUGFyc2VGb3JtYXQ9dCgpfSh0aGlzLChmdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBlPXtMVFM6XCJoOm1tOnNzIEFcIixMVDpcImg6bW0gQVwiLEw6XCJNTS9ERC9ZWVlZXCIsTEw6XCJNTU1NIEQsIFlZWVlcIixMTEw6XCJNTU1NIEQsIFlZWVkgaDptbSBBXCIsTExMTDpcImRkZGQsIE1NTU0gRCwgWVlZWSBoOm1tIEFcIn0sdD0vKFxcW1teW10qXFxdKXwoWy1fOi8uLCgpXFxzXSspfChBfGF8WVlZWXxZWT98TU0/TT9NP3xEb3xERD98aGg/fEhIP3xtbT98c3M/fFN7MSwzfXx6fFpaPykvZyxuPS9cXGRcXGQvLHI9L1xcZFxcZD8vLGk9L1xcZCpbXi1fOi8sKClcXHNcXGRdKy8sbz17fSxzPWZ1bmN0aW9uKGUpe3JldHVybihlPStlKSsoZT42OD8xOTAwOjJlMyl9O3ZhciBhPWZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbih0KXt0aGlzW2VdPSt0fX0sZj1bL1srLV1cXGRcXGQ6PyhcXGRcXGQpP3xaLyxmdW5jdGlvbihlKXsodGhpcy56b25lfHwodGhpcy56b25lPXt9KSkub2Zmc2V0PWZ1bmN0aW9uKGUpe2lmKCFlKXJldHVybiAwO2lmKFwiWlwiPT09ZSlyZXR1cm4gMDt2YXIgdD1lLm1hdGNoKC8oWystXXxcXGRcXGQpL2cpLG49NjAqdFsxXSsoK3RbMl18fDApO3JldHVybiAwPT09bj8wOlwiK1wiPT09dFswXT8tbjpufShlKX1dLGg9ZnVuY3Rpb24oZSl7dmFyIHQ9b1tlXTtyZXR1cm4gdCYmKHQuaW5kZXhPZj90OnQucy5jb25jYXQodC5mKSl9LHU9ZnVuY3Rpb24oZSx0KXt2YXIgbixyPW8ubWVyaWRpZW07aWYocil7Zm9yKHZhciBpPTE7aTw9MjQ7aSs9MSlpZihlLmluZGV4T2YocihpLDAsdCkpPi0xKXtuPWk+MTI7YnJlYWt9fWVsc2Ugbj1lPT09KHQ/XCJwbVwiOlwiUE1cIik7cmV0dXJuIG59LGQ9e0E6W2ksZnVuY3Rpb24oZSl7dGhpcy5hZnRlcm5vb249dShlLCExKX1dLGE6W2ksZnVuY3Rpb24oZSl7dGhpcy5hZnRlcm5vb249dShlLCEwKX1dLFM6Wy9cXGQvLGZ1bmN0aW9uKGUpe3RoaXMubWlsbGlzZWNvbmRzPTEwMCorZX1dLFNTOltuLGZ1bmN0aW9uKGUpe3RoaXMubWlsbGlzZWNvbmRzPTEwKitlfV0sU1NTOlsvXFxkezN9LyxmdW5jdGlvbihlKXt0aGlzLm1pbGxpc2Vjb25kcz0rZX1dLHM6W3IsYShcInNlY29uZHNcIildLHNzOltyLGEoXCJzZWNvbmRzXCIpXSxtOltyLGEoXCJtaW51dGVzXCIpXSxtbTpbcixhKFwibWludXRlc1wiKV0sSDpbcixhKFwiaG91cnNcIildLGg6W3IsYShcImhvdXJzXCIpXSxISDpbcixhKFwiaG91cnNcIildLGhoOltyLGEoXCJob3Vyc1wiKV0sRDpbcixhKFwiZGF5XCIpXSxERDpbbixhKFwiZGF5XCIpXSxEbzpbaSxmdW5jdGlvbihlKXt2YXIgdD1vLm9yZGluYWwsbj1lLm1hdGNoKC9cXGQrLyk7aWYodGhpcy5kYXk9blswXSx0KWZvcih2YXIgcj0xO3I8PTMxO3IrPTEpdChyKS5yZXBsYWNlKC9cXFt8XFxdL2csXCJcIik9PT1lJiYodGhpcy5kYXk9cil9XSxNOltyLGEoXCJtb250aFwiKV0sTU06W24sYShcIm1vbnRoXCIpXSxNTU06W2ksZnVuY3Rpb24oZSl7dmFyIHQ9aChcIm1vbnRoc1wiKSxuPShoKFwibW9udGhzU2hvcnRcIil8fHQubWFwKChmdW5jdGlvbihlKXtyZXR1cm4gZS5zbGljZSgwLDMpfSkpKS5pbmRleE9mKGUpKzE7aWYobjwxKXRocm93IG5ldyBFcnJvcjt0aGlzLm1vbnRoPW4lMTJ8fG59XSxNTU1NOltpLGZ1bmN0aW9uKGUpe3ZhciB0PWgoXCJtb250aHNcIikuaW5kZXhPZihlKSsxO2lmKHQ8MSl0aHJvdyBuZXcgRXJyb3I7dGhpcy5tb250aD10JTEyfHx0fV0sWTpbL1srLV0/XFxkKy8sYShcInllYXJcIildLFlZOltuLGZ1bmN0aW9uKGUpe3RoaXMueWVhcj1zKGUpfV0sWVlZWTpbL1xcZHs0fS8sYShcInllYXJcIildLFo6ZixaWjpmfTtmdW5jdGlvbiBjKG4pe3ZhciByLGk7cj1uLGk9byYmby5mb3JtYXRzO2Zvcih2YXIgcz0obj1yLnJlcGxhY2UoLyhcXFtbXlxcXV0rXSl8KExUUz98bHsxLDR9fEx7MSw0fSkvZywoZnVuY3Rpb24odCxuLHIpe3ZhciBvPXImJnIudG9VcHBlckNhc2UoKTtyZXR1cm4gbnx8aVtyXXx8ZVtyXXx8aVtvXS5yZXBsYWNlKC8oXFxbW15cXF1dK10pfChNTU1NfE1NfEREfGRkZGQpL2csKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gdHx8bi5zbGljZSgxKX0pKX0pKSkubWF0Y2godCksYT1zLmxlbmd0aCxmPTA7ZjxhO2YrPTEpe3ZhciBoPXNbZl0sdT1kW2hdLGM9dSYmdVswXSxsPXUmJnVbMV07c1tmXT1sP3tyZWdleDpjLHBhcnNlcjpsfTpoLnJlcGxhY2UoL15cXFt8XFxdJC9nLFwiXCIpfXJldHVybiBmdW5jdGlvbihlKXtmb3IodmFyIHQ9e30sbj0wLHI9MDtuPGE7bis9MSl7dmFyIGk9c1tuXTtpZihcInN0cmluZ1wiPT10eXBlb2YgaSlyKz1pLmxlbmd0aDtlbHNle3ZhciBvPWkucmVnZXgsZj1pLnBhcnNlcixoPWUuc2xpY2UociksdT1vLmV4ZWMoaClbMF07Zi5jYWxsKHQsdSksZT1lLnJlcGxhY2UodSxcIlwiKX19cmV0dXJuIGZ1bmN0aW9uKGUpe3ZhciB0PWUuYWZ0ZXJub29uO2lmKHZvaWQgMCE9PXQpe3ZhciBuPWUuaG91cnM7dD9uPDEyJiYoZS5ob3Vycys9MTIpOjEyPT09biYmKGUuaG91cnM9MCksZGVsZXRlIGUuYWZ0ZXJub29ufX0odCksdH19cmV0dXJuIGZ1bmN0aW9uKGUsdCxuKXtuLnAuY3VzdG9tUGFyc2VGb3JtYXQ9ITAsZSYmZS5wYXJzZVR3b0RpZ2l0WWVhciYmKHM9ZS5wYXJzZVR3b0RpZ2l0WWVhcik7dmFyIHI9dC5wcm90b3R5cGUsaT1yLnBhcnNlO3IucGFyc2U9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5kYXRlLHI9ZS51dGMscz1lLmFyZ3M7dGhpcy4kdT1yO3ZhciBhPXNbMV07aWYoXCJzdHJpbmdcIj09dHlwZW9mIGEpe3ZhciBmPSEwPT09c1syXSxoPSEwPT09c1szXSx1PWZ8fGgsZD1zWzJdO2gmJihkPXNbMl0pLG89dGhpcy4kbG9jYWxlKCksIWYmJmQmJihvPW4uTHNbZF0pLHRoaXMuJGQ9ZnVuY3Rpb24oZSx0LG4pe3RyeXtpZihbXCJ4XCIsXCJYXCJdLmluZGV4T2YodCk+LTEpcmV0dXJuIG5ldyBEYXRlKChcIlhcIj09PXQ/MWUzOjEpKmUpO3ZhciByPWModCkoZSksaT1yLnllYXIsbz1yLm1vbnRoLHM9ci5kYXksYT1yLmhvdXJzLGY9ci5taW51dGVzLGg9ci5zZWNvbmRzLHU9ci5taWxsaXNlY29uZHMsZD1yLnpvbmUsbD1uZXcgRGF0ZSxtPXN8fChpfHxvPzE6bC5nZXREYXRlKCkpLE09aXx8bC5nZXRGdWxsWWVhcigpLFk9MDtpJiYhb3x8KFk9bz4wP28tMTpsLmdldE1vbnRoKCkpO3ZhciBwPWF8fDAsdj1mfHwwLEQ9aHx8MCxnPXV8fDA7cmV0dXJuIGQ/bmV3IERhdGUoRGF0ZS5VVEMoTSxZLG0scCx2LEQsZys2MCpkLm9mZnNldCoxZTMpKTpuP25ldyBEYXRlKERhdGUuVVRDKE0sWSxtLHAsdixELGcpKTpuZXcgRGF0ZShNLFksbSxwLHYsRCxnKX1jYXRjaChlKXtyZXR1cm4gbmV3IERhdGUoXCJcIil9fSh0LGEsciksdGhpcy5pbml0KCksZCYmITAhPT1kJiYodGhpcy4kTD10aGlzLmxvY2FsZShkKS4kTCksdSYmdCE9dGhpcy5mb3JtYXQoYSkmJih0aGlzLiRkPW5ldyBEYXRlKFwiXCIpKSxvPXt9fWVsc2UgaWYoYSBpbnN0YW5jZW9mIEFycmF5KWZvcih2YXIgbD1hLmxlbmd0aCxtPTE7bTw9bDttKz0xKXtzWzFdPWFbbS0xXTt2YXIgTT1uLmFwcGx5KHRoaXMscyk7aWYoTS5pc1ZhbGlkKCkpe3RoaXMuJGQ9TS4kZCx0aGlzLiRMPU0uJEwsdGhpcy5pbml0KCk7YnJlYWt9bT09PWwmJih0aGlzLiRkPW5ldyBEYXRlKFwiXCIpKX1lbHNlIGkuY2FsbCh0aGlzLGUpfX19KSk7Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../../node_modules/dayjs/plugin/customParseFormat.js\n");
+
+/***/ }),
+
+/***/ "../../../node_modules/dayjs/plugin/isoWeek.js":
+/*!*****************************************************!*\
+ !*** ../../../node_modules/dayjs/plugin/isoWeek.js ***!
+ \*****************************************************/
+/***/ (function(module) {
+
+eval("!function(e,t){ true?module.exports=t():0}(this,(function(){\"use strict\";var e=\"day\";return function(t,i,s){var a=function(t){return t.add(4-t.isoWeekday(),e)},d=i.prototype;d.isoWeekYear=function(){return a(this).year()},d.isoWeek=function(t){if(!this.$utils().u(t))return this.add(7*(t-this.isoWeek()),e);var i,d,n,o,r=a(this),u=(i=this.isoWeekYear(),d=this.$u,n=(d?s.utc:s)().year(i).startOf(\"year\"),o=4-n.isoWeekday(),n.isoWeekday()>4&&(o+=7),n.add(o,e));return r.diff(u,\"week\")+1},d.isoWeekday=function(e){return this.$utils().u(e)?this.day()||7:this.day(this.day()%7?e:e-7)};var n=d.startOf;d.startOf=function(e,t){var i=this.$utils(),s=!!i.u(t)||t;return\"isoweek\"===i.p(e)?s?this.date(this.date()-(this.isoWeekday()-1)).startOf(\"day\"):this.date(this.date()-1-(this.isoWeekday()-1)+7).endOf(\"day\"):n.bind(this)(e,t)}}}));//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2RheWpzL3BsdWdpbi9pc29XZWVrLmpzLmpzIiwibWFwcGluZ3MiOiJBQUFBLGVBQWUsS0FBb0Qsb0JBQW9CLENBQThILENBQUMsa0JBQWtCLGFBQWEsWUFBWSx1QkFBdUIsa0JBQWtCLGlDQUFpQyxlQUFlLHlCQUF5QixzQkFBc0IsdUJBQXVCLCtEQUErRCx3SkFBd0osMEJBQTBCLDBCQUEwQixzRUFBc0UsZ0JBQWdCLHdCQUF3QixrQ0FBa0MseUtBQXlLIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uLy4uL25vZGVfbW9kdWxlcy9kYXlqcy9wbHVnaW4vaXNvV2Vlay5qcz9jOGNiIl0sInNvdXJjZXNDb250ZW50IjpbIiFmdW5jdGlvbihlLHQpe1wib2JqZWN0XCI9PXR5cGVvZiBleHBvcnRzJiZcInVuZGVmaW5lZFwiIT10eXBlb2YgbW9kdWxlP21vZHVsZS5leHBvcnRzPXQoKTpcImZ1bmN0aW9uXCI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQ/ZGVmaW5lKHQpOihlPVwidW5kZWZpbmVkXCIhPXR5cGVvZiBnbG9iYWxUaGlzP2dsb2JhbFRoaXM6ZXx8c2VsZikuZGF5anNfcGx1Z2luX2lzb1dlZWs9dCgpfSh0aGlzLChmdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBlPVwiZGF5XCI7cmV0dXJuIGZ1bmN0aW9uKHQsaSxzKXt2YXIgYT1mdW5jdGlvbih0KXtyZXR1cm4gdC5hZGQoNC10Lmlzb1dlZWtkYXkoKSxlKX0sZD1pLnByb3RvdHlwZTtkLmlzb1dlZWtZZWFyPWZ1bmN0aW9uKCl7cmV0dXJuIGEodGhpcykueWVhcigpfSxkLmlzb1dlZWs9ZnVuY3Rpb24odCl7aWYoIXRoaXMuJHV0aWxzKCkudSh0KSlyZXR1cm4gdGhpcy5hZGQoNyoodC10aGlzLmlzb1dlZWsoKSksZSk7dmFyIGksZCxuLG8scj1hKHRoaXMpLHU9KGk9dGhpcy5pc29XZWVrWWVhcigpLGQ9dGhpcy4kdSxuPShkP3MudXRjOnMpKCkueWVhcihpKS5zdGFydE9mKFwieWVhclwiKSxvPTQtbi5pc29XZWVrZGF5KCksbi5pc29XZWVrZGF5KCk+NCYmKG8rPTcpLG4uYWRkKG8sZSkpO3JldHVybiByLmRpZmYodSxcIndlZWtcIikrMX0sZC5pc29XZWVrZGF5PWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLiR1dGlscygpLnUoZSk/dGhpcy5kYXkoKXx8Nzp0aGlzLmRheSh0aGlzLmRheSgpJTc/ZTplLTcpfTt2YXIgbj1kLnN0YXJ0T2Y7ZC5zdGFydE9mPWZ1bmN0aW9uKGUsdCl7dmFyIGk9dGhpcy4kdXRpbHMoKSxzPSEhaS51KHQpfHx0O3JldHVyblwiaXNvd2Vla1wiPT09aS5wKGUpP3M/dGhpcy5kYXRlKHRoaXMuZGF0ZSgpLSh0aGlzLmlzb1dlZWtkYXkoKS0xKSkuc3RhcnRPZihcImRheVwiKTp0aGlzLmRhdGUodGhpcy5kYXRlKCktMS0odGhpcy5pc29XZWVrZGF5KCktMSkrNykuZW5kT2YoXCJkYXlcIik6bi5iaW5kKHRoaXMpKGUsdCl9fX0pKTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../../node_modules/dayjs/plugin/isoWeek.js\n");
+
+/***/ }),
+
+/***/ "../../../node_modules/debug/src/browser.js":
+/*!**************************************************!*\
+ !*** ../../../node_modules/debug/src/browser.js ***!
+ \**************************************************/
+/***/ ((module, exports, __webpack_require__) => {
+
+eval("/* eslint-env browser */\n\n/**\n * This is the web browser implementation of `debug()`.\n */\n\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.storage = localstorage();\nexports.destroy = (() => {\n\tlet warned = false;\n\n\treturn () => {\n\t\tif (!warned) {\n\t\t\twarned = true;\n\t\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t\t}\n\t};\n})();\n\n/**\n * Colors.\n */\n\nexports.colors = [\n\t'#0000CC',\n\t'#0000FF',\n\t'#0033CC',\n\t'#0033FF',\n\t'#0066CC',\n\t'#0066FF',\n\t'#0099CC',\n\t'#0099FF',\n\t'#00CC00',\n\t'#00CC33',\n\t'#00CC66',\n\t'#00CC99',\n\t'#00CCCC',\n\t'#00CCFF',\n\t'#3300CC',\n\t'#3300FF',\n\t'#3333CC',\n\t'#3333FF',\n\t'#3366CC',\n\t'#3366FF',\n\t'#3399CC',\n\t'#3399FF',\n\t'#33CC00',\n\t'#33CC33',\n\t'#33CC66',\n\t'#33CC99',\n\t'#33CCCC',\n\t'#33CCFF',\n\t'#6600CC',\n\t'#6600FF',\n\t'#6633CC',\n\t'#6633FF',\n\t'#66CC00',\n\t'#66CC33',\n\t'#9900CC',\n\t'#9900FF',\n\t'#9933CC',\n\t'#9933FF',\n\t'#99CC00',\n\t'#99CC33',\n\t'#CC0000',\n\t'#CC0033',\n\t'#CC0066',\n\t'#CC0099',\n\t'#CC00CC',\n\t'#CC00FF',\n\t'#CC3300',\n\t'#CC3333',\n\t'#CC3366',\n\t'#CC3399',\n\t'#CC33CC',\n\t'#CC33FF',\n\t'#CC6600',\n\t'#CC6633',\n\t'#CC9900',\n\t'#CC9933',\n\t'#CCCC00',\n\t'#CCCC33',\n\t'#FF0000',\n\t'#FF0033',\n\t'#FF0066',\n\t'#FF0099',\n\t'#FF00CC',\n\t'#FF00FF',\n\t'#FF3300',\n\t'#FF3333',\n\t'#FF3366',\n\t'#FF3399',\n\t'#FF33CC',\n\t'#FF33FF',\n\t'#FF6600',\n\t'#FF6633',\n\t'#FF9900',\n\t'#FF9933',\n\t'#FFCC00',\n\t'#FFCC33'\n];\n\n/**\n * Currently only WebKit-based Web Inspectors, Firefox >= v31,\n * and the Firebug extension (any Firefox version) are known\n * to support \"%c\" CSS customizations.\n *\n * TODO: add a `localStorage` variable to explicitly enable/disable colors\n */\n\n// eslint-disable-next-line complexity\nfunction useColors() {\n\t// NB: In an Electron preload script, document will be defined but not fully\n\t// initialized. Since we know we're in Chrome, we'll just detect this case\n\t// explicitly\n\tif (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {\n\t\treturn true;\n\t}\n\n\t// Internet Explorer and Edge do not support colors.\n\tif (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/)) {\n\t\treturn false;\n\t}\n\n\t// Is webkit? http://stackoverflow.com/a/16459606/376773\n\t// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632\n\treturn (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||\n\t\t// Is firebug? http://stackoverflow.com/a/398120/376773\n\t\t(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||\n\t\t// Is firefox >= v31?\n\t\t// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||\n\t\t// Double check webkit in userAgent just in case we are in a worker\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/));\n}\n\n/**\n * Colorize log arguments if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n\targs[0] = (this.useColors ? '%c' : '') +\n\t\tthis.namespace +\n\t\t(this.useColors ? ' %c' : ' ') +\n\t\targs[0] +\n\t\t(this.useColors ? '%c ' : ' ') +\n\t\t'+' + module.exports.humanize(this.diff);\n\n\tif (!this.useColors) {\n\t\treturn;\n\t}\n\n\tconst c = 'color: ' + this.color;\n\targs.splice(1, 0, c, 'color: inherit');\n\n\t// The final \"%c\" is somewhat tricky, because there could be other\n\t// arguments passed either before or after the %c, so we need to\n\t// figure out the correct index to insert the CSS into\n\tlet index = 0;\n\tlet lastC = 0;\n\targs[0].replace(/%[a-zA-Z%]/g, match => {\n\t\tif (match === '%%') {\n\t\t\treturn;\n\t\t}\n\t\tindex++;\n\t\tif (match === '%c') {\n\t\t\t// We only are interested in the *last* %c\n\t\t\t// (the user may have provided their own)\n\t\t\tlastC = index;\n\t\t}\n\t});\n\n\targs.splice(lastC, 0, c);\n}\n\n/**\n * Invokes `console.debug()` when available.\n * No-op when `console.debug` is not a \"function\".\n * If `console.debug` is not available, falls back\n * to `console.log`.\n *\n * @api public\n */\nexports.log = console.debug || console.log || (() => {});\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\nfunction save(namespaces) {\n\ttry {\n\t\tif (namespaces) {\n\t\t\texports.storage.setItem('debug', namespaces);\n\t\t} else {\n\t\t\texports.storage.removeItem('debug');\n\t\t}\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\nfunction load() {\n\tlet r;\n\ttry {\n\t\tr = exports.storage.getItem('debug');\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n\n\t// If debug isn't set in LS, and we're in Electron, try to load $DEBUG\n\tif (!r && typeof process !== 'undefined' && 'env' in process) {\n\t\tr = ({\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PORTAL_URL\":\"\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"https://app.excalidraw.com\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_ENABLE_SW\":\"\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_DISABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3000\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_PKG_NAME\":\"@excalidraw/excalidraw\",\"VITE_PKG_VERSION\":\"0.17.6\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).DEBUG;\n\t}\n\n\treturn r;\n}\n\n/**\n * Localstorage attempts to return the localstorage.\n *\n * This is necessary because safari throws\n * when a user disables cookies/localstorage\n * and you attempt to access it.\n *\n * @return {LocalStorage}\n * @api private\n */\n\nfunction localstorage() {\n\ttry {\n\t\t// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context\n\t\t// The Browser also has localStorage in the global context.\n\t\treturn localStorage;\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\nmodule.exports = __webpack_require__(/*! ./common */ \"../../../node_modules/debug/src/common.js\")(exports);\n\nconst {formatters} = module.exports;\n\n/**\n * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n */\n\nformatters.j = function (v) {\n\ttry {\n\t\treturn JSON.stringify(v);\n\t} catch (error) {\n\t\treturn '[UnexpectedJSONParseError]: ' + error.message;\n\t}\n};\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2RlYnVnL3NyYy9icm93c2VyLmpzLmpzIiwibWFwcGluZ3MiOiJBQUFBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxrQkFBa0I7QUFDbEIsWUFBWTtBQUNaLFlBQVk7QUFDWixpQkFBaUI7QUFDakIsZUFBZTtBQUNmLGVBQWU7QUFDZjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTs7QUFFQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsNENBQTRDOztBQUV2RDtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE1BQU0sc3FDQUFXO0FBQ2pCOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGlCQUFpQixtQkFBTyxDQUFDLDJEQUFVOztBQUVuQyxPQUFPLFlBQVk7O0FBRW5CO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uLy4uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvYnJvd3Nlci5qcz9mOGUyIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1lbnYgYnJvd3NlciAqL1xuXG4vKipcbiAqIFRoaXMgaXMgdGhlIHdlYiBicm93c2VyIGltcGxlbWVudGF0aW9uIG9mIGBkZWJ1ZygpYC5cbiAqL1xuXG5leHBvcnRzLmZvcm1hdEFyZ3MgPSBmb3JtYXRBcmdzO1xuZXhwb3J0cy5zYXZlID0gc2F2ZTtcbmV4cG9ydHMubG9hZCA9IGxvYWQ7XG5leHBvcnRzLnVzZUNvbG9ycyA9IHVzZUNvbG9ycztcbmV4cG9ydHMuc3RvcmFnZSA9IGxvY2Fsc3RvcmFnZSgpO1xuZXhwb3J0cy5kZXN0cm95ID0gKCgpID0+IHtcblx0bGV0IHdhcm5lZCA9IGZhbHNlO1xuXG5cdHJldHVybiAoKSA9PiB7XG5cdFx0aWYgKCF3YXJuZWQpIHtcblx0XHRcdHdhcm5lZCA9IHRydWU7XG5cdFx0XHRjb25zb2xlLndhcm4oJ0luc3RhbmNlIG1ldGhvZCBgZGVidWcuZGVzdHJveSgpYCBpcyBkZXByZWNhdGVkIGFuZCBubyBsb25nZXIgZG9lcyBhbnl0aGluZy4gSXQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZXh0IG1ham9yIHZlcnNpb24gb2YgYGRlYnVnYC4nKTtcblx0XHR9XG5cdH07XG59KSgpO1xuXG4vKipcbiAqIENvbG9ycy5cbiAqL1xuXG5leHBvcnRzLmNvbG9ycyA9IFtcblx0JyMwMDAwQ0MnLFxuXHQnIzAwMDBGRicsXG5cdCcjMDAzM0NDJyxcblx0JyMwMDMzRkYnLFxuXHQnIzAwNjZDQycsXG5cdCcjMDA2NkZGJyxcblx0JyMwMDk5Q0MnLFxuXHQnIzAwOTlGRicsXG5cdCcjMDBDQzAwJyxcblx0JyMwMENDMzMnLFxuXHQnIzAwQ0M2NicsXG5cdCcjMDBDQzk5Jyxcblx0JyMwMENDQ0MnLFxuXHQnIzAwQ0NGRicsXG5cdCcjMzMwMENDJyxcblx0JyMzMzAwRkYnLFxuXHQnIzMzMzNDQycsXG5cdCcjMzMzM0ZGJyxcblx0JyMzMzY2Q0MnLFxuXHQnIzMzNjZGRicsXG5cdCcjMzM5OUNDJyxcblx0JyMzMzk5RkYnLFxuXHQnIzMzQ0MwMCcsXG5cdCcjMzNDQzMzJyxcblx0JyMzM0NDNjYnLFxuXHQnIzMzQ0M5OScsXG5cdCcjMzNDQ0NDJyxcblx0JyMzM0NDRkYnLFxuXHQnIzY2MDBDQycsXG5cdCcjNjYwMEZGJyxcblx0JyM2NjMzQ0MnLFxuXHQnIzY2MzNGRicsXG5cdCcjNjZDQzAwJyxcblx0JyM2NkNDMzMnLFxuXHQnIzk5MDBDQycsXG5cdCcjOTkwMEZGJyxcblx0JyM5OTMzQ0MnLFxuXHQnIzk5MzNGRicsXG5cdCcjOTlDQzAwJyxcblx0JyM5OUNDMzMnLFxuXHQnI0NDMDAwMCcsXG5cdCcjQ0MwMDMzJyxcblx0JyNDQzAwNjYnLFxuXHQnI0NDMDA5OScsXG5cdCcjQ0MwMENDJyxcblx0JyNDQzAwRkYnLFxuXHQnI0NDMzMwMCcsXG5cdCcjQ0MzMzMzJyxcblx0JyNDQzMzNjYnLFxuXHQnI0NDMzM5OScsXG5cdCcjQ0MzM0NDJyxcblx0JyNDQzMzRkYnLFxuXHQnI0NDNjYwMCcsXG5cdCcjQ0M2NjMzJyxcblx0JyNDQzk5MDAnLFxuXHQnI0NDOTkzMycsXG5cdCcjQ0NDQzAwJyxcblx0JyNDQ0NDMzMnLFxuXHQnI0ZGMDAwMCcsXG5cdCcjRkYwMDMzJyxcblx0JyNGRjAwNjYnLFxuXHQnI0ZGMDA5OScsXG5cdCcjRkYwMENDJyxcblx0JyNGRjAwRkYnLFxuXHQnI0ZGMzMwMCcsXG5cdCcjRkYzMzMzJyxcblx0JyNGRjMzNjYnLFxuXHQnI0ZGMzM5OScsXG5cdCcjRkYzM0NDJyxcblx0JyNGRjMzRkYnLFxuXHQnI0ZGNjYwMCcsXG5cdCcjRkY2NjMzJyxcblx0JyNGRjk5MDAnLFxuXHQnI0ZGOTkzMycsXG5cdCcjRkZDQzAwJyxcblx0JyNGRkNDMzMnXG5dO1xuXG4vKipcbiAqIEN1cnJlbnRseSBvbmx5IFdlYktpdC1iYXNlZCBXZWIgSW5zcGVjdG9ycywgRmlyZWZveCA+PSB2MzEsXG4gKiBhbmQgdGhlIEZpcmVidWcgZXh0ZW5zaW9uIChhbnkgRmlyZWZveCB2ZXJzaW9uKSBhcmUga25vd25cbiAqIHRvIHN1cHBvcnQgXCIlY1wiIENTUyBjdXN0b21pemF0aW9ucy5cbiAqXG4gKiBUT0RPOiBhZGQgYSBgbG9jYWxTdG9yYWdlYCB2YXJpYWJsZSB0byBleHBsaWNpdGx5IGVuYWJsZS9kaXNhYmxlIGNvbG9yc1xuICovXG5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG5mdW5jdGlvbiB1c2VDb2xvcnMoKSB7XG5cdC8vIE5COiBJbiBhbiBFbGVjdHJvbiBwcmVsb2FkIHNjcmlwdCwgZG9jdW1lbnQgd2lsbCBiZSBkZWZpbmVkIGJ1dCBub3QgZnVsbHlcblx0Ly8gaW5pdGlhbGl6ZWQuIFNpbmNlIHdlIGtub3cgd2UncmUgaW4gQ2hyb21lLCB3ZSdsbCBqdXN0IGRldGVjdCB0aGlzIGNhc2Vcblx0Ly8gZXhwbGljaXRseVxuXHRpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LnByb2Nlc3MgJiYgKHdpbmRvdy5wcm9jZXNzLnR5cGUgPT09ICdyZW5kZXJlcicgfHwgd2luZG93LnByb2Nlc3MuX19ud2pzKSkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cblx0Ly8gSW50ZXJuZXQgRXhwbG9yZXIgYW5kIEVkZ2UgZG8gbm90IHN1cHBvcnQgY29sb3JzLlxuXHRpZiAodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudCAmJiBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkubWF0Y2goLyhlZGdlfHRyaWRlbnQpXFwvKFxcZCspLykpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHQvLyBJcyB3ZWJraXQ/IGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzE2NDU5NjA2LzM3Njc3M1xuXHQvLyBkb2N1bWVudCBpcyB1bmRlZmluZWQgaW4gcmVhY3QtbmF0aXZlOiBodHRwczovL2dpdGh1Yi5jb20vZmFjZWJvb2svcmVhY3QtbmF0aXZlL3B1bGwvMTYzMlxuXHRyZXR1cm4gKHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50ICYmIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZSAmJiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUuV2Via2l0QXBwZWFyYW5jZSkgfHxcblx0XHQvLyBJcyBmaXJlYnVnPyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zOTgxMjAvMzc2NzczXG5cdFx0KHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHdpbmRvdy5jb25zb2xlICYmICh3aW5kb3cuY29uc29sZS5maXJlYnVnIHx8ICh3aW5kb3cuY29uc29sZS5leGNlcHRpb24gJiYgd2luZG93LmNvbnNvbGUudGFibGUpKSkgfHxcblx0XHQvLyBJcyBmaXJlZm94ID49IHYzMT9cblx0XHQvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1Rvb2xzL1dlYl9Db25zb2xlI1N0eWxpbmdfbWVzc2FnZXNcblx0XHQodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudCAmJiBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkubWF0Y2goL2ZpcmVmb3hcXC8oXFxkKykvKSAmJiBwYXJzZUludChSZWdFeHAuJDEsIDEwKSA+PSAzMSkgfHxcblx0XHQvLyBEb3VibGUgY2hlY2sgd2Via2l0IGluIHVzZXJBZ2VudCBqdXN0IGluIGNhc2Ugd2UgYXJlIGluIGEgd29ya2VyXG5cdFx0KHR5cGVvZiBuYXZpZ2F0b3IgIT09ICd1bmRlZmluZWQnICYmIG5hdmlnYXRvci51c2VyQWdlbnQgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudC50b0xvd2VyQ2FzZSgpLm1hdGNoKC9hcHBsZXdlYmtpdFxcLyhcXGQrKS8pKTtcbn1cblxuLyoqXG4gKiBDb2xvcml6ZSBsb2cgYXJndW1lbnRzIGlmIGVuYWJsZWQuXG4gKlxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5mdW5jdGlvbiBmb3JtYXRBcmdzKGFyZ3MpIHtcblx0YXJnc1swXSA9ICh0aGlzLnVzZUNvbG9ycyA/ICclYycgOiAnJykgK1xuXHRcdHRoaXMubmFtZXNwYWNlICtcblx0XHQodGhpcy51c2VDb2xvcnMgPyAnICVjJyA6ICcgJykgK1xuXHRcdGFyZ3NbMF0gK1xuXHRcdCh0aGlzLnVzZUNvbG9ycyA/ICclYyAnIDogJyAnKSArXG5cdFx0JysnICsgbW9kdWxlLmV4cG9ydHMuaHVtYW5pemUodGhpcy5kaWZmKTtcblxuXHRpZiAoIXRoaXMudXNlQ29sb3JzKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0Y29uc3QgYyA9ICdjb2xvcjogJyArIHRoaXMuY29sb3I7XG5cdGFyZ3Muc3BsaWNlKDEsIDAsIGMsICdjb2xvcjogaW5oZXJpdCcpO1xuXG5cdC8vIFRoZSBmaW5hbCBcIiVjXCIgaXMgc29tZXdoYXQgdHJpY2t5LCBiZWNhdXNlIHRoZXJlIGNvdWxkIGJlIG90aGVyXG5cdC8vIGFyZ3VtZW50cyBwYXNzZWQgZWl0aGVyIGJlZm9yZSBvciBhZnRlciB0aGUgJWMsIHNvIHdlIG5lZWQgdG9cblx0Ly8gZmlndXJlIG91dCB0aGUgY29ycmVjdCBpbmRleCB0byBpbnNlcnQgdGhlIENTUyBpbnRvXG5cdGxldCBpbmRleCA9IDA7XG5cdGxldCBsYXN0QyA9IDA7XG5cdGFyZ3NbMF0ucmVwbGFjZSgvJVthLXpBLVolXS9nLCBtYXRjaCA9PiB7XG5cdFx0aWYgKG1hdGNoID09PSAnJSUnKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGluZGV4Kys7XG5cdFx0aWYgKG1hdGNoID09PSAnJWMnKSB7XG5cdFx0XHQvLyBXZSBvbmx5IGFyZSBpbnRlcmVzdGVkIGluIHRoZSAqbGFzdCogJWNcblx0XHRcdC8vICh0aGUgdXNlciBtYXkgaGF2ZSBwcm92aWRlZCB0aGVpciBvd24pXG5cdFx0XHRsYXN0QyA9IGluZGV4O1xuXHRcdH1cblx0fSk7XG5cblx0YXJncy5zcGxpY2UobGFzdEMsIDAsIGMpO1xufVxuXG4vKipcbiAqIEludm9rZXMgYGNvbnNvbGUuZGVidWcoKWAgd2hlbiBhdmFpbGFibGUuXG4gKiBOby1vcCB3aGVuIGBjb25zb2xlLmRlYnVnYCBpcyBub3QgYSBcImZ1bmN0aW9uXCIuXG4gKiBJZiBgY29uc29sZS5kZWJ1Z2AgaXMgbm90IGF2YWlsYWJsZSwgZmFsbHMgYmFja1xuICogdG8gYGNvbnNvbGUubG9nYC5cbiAqXG4gKiBAYXBpIHB1YmxpY1xuICovXG5leHBvcnRzLmxvZyA9IGNvbnNvbGUuZGVidWcgfHwgY29uc29sZS5sb2cgfHwgKCgpID0+IHt9KTtcblxuLyoqXG4gKiBTYXZlIGBuYW1lc3BhY2VzYC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZXNwYWNlc1xuICogQGFwaSBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIHNhdmUobmFtZXNwYWNlcykge1xuXHR0cnkge1xuXHRcdGlmIChuYW1lc3BhY2VzKSB7XG5cdFx0XHRleHBvcnRzLnN0b3JhZ2Uuc2V0SXRlbSgnZGVidWcnLCBuYW1lc3BhY2VzKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZXhwb3J0cy5zdG9yYWdlLnJlbW92ZUl0ZW0oJ2RlYnVnJyk7XG5cdFx0fVxuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdC8vIFN3YWxsb3dcblx0XHQvLyBYWFggKEBRaXgtKSBzaG91bGQgd2UgYmUgbG9nZ2luZyB0aGVzZT9cblx0fVxufVxuXG4vKipcbiAqIExvYWQgYG5hbWVzcGFjZXNgLlxuICpcbiAqIEByZXR1cm4ge1N0cmluZ30gcmV0dXJucyB0aGUgcHJldmlvdXNseSBwZXJzaXN0ZWQgZGVidWcgbW9kZXNcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBsb2FkKCkge1xuXHRsZXQgcjtcblx0dHJ5IHtcblx0XHRyID0gZXhwb3J0cy5zdG9yYWdlLmdldEl0ZW0oJ2RlYnVnJyk7XG5cdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0Ly8gU3dhbGxvd1xuXHRcdC8vIFhYWCAoQFFpeC0pIHNob3VsZCB3ZSBiZSBsb2dnaW5nIHRoZXNlP1xuXHR9XG5cblx0Ly8gSWYgZGVidWcgaXNuJ3Qgc2V0IGluIExTLCBhbmQgd2UncmUgaW4gRWxlY3Ryb24sIHRyeSB0byBsb2FkICRERUJVR1xuXHRpZiAoIXIgJiYgdHlwZW9mIHByb2Nlc3MgIT09ICd1bmRlZmluZWQnICYmICdlbnYnIGluIHByb2Nlc3MpIHtcblx0XHRyID0gcHJvY2Vzcy5lbnYuREVCVUc7XG5cdH1cblxuXHRyZXR1cm4gcjtcbn1cblxuLyoqXG4gKiBMb2NhbHN0b3JhZ2UgYXR0ZW1wdHMgdG8gcmV0dXJuIHRoZSBsb2NhbHN0b3JhZ2UuXG4gKlxuICogVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSBzYWZhcmkgdGhyb3dzXG4gKiB3aGVuIGEgdXNlciBkaXNhYmxlcyBjb29raWVzL2xvY2Fsc3RvcmFnZVxuICogYW5kIHlvdSBhdHRlbXB0IHRvIGFjY2VzcyBpdC5cbiAqXG4gKiBAcmV0dXJuIHtMb2NhbFN0b3JhZ2V9XG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuXG5mdW5jdGlvbiBsb2NhbHN0b3JhZ2UoKSB7XG5cdHRyeSB7XG5cdFx0Ly8gVFZNTEtpdCAoQXBwbGUgVFYgSlMgUnVudGltZSkgZG9lcyBub3QgaGF2ZSBhIHdpbmRvdyBvYmplY3QsIGp1c3QgbG9jYWxTdG9yYWdlIGluIHRoZSBnbG9iYWwgY29udGV4dFxuXHRcdC8vIFRoZSBCcm93c2VyIGFsc28gaGFzIGxvY2FsU3RvcmFnZSBpbiB0aGUgZ2xvYmFsIGNvbnRleHQuXG5cdFx0cmV0dXJuIGxvY2FsU3RvcmFnZTtcblx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHQvLyBTd2FsbG93XG5cdFx0Ly8gWFhYIChAUWl4LSkgc2hvdWxkIHdlIGJlIGxvZ2dpbmcgdGhlc2U/XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL2NvbW1vbicpKGV4cG9ydHMpO1xuXG5jb25zdCB7Zm9ybWF0dGVyc30gPSBtb2R1bGUuZXhwb3J0cztcblxuLyoqXG4gKiBNYXAgJWogdG8gYEpTT04uc3RyaW5naWZ5KClgLCBzaW5jZSBubyBXZWIgSW5zcGVjdG9ycyBkbyB0aGF0IGJ5IGRlZmF1bHQuXG4gKi9cblxuZm9ybWF0dGVycy5qID0gZnVuY3Rpb24gKHYpIHtcblx0dHJ5IHtcblx0XHRyZXR1cm4gSlNPTi5zdHJpbmdpZnkodik7XG5cdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0cmV0dXJuICdbVW5leHBlY3RlZEpTT05QYXJzZUVycm9yXTogJyArIGVycm9yLm1lc3NhZ2U7XG5cdH1cbn07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../../node_modules/debug/src/browser.js\n");
+
+/***/ }),
+
+/***/ "../../../node_modules/debug/src/common.js":
+/*!*************************************************!*\
+ !*** ../../../node_modules/debug/src/common.js ***!
+ \*************************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+eval("\n/**\n * This is the common logic for both the Node.js and web browser\n * implementations of `debug()`.\n */\n\nfunction setup(env) {\n\tcreateDebug.debug = createDebug;\n\tcreateDebug.default = createDebug;\n\tcreateDebug.coerce = coerce;\n\tcreateDebug.disable = disable;\n\tcreateDebug.enable = enable;\n\tcreateDebug.enabled = enabled;\n\tcreateDebug.humanize = __webpack_require__(/*! ms */ \"../../../node_modules/ms/index.js\");\n\tcreateDebug.destroy = destroy;\n\n\tObject.keys(env).forEach(key => {\n\t\tcreateDebug[key] = env[key];\n\t});\n\n\t/**\n\t* The currently active debug mode names, and names to skip.\n\t*/\n\n\tcreateDebug.names = [];\n\tcreateDebug.skips = [];\n\n\t/**\n\t* Map of special \"%n\" handling functions, for the debug \"format\" argument.\n\t*\n\t* Valid key names are a single, lower or upper-case letter, i.e. \"n\" and \"N\".\n\t*/\n\tcreateDebug.formatters = {};\n\n\t/**\n\t* Selects a color for a debug namespace\n\t* @param {String} namespace The namespace string for the debug instance to be colored\n\t* @return {Number|String} An ANSI color code for the given namespace\n\t* @api private\n\t*/\n\tfunction selectColor(namespace) {\n\t\tlet hash = 0;\n\n\t\tfor (let i = 0; i < namespace.length; i++) {\n\t\t\thash = ((hash << 5) - hash) + namespace.charCodeAt(i);\n\t\t\thash |= 0; // Convert to 32bit integer\n\t\t}\n\n\t\treturn createDebug.colors[Math.abs(hash) % createDebug.colors.length];\n\t}\n\tcreateDebug.selectColor = selectColor;\n\n\t/**\n\t* Create a debugger with the given `namespace`.\n\t*\n\t* @param {String} namespace\n\t* @return {Function}\n\t* @api public\n\t*/\n\tfunction createDebug(namespace) {\n\t\tlet prevTime;\n\t\tlet enableOverride = null;\n\t\tlet namespacesCache;\n\t\tlet enabledCache;\n\n\t\tfunction debug(...args) {\n\t\t\t// Disabled?\n\t\t\tif (!debug.enabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst self = debug;\n\n\t\t\t// Set `diff` timestamp\n\t\t\tconst curr = Number(new Date());\n\t\t\tconst ms = curr - (prevTime || curr);\n\t\t\tself.diff = ms;\n\t\t\tself.prev = prevTime;\n\t\t\tself.curr = curr;\n\t\t\tprevTime = curr;\n\n\t\t\targs[0] = createDebug.coerce(args[0]);\n\n\t\t\tif (typeof args[0] !== 'string') {\n\t\t\t\t// Anything else let's inspect with %O\n\t\t\t\targs.unshift('%O');\n\t\t\t}\n\n\t\t\t// Apply any `formatters` transformations\n\t\t\tlet index = 0;\n\t\t\targs[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {\n\t\t\t\t// If we encounter an escaped % then don't increase the array index\n\t\t\t\tif (match === '%%') {\n\t\t\t\t\treturn '%';\n\t\t\t\t}\n\t\t\t\tindex++;\n\t\t\t\tconst formatter = createDebug.formatters[format];\n\t\t\t\tif (typeof formatter === 'function') {\n\t\t\t\t\tconst val = args[index];\n\t\t\t\t\tmatch = formatter.call(self, val);\n\n\t\t\t\t\t// Now we need to remove `args[index]` since it's inlined in the `format`\n\t\t\t\t\targs.splice(index, 1);\n\t\t\t\t\tindex--;\n\t\t\t\t}\n\t\t\t\treturn match;\n\t\t\t});\n\n\t\t\t// Apply env-specific formatting (colors, etc.)\n\t\t\tcreateDebug.formatArgs.call(self, args);\n\n\t\t\tconst logFn = self.log || createDebug.log;\n\t\t\tlogFn.apply(self, args);\n\t\t}\n\n\t\tdebug.namespace = namespace;\n\t\tdebug.useColors = createDebug.useColors();\n\t\tdebug.color = createDebug.selectColor(namespace);\n\t\tdebug.extend = extend;\n\t\tdebug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.\n\n\t\tObject.defineProperty(debug, 'enabled', {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t\tget: () => {\n\t\t\t\tif (enableOverride !== null) {\n\t\t\t\t\treturn enableOverride;\n\t\t\t\t}\n\t\t\t\tif (namespacesCache !== createDebug.namespaces) {\n\t\t\t\t\tnamespacesCache = createDebug.namespaces;\n\t\t\t\t\tenabledCache = createDebug.enabled(namespace);\n\t\t\t\t}\n\n\t\t\t\treturn enabledCache;\n\t\t\t},\n\t\t\tset: v => {\n\t\t\t\tenableOverride = v;\n\t\t\t}\n\t\t});\n\n\t\t// Env-specific initialization logic for debug instances\n\t\tif (typeof createDebug.init === 'function') {\n\t\t\tcreateDebug.init(debug);\n\t\t}\n\n\t\treturn debug;\n\t}\n\n\tfunction extend(namespace, delimiter) {\n\t\tconst newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);\n\t\tnewDebug.log = this.log;\n\t\treturn newDebug;\n\t}\n\n\t/**\n\t* Enables a debug mode by namespaces. This can include modes\n\t* separated by a colon and wildcards.\n\t*\n\t* @param {String} namespaces\n\t* @api public\n\t*/\n\tfunction enable(namespaces) {\n\t\tcreateDebug.save(namespaces);\n\t\tcreateDebug.namespaces = namespaces;\n\n\t\tcreateDebug.names = [];\n\t\tcreateDebug.skips = [];\n\n\t\tlet i;\n\t\tconst split = (typeof namespaces === 'string' ? namespaces : '').split(/[\\s,]+/);\n\t\tconst len = split.length;\n\n\t\tfor (i = 0; i < len; i++) {\n\t\t\tif (!split[i]) {\n\t\t\t\t// ignore empty strings\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tnamespaces = split[i].replace(/\\*/g, '.*?');\n\n\t\t\tif (namespaces[0] === '-') {\n\t\t\t\tcreateDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));\n\t\t\t} else {\n\t\t\t\tcreateDebug.names.push(new RegExp('^' + namespaces + '$'));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t* Disable debug output.\n\t*\n\t* @return {String} namespaces\n\t* @api public\n\t*/\n\tfunction disable() {\n\t\tconst namespaces = [\n\t\t\t...createDebug.names.map(toNamespace),\n\t\t\t...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)\n\t\t].join(',');\n\t\tcreateDebug.enable('');\n\t\treturn namespaces;\n\t}\n\n\t/**\n\t* Returns true if the given mode name is enabled, false otherwise.\n\t*\n\t* @param {String} name\n\t* @return {Boolean}\n\t* @api public\n\t*/\n\tfunction enabled(name) {\n\t\tif (name[name.length - 1] === '*') {\n\t\t\treturn true;\n\t\t}\n\n\t\tlet i;\n\t\tlet len;\n\n\t\tfor (i = 0, len = createDebug.skips.length; i < len; i++) {\n\t\t\tif (createDebug.skips[i].test(name)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tfor (i = 0, len = createDebug.names.length; i < len; i++) {\n\t\t\tif (createDebug.names[i].test(name)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t* Convert regexp to namespace\n\t*\n\t* @param {RegExp} regxep\n\t* @return {String} namespace\n\t* @api private\n\t*/\n\tfunction toNamespace(regexp) {\n\t\treturn regexp.toString()\n\t\t\t.substring(2, regexp.toString().length - 2)\n\t\t\t.replace(/\\.\\*\\?$/, '*');\n\t}\n\n\t/**\n\t* Coerce `val`.\n\t*\n\t* @param {Mixed} val\n\t* @return {Mixed}\n\t* @api private\n\t*/\n\tfunction coerce(val) {\n\t\tif (val instanceof Error) {\n\t\t\treturn val.stack || val.message;\n\t\t}\n\t\treturn val;\n\t}\n\n\t/**\n\t* XXX DO NOT USE. This is a temporary stub function.\n\t* XXX It WILL be removed in the next major release.\n\t*/\n\tfunction destroy() {\n\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t}\n\n\tcreateDebug.enable(createDebug.load());\n\n\treturn createDebug;\n}\n\nmodule.exports = setup;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2RlYnVnL3NyYy9jb21tb24uanMuanMiLCJtYXBwaW5ncyI6IjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLG1CQUFPLENBQUMsNkNBQUk7QUFDcEM7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsWUFBWSxlQUFlO0FBQzNCO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtCQUFrQixzQkFBc0I7QUFDeEM7QUFDQSxjQUFjO0FBQ2Q7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQixZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUM7O0FBRXZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxRQUFRO0FBQ25CLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSw4Q0FBOEMsU0FBUztBQUN2RDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSw4Q0FBOEMsU0FBUztBQUN2RDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQixZQUFZLFFBQVE7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxPQUFPO0FBQ2xCLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2RlYnVnL3NyYy9jb21tb24uanM/YmRlMiJdLCJzb3VyY2VzQ29udGVudCI6WyJcbi8qKlxuICogVGhpcyBpcyB0aGUgY29tbW9uIGxvZ2ljIGZvciBib3RoIHRoZSBOb2RlLmpzIGFuZCB3ZWIgYnJvd3NlclxuICogaW1wbGVtZW50YXRpb25zIG9mIGBkZWJ1ZygpYC5cbiAqL1xuXG5mdW5jdGlvbiBzZXR1cChlbnYpIHtcblx0Y3JlYXRlRGVidWcuZGVidWcgPSBjcmVhdGVEZWJ1Zztcblx0Y3JlYXRlRGVidWcuZGVmYXVsdCA9IGNyZWF0ZURlYnVnO1xuXHRjcmVhdGVEZWJ1Zy5jb2VyY2UgPSBjb2VyY2U7XG5cdGNyZWF0ZURlYnVnLmRpc2FibGUgPSBkaXNhYmxlO1xuXHRjcmVhdGVEZWJ1Zy5lbmFibGUgPSBlbmFibGU7XG5cdGNyZWF0ZURlYnVnLmVuYWJsZWQgPSBlbmFibGVkO1xuXHRjcmVhdGVEZWJ1Zy5odW1hbml6ZSA9IHJlcXVpcmUoJ21zJyk7XG5cdGNyZWF0ZURlYnVnLmRlc3Ryb3kgPSBkZXN0cm95O1xuXG5cdE9iamVjdC5rZXlzKGVudikuZm9yRWFjaChrZXkgPT4ge1xuXHRcdGNyZWF0ZURlYnVnW2tleV0gPSBlbnZba2V5XTtcblx0fSk7XG5cblx0LyoqXG5cdCogVGhlIGN1cnJlbnRseSBhY3RpdmUgZGVidWcgbW9kZSBuYW1lcywgYW5kIG5hbWVzIHRvIHNraXAuXG5cdCovXG5cblx0Y3JlYXRlRGVidWcubmFtZXMgPSBbXTtcblx0Y3JlYXRlRGVidWcuc2tpcHMgPSBbXTtcblxuXHQvKipcblx0KiBNYXAgb2Ygc3BlY2lhbCBcIiVuXCIgaGFuZGxpbmcgZnVuY3Rpb25zLCBmb3IgdGhlIGRlYnVnIFwiZm9ybWF0XCIgYXJndW1lbnQuXG5cdCpcblx0KiBWYWxpZCBrZXkgbmFtZXMgYXJlIGEgc2luZ2xlLCBsb3dlciBvciB1cHBlci1jYXNlIGxldHRlciwgaS5lLiBcIm5cIiBhbmQgXCJOXCIuXG5cdCovXG5cdGNyZWF0ZURlYnVnLmZvcm1hdHRlcnMgPSB7fTtcblxuXHQvKipcblx0KiBTZWxlY3RzIGEgY29sb3IgZm9yIGEgZGVidWcgbmFtZXNwYWNlXG5cdCogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZSBUaGUgbmFtZXNwYWNlIHN0cmluZyBmb3IgdGhlIGRlYnVnIGluc3RhbmNlIHRvIGJlIGNvbG9yZWRcblx0KiBAcmV0dXJuIHtOdW1iZXJ8U3RyaW5nfSBBbiBBTlNJIGNvbG9yIGNvZGUgZm9yIHRoZSBnaXZlbiBuYW1lc3BhY2Vcblx0KiBAYXBpIHByaXZhdGVcblx0Ki9cblx0ZnVuY3Rpb24gc2VsZWN0Q29sb3IobmFtZXNwYWNlKSB7XG5cdFx0bGV0IGhhc2ggPSAwO1xuXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBuYW1lc3BhY2UubGVuZ3RoOyBpKyspIHtcblx0XHRcdGhhc2ggPSAoKGhhc2ggPDwgNSkgLSBoYXNoKSArIG5hbWVzcGFjZS5jaGFyQ29kZUF0KGkpO1xuXHRcdFx0aGFzaCB8PSAwOyAvLyBDb252ZXJ0IHRvIDMyYml0IGludGVnZXJcblx0XHR9XG5cblx0XHRyZXR1cm4gY3JlYXRlRGVidWcuY29sb3JzW01hdGguYWJzKGhhc2gpICUgY3JlYXRlRGVidWcuY29sb3JzLmxlbmd0aF07XG5cdH1cblx0Y3JlYXRlRGVidWcuc2VsZWN0Q29sb3IgPSBzZWxlY3RDb2xvcjtcblxuXHQvKipcblx0KiBDcmVhdGUgYSBkZWJ1Z2dlciB3aXRoIHRoZSBnaXZlbiBgbmFtZXNwYWNlYC5cblx0KlxuXHQqIEBwYXJhbSB7U3RyaW5nfSBuYW1lc3BhY2Vcblx0KiBAcmV0dXJuIHtGdW5jdGlvbn1cblx0KiBAYXBpIHB1YmxpY1xuXHQqL1xuXHRmdW5jdGlvbiBjcmVhdGVEZWJ1ZyhuYW1lc3BhY2UpIHtcblx0XHRsZXQgcHJldlRpbWU7XG5cdFx0bGV0IGVuYWJsZU92ZXJyaWRlID0gbnVsbDtcblx0XHRsZXQgbmFtZXNwYWNlc0NhY2hlO1xuXHRcdGxldCBlbmFibGVkQ2FjaGU7XG5cblx0XHRmdW5jdGlvbiBkZWJ1ZyguLi5hcmdzKSB7XG5cdFx0XHQvLyBEaXNhYmxlZD9cblx0XHRcdGlmICghZGVidWcuZW5hYmxlZCkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHNlbGYgPSBkZWJ1ZztcblxuXHRcdFx0Ly8gU2V0IGBkaWZmYCB0aW1lc3RhbXBcblx0XHRcdGNvbnN0IGN1cnIgPSBOdW1iZXIobmV3IERhdGUoKSk7XG5cdFx0XHRjb25zdCBtcyA9IGN1cnIgLSAocHJldlRpbWUgfHwgY3Vycik7XG5cdFx0XHRzZWxmLmRpZmYgPSBtcztcblx0XHRcdHNlbGYucHJldiA9IHByZXZUaW1lO1xuXHRcdFx0c2VsZi5jdXJyID0gY3Vycjtcblx0XHRcdHByZXZUaW1lID0gY3VycjtcblxuXHRcdFx0YXJnc1swXSA9IGNyZWF0ZURlYnVnLmNvZXJjZShhcmdzWzBdKTtcblxuXHRcdFx0aWYgKHR5cGVvZiBhcmdzWzBdICE9PSAnc3RyaW5nJykge1xuXHRcdFx0XHQvLyBBbnl0aGluZyBlbHNlIGxldCdzIGluc3BlY3Qgd2l0aCAlT1xuXHRcdFx0XHRhcmdzLnVuc2hpZnQoJyVPJyk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFwcGx5IGFueSBgZm9ybWF0dGVyc2AgdHJhbnNmb3JtYXRpb25zXG5cdFx0XHRsZXQgaW5kZXggPSAwO1xuXHRcdFx0YXJnc1swXSA9IGFyZ3NbMF0ucmVwbGFjZSgvJShbYS16QS1aJV0pL2csIChtYXRjaCwgZm9ybWF0KSA9PiB7XG5cdFx0XHRcdC8vIElmIHdlIGVuY291bnRlciBhbiBlc2NhcGVkICUgdGhlbiBkb24ndCBpbmNyZWFzZSB0aGUgYXJyYXkgaW5kZXhcblx0XHRcdFx0aWYgKG1hdGNoID09PSAnJSUnKSB7XG5cdFx0XHRcdFx0cmV0dXJuICclJztcblx0XHRcdFx0fVxuXHRcdFx0XHRpbmRleCsrO1xuXHRcdFx0XHRjb25zdCBmb3JtYXR0ZXIgPSBjcmVhdGVEZWJ1Zy5mb3JtYXR0ZXJzW2Zvcm1hdF07XG5cdFx0XHRcdGlmICh0eXBlb2YgZm9ybWF0dGVyID09PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRcdFx0Y29uc3QgdmFsID0gYXJnc1tpbmRleF07XG5cdFx0XHRcdFx0bWF0Y2ggPSBmb3JtYXR0ZXIuY2FsbChzZWxmLCB2YWwpO1xuXG5cdFx0XHRcdFx0Ly8gTm93IHdlIG5lZWQgdG8gcmVtb3ZlIGBhcmdzW2luZGV4XWAgc2luY2UgaXQncyBpbmxpbmVkIGluIHRoZSBgZm9ybWF0YFxuXHRcdFx0XHRcdGFyZ3Muc3BsaWNlKGluZGV4LCAxKTtcblx0XHRcdFx0XHRpbmRleC0tO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBtYXRjaDtcblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBBcHBseSBlbnYtc3BlY2lmaWMgZm9ybWF0dGluZyAoY29sb3JzLCBldGMuKVxuXHRcdFx0Y3JlYXRlRGVidWcuZm9ybWF0QXJncy5jYWxsKHNlbGYsIGFyZ3MpO1xuXG5cdFx0XHRjb25zdCBsb2dGbiA9IHNlbGYubG9nIHx8IGNyZWF0ZURlYnVnLmxvZztcblx0XHRcdGxvZ0ZuLmFwcGx5KHNlbGYsIGFyZ3MpO1xuXHRcdH1cblxuXHRcdGRlYnVnLm5hbWVzcGFjZSA9IG5hbWVzcGFjZTtcblx0XHRkZWJ1Zy51c2VDb2xvcnMgPSBjcmVhdGVEZWJ1Zy51c2VDb2xvcnMoKTtcblx0XHRkZWJ1Zy5jb2xvciA9IGNyZWF0ZURlYnVnLnNlbGVjdENvbG9yKG5hbWVzcGFjZSk7XG5cdFx0ZGVidWcuZXh0ZW5kID0gZXh0ZW5kO1xuXHRcdGRlYnVnLmRlc3Ryb3kgPSBjcmVhdGVEZWJ1Zy5kZXN0cm95OyAvLyBYWFggVGVtcG9yYXJ5LiBXaWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5leHQgbWFqb3IgcmVsZWFzZS5cblxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShkZWJ1ZywgJ2VuYWJsZWQnLCB7XG5cdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuXHRcdFx0Y29uZmlndXJhYmxlOiBmYWxzZSxcblx0XHRcdGdldDogKCkgPT4ge1xuXHRcdFx0XHRpZiAoZW5hYmxlT3ZlcnJpZGUgIT09IG51bGwpIHtcblx0XHRcdFx0XHRyZXR1cm4gZW5hYmxlT3ZlcnJpZGU7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKG5hbWVzcGFjZXNDYWNoZSAhPT0gY3JlYXRlRGVidWcubmFtZXNwYWNlcykge1xuXHRcdFx0XHRcdG5hbWVzcGFjZXNDYWNoZSA9IGNyZWF0ZURlYnVnLm5hbWVzcGFjZXM7XG5cdFx0XHRcdFx0ZW5hYmxlZENhY2hlID0gY3JlYXRlRGVidWcuZW5hYmxlZChuYW1lc3BhY2UpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIGVuYWJsZWRDYWNoZTtcblx0XHRcdH0sXG5cdFx0XHRzZXQ6IHYgPT4ge1xuXHRcdFx0XHRlbmFibGVPdmVycmlkZSA9IHY7XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvLyBFbnYtc3BlY2lmaWMgaW5pdGlhbGl6YXRpb24gbG9naWMgZm9yIGRlYnVnIGluc3RhbmNlc1xuXHRcdGlmICh0eXBlb2YgY3JlYXRlRGVidWcuaW5pdCA9PT0gJ2Z1bmN0aW9uJykge1xuXHRcdFx0Y3JlYXRlRGVidWcuaW5pdChkZWJ1Zyk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRlYnVnO1xuXHR9XG5cblx0ZnVuY3Rpb24gZXh0ZW5kKG5hbWVzcGFjZSwgZGVsaW1pdGVyKSB7XG5cdFx0Y29uc3QgbmV3RGVidWcgPSBjcmVhdGVEZWJ1Zyh0aGlzLm5hbWVzcGFjZSArICh0eXBlb2YgZGVsaW1pdGVyID09PSAndW5kZWZpbmVkJyA/ICc6JyA6IGRlbGltaXRlcikgKyBuYW1lc3BhY2UpO1xuXHRcdG5ld0RlYnVnLmxvZyA9IHRoaXMubG9nO1xuXHRcdHJldHVybiBuZXdEZWJ1Zztcblx0fVxuXG5cdC8qKlxuXHQqIEVuYWJsZXMgYSBkZWJ1ZyBtb2RlIGJ5IG5hbWVzcGFjZXMuIFRoaXMgY2FuIGluY2x1ZGUgbW9kZXNcblx0KiBzZXBhcmF0ZWQgYnkgYSBjb2xvbiBhbmQgd2lsZGNhcmRzLlxuXHQqXG5cdCogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZXNcblx0KiBAYXBpIHB1YmxpY1xuXHQqL1xuXHRmdW5jdGlvbiBlbmFibGUobmFtZXNwYWNlcykge1xuXHRcdGNyZWF0ZURlYnVnLnNhdmUobmFtZXNwYWNlcyk7XG5cdFx0Y3JlYXRlRGVidWcubmFtZXNwYWNlcyA9IG5hbWVzcGFjZXM7XG5cblx0XHRjcmVhdGVEZWJ1Zy5uYW1lcyA9IFtdO1xuXHRcdGNyZWF0ZURlYnVnLnNraXBzID0gW107XG5cblx0XHRsZXQgaTtcblx0XHRjb25zdCBzcGxpdCA9ICh0eXBlb2YgbmFtZXNwYWNlcyA9PT0gJ3N0cmluZycgPyBuYW1lc3BhY2VzIDogJycpLnNwbGl0KC9bXFxzLF0rLyk7XG5cdFx0Y29uc3QgbGVuID0gc3BsaXQubGVuZ3RoO1xuXG5cdFx0Zm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRpZiAoIXNwbGl0W2ldKSB7XG5cdFx0XHRcdC8vIGlnbm9yZSBlbXB0eSBzdHJpbmdzXG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHRuYW1lc3BhY2VzID0gc3BsaXRbaV0ucmVwbGFjZSgvXFwqL2csICcuKj8nKTtcblxuXHRcdFx0aWYgKG5hbWVzcGFjZXNbMF0gPT09ICctJykge1xuXHRcdFx0XHRjcmVhdGVEZWJ1Zy5za2lwcy5wdXNoKG5ldyBSZWdFeHAoJ14nICsgbmFtZXNwYWNlcy5zbGljZSgxKSArICckJykpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y3JlYXRlRGVidWcubmFtZXMucHVzaChuZXcgUmVnRXhwKCdeJyArIG5hbWVzcGFjZXMgKyAnJCcpKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvKipcblx0KiBEaXNhYmxlIGRlYnVnIG91dHB1dC5cblx0KlxuXHQqIEByZXR1cm4ge1N0cmluZ30gbmFtZXNwYWNlc1xuXHQqIEBhcGkgcHVibGljXG5cdCovXG5cdGZ1bmN0aW9uIGRpc2FibGUoKSB7XG5cdFx0Y29uc3QgbmFtZXNwYWNlcyA9IFtcblx0XHRcdC4uLmNyZWF0ZURlYnVnLm5hbWVzLm1hcCh0b05hbWVzcGFjZSksXG5cdFx0XHQuLi5jcmVhdGVEZWJ1Zy5za2lwcy5tYXAodG9OYW1lc3BhY2UpLm1hcChuYW1lc3BhY2UgPT4gJy0nICsgbmFtZXNwYWNlKVxuXHRcdF0uam9pbignLCcpO1xuXHRcdGNyZWF0ZURlYnVnLmVuYWJsZSgnJyk7XG5cdFx0cmV0dXJuIG5hbWVzcGFjZXM7XG5cdH1cblxuXHQvKipcblx0KiBSZXR1cm5zIHRydWUgaWYgdGhlIGdpdmVuIG1vZGUgbmFtZSBpcyBlbmFibGVkLCBmYWxzZSBvdGhlcndpc2UuXG5cdCpcblx0KiBAcGFyYW0ge1N0cmluZ30gbmFtZVxuXHQqIEByZXR1cm4ge0Jvb2xlYW59XG5cdCogQGFwaSBwdWJsaWNcblx0Ki9cblx0ZnVuY3Rpb24gZW5hYmxlZChuYW1lKSB7XG5cdFx0aWYgKG5hbWVbbmFtZS5sZW5ndGggLSAxXSA9PT0gJyonKSB7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cblx0XHRsZXQgaTtcblx0XHRsZXQgbGVuO1xuXG5cdFx0Zm9yIChpID0gMCwgbGVuID0gY3JlYXRlRGVidWcuc2tpcHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdGlmIChjcmVhdGVEZWJ1Zy5za2lwc1tpXS50ZXN0KG5hbWUpKSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjcmVhdGVEZWJ1Zy5uYW1lcy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0aWYgKGNyZWF0ZURlYnVnLm5hbWVzW2ldLnRlc3QobmFtZSkpIHtcblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG5cblx0LyoqXG5cdCogQ29udmVydCByZWdleHAgdG8gbmFtZXNwYWNlXG5cdCpcblx0KiBAcGFyYW0ge1JlZ0V4cH0gcmVneGVwXG5cdCogQHJldHVybiB7U3RyaW5nfSBuYW1lc3BhY2Vcblx0KiBAYXBpIHByaXZhdGVcblx0Ki9cblx0ZnVuY3Rpb24gdG9OYW1lc3BhY2UocmVnZXhwKSB7XG5cdFx0cmV0dXJuIHJlZ2V4cC50b1N0cmluZygpXG5cdFx0XHQuc3Vic3RyaW5nKDIsIHJlZ2V4cC50b1N0cmluZygpLmxlbmd0aCAtIDIpXG5cdFx0XHQucmVwbGFjZSgvXFwuXFwqXFw/JC8sICcqJyk7XG5cdH1cblxuXHQvKipcblx0KiBDb2VyY2UgYHZhbGAuXG5cdCpcblx0KiBAcGFyYW0ge01peGVkfSB2YWxcblx0KiBAcmV0dXJuIHtNaXhlZH1cblx0KiBAYXBpIHByaXZhdGVcblx0Ki9cblx0ZnVuY3Rpb24gY29lcmNlKHZhbCkge1xuXHRcdGlmICh2YWwgaW5zdGFuY2VvZiBFcnJvcikge1xuXHRcdFx0cmV0dXJuIHZhbC5zdGFjayB8fCB2YWwubWVzc2FnZTtcblx0XHR9XG5cdFx0cmV0dXJuIHZhbDtcblx0fVxuXG5cdC8qKlxuXHQqIFhYWCBETyBOT1QgVVNFLiBUaGlzIGlzIGEgdGVtcG9yYXJ5IHN0dWIgZnVuY3Rpb24uXG5cdCogWFhYIEl0IFdJTEwgYmUgcmVtb3ZlZCBpbiB0aGUgbmV4dCBtYWpvciByZWxlYXNlLlxuXHQqL1xuXHRmdW5jdGlvbiBkZXN0cm95KCkge1xuXHRcdGNvbnNvbGUud2FybignSW5zdGFuY2UgbWV0aG9kIGBkZWJ1Zy5kZXN0cm95KClgIGlzIGRlcHJlY2F0ZWQgYW5kIG5vIGxvbmdlciBkb2VzIGFueXRoaW5nLiBJdCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5leHQgbWFqb3IgdmVyc2lvbiBvZiBgZGVidWdgLicpO1xuXHR9XG5cblx0Y3JlYXRlRGVidWcuZW5hYmxlKGNyZWF0ZURlYnVnLmxvYWQoKSk7XG5cblx0cmV0dXJuIGNyZWF0ZURlYnVnO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHNldHVwO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../../node_modules/debug/src/common.js\n");
+
+/***/ }),
+
+/***/ "../../../node_modules/dompurify/dist/purify.js":
+/*!******************************************************!*\
+ !*** ../../../node_modules/dompurify/dist/purify.js ***!
+ \******************************************************/
+/***/ (function(module) {
+
+eval("/*! @license DOMPurify 3.0.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.0.3/LICENSE */\n\n(function (global, factory) {\n true ? module.exports = factory() :\n 0;\n})(this, (function () { 'use strict';\n\n const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor\n } = Object;\n let {\n freeze,\n seal,\n create\n } = Object; // eslint-disable-line import/no-mutable-exports\n\n let {\n apply,\n construct\n } = typeof Reflect !== 'undefined' && Reflect;\n\n if (!apply) {\n apply = function apply(fun, thisValue, args) {\n return fun.apply(thisValue, args);\n };\n }\n\n if (!freeze) {\n freeze = function freeze(x) {\n return x;\n };\n }\n\n if (!seal) {\n seal = function seal(x) {\n return x;\n };\n }\n\n if (!construct) {\n construct = function construct(Func, args) {\n return new Func(...args);\n };\n }\n\n const arrayForEach = unapply(Array.prototype.forEach);\n const arrayPop = unapply(Array.prototype.pop);\n const arrayPush = unapply(Array.prototype.push);\n const stringToLowerCase = unapply(String.prototype.toLowerCase);\n const stringToString = unapply(String.prototype.toString);\n const stringMatch = unapply(String.prototype.match);\n const stringReplace = unapply(String.prototype.replace);\n const stringIndexOf = unapply(String.prototype.indexOf);\n const stringTrim = unapply(String.prototype.trim);\n const regExpTest = unapply(RegExp.prototype.test);\n const typeErrorCreate = unconstruct(TypeError);\n function unapply(func) {\n return function (thisArg) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n return apply(func, thisArg, args);\n };\n }\n function unconstruct(func) {\n return function () {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n\n return construct(func, args);\n };\n }\n /* Add properties to a lookup table */\n\n function addToSet(set, array, transformCaseFunc) {\n var _transformCaseFunc;\n\n transformCaseFunc = (_transformCaseFunc = transformCaseFunc) !== null && _transformCaseFunc !== void 0 ? _transformCaseFunc : stringToLowerCase;\n\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n\n let l = array.length;\n\n while (l--) {\n let element = array[l];\n\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n array[l] = lcElement;\n }\n\n element = lcElement;\n }\n }\n\n set[element] = true;\n }\n\n return set;\n }\n /* Shallow clone an object */\n\n function clone(object) {\n const newObject = create(null);\n\n for (const [property, value] of entries(object)) {\n newObject[property] = value;\n }\n\n return newObject;\n }\n /* This method automatically checks if the prop is function\n * or getter and behaves accordingly. */\n\n function lookupGetter(object, prop) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n\n object = getPrototypeOf(object);\n }\n\n function fallbackValue(element) {\n console.warn('fallback value for', element);\n return null;\n }\n\n return fallbackValue;\n }\n\n const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']); // SVG\n\n const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);\n const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']); // List of SVG elements that are disallowed by default.\n // We still need to know them so that we can do namespace\n // checks properly in case one wants to add them to\n // allow-list.\n\n const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);\n const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']); // Similarly to SVG, we want to know all MathML elements,\n // even those that we disallow by default.\n\n const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);\n const text = freeze(['#text']);\n\n const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);\n const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);\n const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);\n const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);\n\n const MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\n\n const ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\n const TMPLIT_EXPR = seal(/\\${[\\w\\W]*}/gm);\n const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\n\n const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\n\n const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n );\n const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\n const ATTR_WHITESPACE = seal(/[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n );\n const DOCTYPE_NAME = seal(/^html$/i);\n\n var EXPRESSIONS = /*#__PURE__*/Object.freeze({\n __proto__: null,\n MUSTACHE_EXPR: MUSTACHE_EXPR,\n ERB_EXPR: ERB_EXPR,\n TMPLIT_EXPR: TMPLIT_EXPR,\n DATA_ATTR: DATA_ATTR,\n ARIA_ATTR: ARIA_ATTR,\n IS_ALLOWED_URI: IS_ALLOWED_URI,\n IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE: ATTR_WHITESPACE,\n DOCTYPE_NAME: DOCTYPE_NAME\n });\n\n const getGlobal = () => typeof window === 'undefined' ? null : window;\n /**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\n\n\n const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {\n if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {\n return null;\n } // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n\n\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n\n createScriptURL(scriptUrl) {\n return scriptUrl;\n }\n\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn('TrustedTypes policy ' + policyName + ' could not be created.');\n return null;\n }\n };\n\n function createDOMPurify() {\n let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();\n\n const DOMPurify = root => createDOMPurify(root);\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n\n\n DOMPurify.version = '3.0.3';\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n\n DOMPurify.removed = [];\n\n if (!window || !window.document || window.document.nodeType !== 9) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n return DOMPurify;\n }\n\n const originalDocument = window.document;\n const currentScript = originalDocument.currentScript;\n let {\n document\n } = window;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes\n } = window;\n const ElementPrototype = Element.prototype;\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n\n let trustedTypesPolicy;\n let emptyHTML = '';\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName\n } = document;\n const {\n importNode\n } = originalDocument;\n let hooks = {};\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n\n DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE\n } = EXPRESSIONS;\n let {\n IS_ALLOWED_URI: IS_ALLOWED_URI$1\n } = EXPRESSIONS;\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);\n /* Allowed attribute names */\n\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);\n /*\n * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n\n let CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false\n }\n }));\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n\n let FORBID_TAGS = null;\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n\n let FORBID_ATTR = null;\n /* Decide if ARIA attributes are okay */\n\n let ALLOW_ARIA_ATTR = true;\n /* Decide if custom data attributes are okay */\n\n let ALLOW_DATA_ATTR = true;\n /* Decide if unknown protocols are okay */\n\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n\n let SAFE_FOR_TEMPLATES = false;\n /* Decide if document with ... should be returned */\n\n let WHOLE_DOCUMENT = false;\n /* Track whether config is already set on this instance of DOMPurify. */\n\n let SET_CONFIG = false;\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n\n let FORCE_BODY = false;\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n\n let RETURN_DOM = false;\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n\n let RETURN_DOM_FRAGMENT = false;\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n\n let RETURN_TRUSTED_TYPE = false;\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n\n let SANITIZE_DOM = true;\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (§7.3.3)\n * - DOM Tree Accessors (§3.1.5)\n * - Form Element Parent-Child Relations (§4.10.3)\n * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n * - HTMLCollection (§4.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n /* Keep element content when removing element? */\n\n let KEEP_CONTENT = true;\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n\n let IN_PLACE = false;\n /* Allow usage of profiles like html, svg and mathMl */\n\n let USE_PROFILES = {};\n /* Tags to ignore content of when KEEP_CONTENT is true */\n\n let FORBID_CONTENTS = null;\n const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);\n /* Tags that are safe for data: URIs */\n\n let DATA_URI_TAGS = null;\n const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);\n /* Attributes safe for values like \"javascript:\" */\n\n let URI_SAFE_ATTRIBUTES = null;\n const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);\n const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n /* Document namespace */\n\n let NAMESPACE = HTML_NAMESPACE;\n let IS_EMPTY_INPUT = false;\n /* Allowed XHTML+XML namespaces */\n\n let ALLOWED_NAMESPACES = null;\n const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);\n /* Parsing of strict XHTML documents */\n\n let PARSER_MEDIA_TYPE;\n const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n let transformCaseFunc;\n /* Keep a reference to config to pass to hooks */\n\n let CONFIG = null;\n /* Ideally, do not touch anything below this line */\n\n /* ______________________________________________ */\n\n const formElement = document.createElement('form');\n\n const isRegexOrFunction = function isRegexOrFunction(testValue) {\n return testValue instanceof RegExp || testValue instanceof Function;\n };\n /**\n * _parseConfig\n *\n * @param {Object} cfg optional config literal\n */\n // eslint-disable-next-line complexity\n\n\n const _parseConfig = function _parseConfig(cfg) {\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n /* Shield configuration object from tampering */\n\n\n if (!cfg || typeof cfg !== 'object') {\n cfg = {};\n }\n /* Shield configuration object from prototype pollution */\n\n\n cfg = clone(cfg);\n PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes\n SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE; // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n\n transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;\n /* Set configuration parameters */\n\n ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;\n ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;\n URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent\n cfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent\n cfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_DATA_URI_TAGS;\n FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;\n FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};\n FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};\n USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n\n ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n\n SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n\n IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;\n NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n }\n\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n }\n\n if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n }\n\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n /* Parse profile info */\n\n\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, [...text]);\n ALLOWED_ATTR = [];\n\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, html$1);\n addToSet(ALLOWED_ATTR, html);\n }\n\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, svg$1);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, svgFilters);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, mathMl$1);\n addToSet(ALLOWED_ATTR, mathMl);\n addToSet(ALLOWED_ATTR, xml);\n }\n }\n /* Merge configuration parameters */\n\n\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n }\n\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n }\n\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n }\n\n if (cfg.FORBID_CONTENTS) {\n if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n FORBID_CONTENTS = clone(FORBID_CONTENTS);\n }\n\n addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n }\n /* Add #text in case KEEP_CONTENT is set to true */\n\n\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n\n\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n\n\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n\n if (cfg.TRUSTED_TYPES_POLICY) {\n if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.');\n }\n\n if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.');\n } // Overwrite existing TrustedTypes policy.\n\n\n trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; // Sign local variables required by `sanitize`.\n\n emptyHTML = trustedTypesPolicy.createHTML('');\n } else {\n // Uninitialized policy, attempt to initialize the internal dompurify policy.\n if (trustedTypesPolicy === undefined) {\n trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);\n } // If creating the internal policy succeeded sign internal variables.\n\n\n if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n emptyHTML = trustedTypesPolicy.createHTML('');\n }\n } // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n\n\n if (freeze) {\n freeze(cfg);\n }\n\n CONFIG = cfg;\n };\n\n const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);\n const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']); // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erroneously deleted from\n // HTML namespace.\n\n const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n\n const ALL_SVG_TAGS = addToSet({}, svg$1);\n addToSet(ALL_SVG_TAGS, svgFilters);\n addToSet(ALL_SVG_TAGS, svgDisallowed);\n const ALL_MATHML_TAGS = addToSet({}, mathMl$1);\n addToSet(ALL_MATHML_TAGS, mathMlDisallowed);\n /**\n *\n *\n * @param {Element} element a DOM element whose namespace is being checked\n * @returns {boolean} Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n\n const _checkValidNamespace = function _checkValidNamespace(element) {\n let parent = getParentNode(element); // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: NAMESPACE,\n tagName: 'template'\n };\n }\n\n const tagName = stringToLowerCase(element.tagName);\n const parentTagName = stringToLowerCase(parent.tagName);\n\n if (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n return false;\n }\n\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via