{"version":3,"sources":["webpack:///./behaviors/markdown/paste_markdown_table.js","webpack:///./dropzone_input.js","webpack:///./gl_form.js","webpack:///./lib/utils/file_upload.js","webpack:///./lib/utils/text_markdown.js","webpack:///./behaviors/shortcuts/shortcuts.js"],"names":["PasteMarkdownTable","constructor","clipboardData","this","data","columnWidths","rows","tableFound","parseTable","isTable","convertToTableMarkdown","_this","calculateColumnWidths","markdownRows","map","row","column","index","formatColumn","join","splice","generateHeaderBreak","types","includes","htmlData","getData","doc","DOMParser","parseFromString","querySelectorAll","length","splitRows","trim","split","normalizeRows","columnCountsMatch","rowLengths","maxLength","Math","max","forEach","push","_this2","_column","columnIndex","maxColumnWidth","textColumnCount","htmlColumnCount","cells","Array","_this3","width","dropzoneInput","form","config","parallelUploads","_form$get$querySelect","iconPaperclip","spriteIcon","$attachingFileMessage","find","$cancelButton","$retryLink","$uploadProgress","$uploadingErrorContainer","$uploadingErrorMessage","$uploadingProgressContainer","uploadsPath","window","uploads_path","maxFileSize","gon","max_file_size","formTextarea","handlePaste","pasteText","addFileToForm","updateAttachingMessage","uploadFile","hasPlainText","wrap","$mdArea","closest","$formDropzone","parent","addClass","append","on","event","dropzone","url","dictDefaultMessage","clickable","get","querySelector","paramName","maxFilesize","uploadMultiple","headers","csrf","previewContainer","dragover","css","dragleave","removeClass","drop","focus","success","header","response","shouldPad","getQueuedFiles","getUploadingFiles","link","size","markdown","error","file","errorMessage","__","xhr","message","res","responseText","html","totaluploadprogress","totalUploadProgress","files","text","round","sending","removedfile","queuecomplete","$","remove","trigger","child","children","e","preventDefault","stopPropagation","Dropzone","forElement","removeAllFiles","dropzoneInstance","target","failedFiles","failedFile","status","ERROR","undefined","accepted","addFile","pasteEvent","originalEvent","items","converter","type","indexOf","MAX_FILE_NAME_LENGTH","filename","getFilename","truncateFilename","truncate","some","item","formattedText","textarea","caretStart","selectionStart","caretEnd","selectionEnd","textEnd","val","beforeSelection","substring","afterSelection","setSelectionRange","style","height","scrollHeight","dispatchEvent","Event","path","_escape","closeSpinner","handleAttachFile","click","formData","FormData","axios","post","then","md","$child","replace","insertToTextArea","catch","messageContainer","filesCount","filter","attachingMessage","n__","$attachFileButton","addEventListener","autoDiscover","GLForm","enableGFM","forceNew","gfmDataSources","defaultAutocompleteConfig","dataSources","gl","GfmAutoComplete","_isEmpty","Object","keys","destroy","setupForm","clearEventListeners","autoComplete","formDropzone","isNewForm","is","disableButtonIfEmptyField","setup","autosize","addEventListeners","addMarkdownListeners","show","isAutosizeable","setupAutosize","off","setHeightData","bind","destroyAutosize","setTimeout","outerHeight","removeMarkdownListeners","Boolean","buttonSelector","fileSelector","btn","document","fileInput","textContent","value","fileName","name","validateImageName","test","validateFileFromAllowList","allowList","parts","ext","LIST_LINE_HEAD_PATTERN","HR_PATTERN","compositioningNoteText","addBlockTags","blockTag","selected","lineAfterSelection","textArea","linesFromSelection","startPos","lastIndexOf","endPos","lines","setNewSelectionRange","lineStart","firstLineChange","totalChanged","newStart","newEnd","getEditorSelectionRange","editor","start","sel","getSelection","startLineNumber","startColumn","end","endLineNumber","endColumn","insertMarkdownText","tag","cursorOffset","select","editorSelectionStart","editorSelectionEnd","lastNewLine","textToInsert","removedLastNewLine","removedFirstNewLine","currentLineEmpty","toString","selectionRange","URL","origin","selectedSplit","getValue","substr","isBeginning","startChar","lastLine","rangeWithBlockTags","Range","editorBlockTagText","lineBefore","lineBeforeSelection","blockTagText","String","replaceSelectedText","insertText","positionBetweenTags","pos","startPosition","endPosition","selectWithinSelection","moveCursor","updateText","tagContent","$textArea","selectedText","handleContinueList","markdown_automatic_lists","key","altKey","ctrlKey","metaKey","shiftKey","selectedLines","firstSelectedLine","listLineMatch","match","leader","indent","content","isOl","groups","emptyListItem","prefixLength","itemToInsert","nextLineMatch","_nextLineMatch$groups","nextIndent","nextIsOl","numStr","postfix","incrementBy","parseInt","continueOlText","keypressNoteText","_$$atwho","_$","atwho","call","markdown_surround_selection","_","handleSurroundSelectedText","compositionStartNoteText","compositionEndNoteText","updateTextForToolbarBtn","$toolbarBtn","shiftedLines","totalAdded","line","repeat","indentLines","totalRemoved","removedFromFirstline","removedFromLine","slice","outdentLines","attr","each","Shortcuts","initMarkdownEditorShortcuts","addEditorMarkdownListeners","mdTag","mdBlock","mdPrepend","mdSelect","currentTarget","getSelectedText","removeMarkdownEditorShortcuts","resolveSelectedImage","async","markdownPreviewPath","selectedLine","lineSelectionStart","preExlm","postClose","imageMarkdown","imageURL","body","getAttribute","LOCAL_MOUSETRAP_DATA_KEY","getToolbarBtnToShortcutsMap","$textarea","$allToolbarBtns","Map","keyboardShortcuts","set","extensions","onToggleHelp","helpModalElement","helpModalVueInstance","addAll","TOGGLE_KEYBOARD_SHORTCUTS_DIALOG","START_SEARCH","focusSearch","FOCUS_FILTER_BAR","focusFilter","TOGGLE_PERFORMANCE_BAR","onTogglePerfBar","HIDE_APPEARING_CONTENT","hideAppearingContent","TOGGLE_CANARY","onToggleCanary","GO_TO_YOUR_TODO_LIST","findAndFollowLink","GO_TO_ACTIVITY_FEED","GO_TO_YOUR_ISSUES","GO_TO_YOUR_MERGE_REQUESTS","GO_TO_YOUR_REVIEW_REQUESTS","GO_TO_YOUR_PROJECTS","GO_TO_YOUR_GROUPS","GO_TO_MILESTONE_LIST","GO_TO_YOUR_SNIPPETS","TOGGLE_MARKDOWN_PREVIEW","toggleMarkdownPreview","addStopCallback","element","combo","keysFor","findFileURL","dataset","findFile","add","GO_TO_PROJECT_FIND_FILE","visitUrl","shouldDisableShortcuts","disableShortcuts","addExtension","Extension","args","extensionsCurrentlyLoading","Set","instance","Dep","_Extension$dependenci","dependencies","has","delete","command","callback","Mousetrap","commandsAndCallbacks","commandAndCallback","$destroy","createElement","Vue","el","components","ShortcutsHelp","render","hidden","parseBoolean","getCookie","setCookie","refreshCurrentPage","currentValue","expires","triggerHandler","filterInput","_document$querySelect","display","handler","toolbarBtnToShortcutsMap","localMousetrap","allShortcuts","_flatten","values","originalStopCallback","prototype","stopCallback","unbind"],"mappings":"4aAGe,MAAMA,EACnBC,YAAYC,GACVC,KAAKC,KAAOF,EACZC,KAAKE,aAAe,GACpBF,KAAKG,KAAO,GACZH,KAAKI,WAAaJ,KAAKK,aAGzBC,UACE,OAAON,KAAKI,WAGdG,yBAAyB,IAAAC,EAAA,KACvBR,KAAKS,wBAEL,MAAMC,EAAeV,KAAKG,KAAKQ,KAC7B,SAACC,GAAG,WAMGA,EAAID,KAAI,SAACE,EAAQC,GAAK,OAAKN,EAAKO,aAAaF,EAAQC,MAAQE,KAAK,cAM3E,OAFAN,EAAaO,OAAO,EAAG,EAAGjB,KAAKkB,uBAExBR,EAAaM,KAAK,MAY3BX,aACE,IAAKL,KAAKC,KAAKkB,MAAMC,SAAS,eAAiBpB,KAAKC,KAAKkB,MAAMC,SAAS,cACtE,OAAO,EAGT,MAAMC,EAAWrB,KAAKC,KAAKqB,QAAQ,aACnCtB,KAAKuB,KAAM,IAAIC,WAAYC,gBAAgBJ,EAAU,aAQrD,GAAsB,IANPrB,KAAKuB,IAAIG,iBAAiB,+BAM9BC,OACT,OAAO,EAGT,MACMC,EADO5B,KAAKC,KAAKqB,QAAQ,cAAcO,OACtBC,MAAM,iCAG7B,OAAI9B,KAAKuB,IAAIG,iBAAiB,MAAMC,SAAWC,EAAUD,SAIzD3B,KAAKG,KAAOyB,EAAUjB,KAAI,SAACC,GAAG,OAAKA,EAAIkB,MAAM,SAC7C9B,KAAK+B,kBAKA/B,KAAKgC,qBAQZD,gBACE,MAAME,EAAajC,KAAKG,KAAKQ,KAAI,SAACC,GAAG,OAAKA,EAAIe,UACxCO,EAAYC,KAAKC,OAAOH,GAE9BjC,KAAKG,KAAKkC,SAAQ,SAACzB,GACjB,KAAOA,EAAIe,OAASO,GAClBtB,EAAI0B,KAAK,OAKf7B,wBAAwB,IAAA8B,EAAA,KACtBvC,KAAKE,aAAeF,KAAKG,KAAK,GAAGQ,KAAI,SAAC6B,EAASC,GAAW,OA/FvC,SAACtC,EAAMsC,GAAW,OACvCN,KAAKC,OAAOjC,EAAKQ,KAAI,SAACC,GAAG,OAAKA,EAAI6B,GAAad,WA+F3Ce,CAAeH,EAAKpC,KAAMsC,MAI9BT,oBACE,MAAMW,EAAkB3C,KAAKG,KAAK,GAAGwB,OACrC,IAAIiB,EAAkB,EAMtB,OAJA5C,KAAKuB,IAAIG,iBAAiB,YAAYW,SAAQ,SAACzB,GAC7CgC,EAAkBT,KAAKC,IAAIxB,EAAIiC,MAAMlB,OAAQiB,MAGxCD,IAAoBC,EAG7B7B,aAAaF,EAAQC,GAEnB,OAAOD,EADQiC,MAAM9C,KAAKE,aAAaY,GAASD,EAAOc,OAAS,GAAGX,KAAK,KAI1EE,sBAAsB,IAAA6B,EAAA,KAKpB,MAAQ,IAHO/C,KAAKE,aAAaS,KAAI,SAACqC,EAAOlC,GAAK,OAChDgC,MAAMC,EAAK7C,aAAaY,GAAS,GAAGE,KAAK,QAEzBA,KAAK,S,4BC9FZ,SAASiC,EAAcC,EAAMC,EAAS,CAAEC,gBAAiB,IAAK,IAAAC,EAC3E,MACMC,EAAgBC,YAAW,YAAa,yBACxCC,EAAwBN,EAAKO,KAAK,2BAClCC,EAAgBR,EAAKO,KAAK,kCAC1BE,EAAaT,EAAKO,KAAK,yBACvBG,EAAkBV,EAAKO,KAAK,uBAC5BI,EAA2BX,EAAKO,KAAK,8BACrCK,EAAyBZ,EAAKO,KAAK,4BACnCM,EAA8Bb,EAAKO,KAAK,iCACxCO,EAAcd,EAAKjD,KAAK,iBAAmBgE,OAAOC,cAAgB,KAClEC,EAAcC,IAAIC,eAAiB,GACnCC,EAAepB,EAAKO,KAAK,iBAC/B,IAAIc,EACAC,EACAC,EACAC,EACAC,EACAC,EAEJN,EAAaO,KAAK,oCAGlB,MAAMC,EAAUR,EAAaS,QAAQ,YAC/BC,EAAgB9B,EAAKO,KAAK,iBAKhC,GAJAuB,EAAcC,SAASC,SAAS,wBAChCF,EAAcG,OAzBG,0CA0BjBH,EAAcvB,KAAK,uBAAuB0B,OAAO7B,IAE5CU,EAEH,OADAgB,EAAcE,SAAS,uBAChB,KAGTZ,EAAac,GAAG,SAAS,SAACC,GAAK,OAAKd,EAAYc,MAEhD,MAAMC,EAAWN,EAAcM,SAAS,CACtCC,IAAKvB,EACLwB,mBAAoB,GACpBC,UAAwE,QAA/DpC,EAAEH,EAAKwC,IAAI,GAAGC,cAAc,2CAAmC,IAAAtC,KACxEuC,UAAW,OACXC,YAAa1B,EACb2B,gBAAgB,EAChBC,QAASC,IAAKD,QACdE,kBAAkB,KACf9C,EACH+C,SAAU,WACRpB,EAAQI,SAAS,qBACjBhC,EAAKO,KAAK,uBAAuB0C,IAAI,UAAW,KAElDC,UAAW,WACTtB,EAAQuB,YAAY,qBACpBnD,EAAKO,KAAK,uBAAuB0C,IAAI,UAAW,IAElDG,KAAM,WACJxB,EAAQuB,YAAY,qBACpBnD,EAAKO,KAAK,uBAAuB0C,IAAI,UAAW,GAChD7B,EAAaiC,SAEfC,QAAQC,EAAQC,GACd,MACMC,EADsB3G,KAAK4G,iBAAiBjF,OAAS3B,KAAK6G,oBAAoBlF,QAC3C,EAEzC8C,EAAciC,EAASI,KAAKvB,IAAKkB,EAAOM,MACxCvC,EAAUkC,EAASI,KAAKE,SAAUL,IAEpCM,MAAO,SAACC,EAAMC,EAAeC,YAAG,8BAA+BC,GAO7D,MAAMC,GAjFaC,EAiFaJ,GAAgBE,EAAIG,eAhF7B,iBAARD,EAIZA,EAAID,QAHFC,EAFX,IAAyBA,EAmFnB1D,EAAyBwC,YAAY,QACrCvC,EAAuB2D,KAAKH,GAC5B5D,EAAcwB,SAAS,SAEzBwC,oBAAoBC,GAClBjD,EAAuB1E,KAAK4H,MAAOpE,GACnCI,EAAgBiE,KAAQ1F,KAAK2F,MAAMH,GAAb,MAExBI,QAAS,WAIPlE,EAAyBqB,SAAS,QAClCnB,EAA4BsC,YAAY,QACxC3C,EAAc2C,YAAY,SAE5B2B,YAAa,WACXtE,EAAcwB,SAAS,QACvBnB,EAA4BmB,SAAS,QACrCrB,EAAyBqB,SAAS,SAEpC+C,cAAe,WACbC,IAAE,eAAeC,SACjBD,IAAE,kBAAkBE,QAAQ,SAE5BrE,EAA4BmB,SAAS,QACrCxB,EAAcwB,SAAS,WAIrBmD,EAAQH,IAAE5C,EAAS,IAAIgD,SAAS,YAItC5E,EAAc0B,GAAG,SAAS,SAACmD,GACzBA,EAAEC,iBACFD,EAAEE,kBACFC,IAASC,WAAW3D,EAAcU,IAAI,IAAIkD,gBAAe,MAO3DjF,EAAWyB,GAAG,SAAS,SAACmD,GACtB,MAAMM,EAAmBH,IAASC,WAChCJ,EAAEO,OAAO/D,QAAQ,wBAAwBY,cAAc,kBAEnDoD,EAAcF,EAAiBjB,MAErCW,EAAEC,iBAIFK,EAAiBD,gBAAe,GAEhCG,EAAYpI,KAAI,SAACqI,GACf,MAAM9B,EAAO8B,EAOb,OALI9B,EAAK+B,SAAWP,IAASQ,QAC3BhC,EAAK+B,YAASE,EACdjC,EAAKkC,cAAWD,GAGXN,EAAiBQ,QAAQnC,SAIpC3C,EAAc,SAACc,GACb,MAAMiE,EAAajE,EAAMkE,eACnB,cAAExJ,GAAkBuJ,EAC1B,GAAIvJ,GAAiBA,EAAcyJ,MAAO,CACxC,MAAMC,EAAY,IAAI5J,EAAmBE,GAGzC,GAAI0J,EAAUnJ,UAAW,CACvB+E,EAAMmD,iBACN,MAAMX,EAAO4B,EAAUlJ,yBACvBiE,EAAUqD,QACL,IAAKjD,EAAa0E,GAAa,CACnB,IAAIvJ,EAAc6H,OAC1BvF,SAAQ,SAAC6E,GAChB,IAAoC,IAAhCA,EAAKwC,KAAKC,QAAQ,SAAiB,CACrCtE,EAAMmD,iBACN,MAAMoB,EAAuB,IAEvBC,EAAWC,YAAY5C,IAAS,YAChC6C,EAAmBC,YAASH,EAAUD,GAE5CpF,EADc,KAAIuF,OAGlBpF,EAAWuC,EAAM6C,UAO3BnF,EAAe,SAAC3E,GAEd,MAD0B,IAAIA,EAAKF,cAAcyJ,OACxBS,MAAK,SAACC,GAAI,MAAmB,eAAdA,EAAKR,SAG/ClF,EAAY,SAACqD,EAAMlB,GACjB,IAAIwD,EAAgBtC,EAChBlB,IACFwD,GAAiB,QAEnB,MAAMC,EAAW/B,EAAM3C,IAAI,GACrB2E,EAAaD,EAASE,eACtBC,EAAWH,EAASI,aACpBC,EAAUvC,IAAEG,GAAOqC,MAAM/I,OACzBgJ,EAAkBzC,IAAEG,GAAOqC,MAAME,UAAU,EAAGP,GAC9CQ,EAAiB3C,IAAEG,GAAOqC,MAAME,UAAUL,EAAUE,GAK1D,OAJAvC,IAAEG,GAAOqC,IAAIC,EAAkBR,EAAgBU,GAC/CT,EAASU,kBAAkBT,EAAaF,EAAcxI,OAAQ4I,EAAWJ,EAAcxI,QACvFyI,EAASW,MAAMC,OAAYZ,EAASa,aAAX,KACzB3G,EAAaoB,IAAI,GAAGwF,cAAc,IAAIC,MAAM,UACrC7G,EAAa8D,QAAQ,UAG9B3D,EAAgB,SAAC2G,GACflD,IAAEhF,GAAMiC,OAAQ,8CAA6CkG,IAAOD,SAGtE,MAEME,EAAe,kBAAMvH,EAA4BmB,SAAS,SAkDhE,SAASqG,EAAiBhD,GACxBA,EAAEC,iBACFN,IAAElI,MAAM+E,QAAQ,aAAatB,KAAK,iBAAiB+H,QACnDlH,EAAaiC,QAhCf5B,EAAa,SAACuF,EAAML,GAClB,MAAM4B,EAAW,IAAIC,SACrBD,EAAStG,OAAO,OAAQ+E,EAAML,GAzBN9F,EAA4BsC,YAAY,QA6BhEsF,IACGC,KAAK5H,EAAayH,GAClBI,MAAK,UAAC,KAAE5L,IACP,MAAM6L,EAAK7L,EAAK6G,KAAKE,UAvBF,SAAC6C,EAAUtE,GAClC,MAAMwG,EAAS7D,IAAEG,GACX+B,EAAW2B,EAAOrG,IAAI,GACtB2E,EAAaD,EAASE,eACtBC,EAAWH,EAASI,aACpBL,EAAiB,KAAIN,MAC3BkC,EAAOrB,KAAI,SAAC5J,EAAO4J,GAAG,OAAKA,EAAIsB,QAAQ7B,EAAe5E,MACtD6E,EAASU,kBACPT,EAAaF,EAAcxI,OAAS4D,EAAI5D,OACxC4I,EAAWJ,EAAcxI,OAAS4D,EAAI5D,QAExCoK,EAAO3D,QAAQ,UAcX6D,CAAiBpC,EAAUiC,GAC3BR,OAEDY,OAAM,SAAC3D,GAjCM,IAACjB,IAkCHiB,EAAE7B,SAASzG,KAAKqH,QAjC9BzD,EAAyBwC,YAAY,QACrCvC,EAAuB2D,KAAKH,GAiCxBgE,QAIN5G,EAAyB,SAACkD,EAAOuE,GAC/B,MAAMC,EAAaxE,EAAMyE,QACvB,SAACnF,GAAI,MAAqB,cAAhBA,EAAK+B,QAA0C,WAAhB/B,EAAK+B,UAC9CtH,OACI2K,EAAmBC,YAAI,mBAAoB,qBAAsBH,GAEvED,EAAiBtE,KAAQyE,EAAF,OASzBpJ,EAAKO,KAAK,sBAAsB+H,MAAMD,GAEtC,MAAMiB,EAAoBtJ,EAAKO,KAAK,0BAKpC,OAJI+I,EAAkB7K,QACpB6K,EAAkB9G,IAAI,GAAG+G,iBAAiB,QAASlB,GAG9CvG,EAAcU,IAAI,GAAKgD,IAASC,WAAW3D,EAAcU,IAAI,IAAM,KAxR5EgD,IAASgE,cAAe,E,gBCJT,MAAMC,EAWnB7M,YAAYoD,EAAM0J,EAAY,GAAIC,GAAW,EAAOC,EAAiB,IAAI,IAAAtM,EAAA,KACvER,KAAKkD,KAAOA,EACZlD,KAAKoK,SAAWpK,KAAKkD,KAAKO,KAAK,yBAC/BzD,KAAK4M,UAAY,IAAKG,OAA8BH,GAGpD,IAAII,EAAeC,GAAGC,iBAAmBD,GAAGC,gBAAgBF,aAAgB,GAEvEG,IAAQL,KACXE,EAAcF,GAGhBM,OAAOC,KAAKrN,KAAK4M,WAAWvK,SAAQ,SAAC6H,GACtB,WAATA,GAAsB8C,EAAY9C,KACpC1J,EAAKoM,UAAU1C,IAAQ,MAK3BlK,KAAKsN,UAELtN,KAAKuN,UAAUP,EAAaH,GAC5B7M,KAAKkD,KAAKjD,KAAK,SAAUD,MAG3BsN,UAEEtN,KAAKwN,sBACDxN,KAAKyN,cACPzN,KAAKyN,aAAaH,UAEhBtN,KAAK0N,cACP1N,KAAK0N,aAAaJ,UAGpBtN,KAAKkD,KAAKjD,KAAK,SAAU,MAG3BsN,UAAUP,EAAaH,GAAW,GAChC,MAAMc,EAAY3N,KAAKkD,KAAK0K,GAAG,oBAAsBf,EACrD7M,KAAKkD,KAAKmD,YAAY,oBAClBsH,IACF3N,KAAKkD,KAAKO,KAAK,iBAAiB0E,SAChCnI,KAAKkD,KAAKgC,SAAS,YAEnB2I,YACE7N,KAAKkD,KAAKO,KAAK,iBACfzD,KAAKkD,KAAKO,KAAK,gDAEjBzD,KAAKyN,aAAe,IAAIP,IAAgBF,GACxChN,KAAKyN,aAAaK,MAAM9N,KAAKkD,KAAKO,KAAK,iBAAkBzD,KAAK4M,WAC9D5M,KAAK0N,aAAezK,EAAcjD,KAAKkD,KAAM,CAAEE,gBAAiB,IAE5DpD,KAAKkD,KAAK0K,GAAG,0BACfG,YAAS/N,KAAKoK,WAIlBpK,KAAKgO,oBACLC,YAAqBjO,KAAKkD,MAC1BlD,KAAKkD,KAAKgL,OACNlO,KAAKmO,gBAAgBnO,KAAKoO,iBACU,IAApCpO,KAAKoK,SAASnK,KAAK,cAAuBD,KAAKoK,SAAS7D,QAG9D6H,gBAAgB,IAAA7L,EAAA,KAEdvC,KAAKoK,SAASiE,IAAI,oBAAoBjJ,GAAG,mBAAoBpF,KAAKsO,cAAcC,KAAKvO,OAGrFA,KAAKoK,SAASiE,IAAI,oBAAoBjJ,GAAG,mBAAoBpF,KAAKwO,gBAAgBD,KAAKvO,OAEvFyO,YAAW,WACTV,YAASxL,EAAK6H,UACd7H,EAAK6H,SAASjE,IAAI,SAAU,cAC3B,GAGLmI,gBACEtO,KAAKoK,SAASnK,KAAK,SAAUD,KAAKoK,SAASsE,eAG7CF,kBACE,MAAME,EAAc1O,KAAKoK,SAASsE,cAE9B1O,KAAKoK,SAASnK,KAAK,YAAcyO,IAErCX,IAAST,QAAQtN,KAAKoK,UAEtBpK,KAAKoK,SAASnK,KAAK,SAAUyO,GAC7B1O,KAAKoK,SAASsE,YAAYA,GAC1B1O,KAAKoK,SAASjE,IAAI,aAAclC,OAAOyK,cAGzClB,sBAEExN,KAAKoK,SAASiE,IAAI,SAElBrO,KAAKoK,SAASiE,IAAI,QAClBM,YAAwB3O,KAAKkD,MAG/B8K,oBACEhO,KAAKoK,SAAShF,GAAG,SAAS,WACxB8C,IAAElI,MAAM+E,QAAQ,YAAYG,SAAS,iBAEvClF,KAAKoK,SAAShF,GAAG,QAAQ,WACvB8C,IAAElI,MAAM+E,QAAQ,YAAYsB,YAAY,iBAI5C,2BACE,OAAOuI,QAAQ5O,KAAKoK,SAASnK,KAAK,8B,kJCnIvB,aAAC4O,EAAgBC,GAC9B,MAAMC,EAAMC,SAASrJ,cAAckJ,GAC7BI,EAAYD,SAASrJ,cAAcmJ,GAEzC,IAAKC,IAAQE,EAAW,OAExB,MAAM/L,EAAO6L,EAAIhK,QAAQ,QAEzBgK,EAAItC,iBAAiB,SAAS,WAC5BwC,EAAUzD,WAGZyD,EAAUxC,iBAAiB,UAAU,WACnCvJ,EAAKyC,cAAc,gBAAgBuJ,YAAcD,EAAUE,MAAMnD,QAAQ,YAAa,QAInF,MAAMlC,EAAc,SAAC5C,GAC1B,IAAIkI,EAKJ,OAJIlI,IACFkI,EAAWlI,EAAKmI,MAGXD,GAGIE,EAAoB,SAACpI,GAChC,MAAMkI,EAAWlI,EAAKmI,KAAOnI,EAAKmI,KAAO,YAEzC,MADwB,oDACDE,KAAKH,GAAYA,EAAW,aAGxCI,EAA4B,SAACJ,EAAUK,GAClD,MAAMC,EAAQN,EAAStN,MAAM,KACvB6N,EAAO,IAAGD,EAAMA,EAAM/N,OAAS,GAErC,OAAO8N,EAAUrO,SAASuO,K,yZC9B5B,MAQMC,EAAyB,6FAGzBC,EAAa,uEAEnB,IAAIC,GAAyB,EAM7B,SAASC,EAAaC,EAAUC,GAC9B,MAAQ,GAAED,MAAaC,MAAaD,IA+BtC,SAASE,EAAmBrI,EAAMsI,GAChC,IAAIrO,EAAQ+F,EAAK+C,UAAUuF,EAAS3F,cAMpC,OAHA1I,EAAQA,EAAMkK,QAAQ,MAAO,IAC7BlK,EAAQA,EAAMA,MAAM,MAEbA,EAAM,GASf,SAASsO,EAAmBD,GAC1B,MAAMtI,EAAOsI,EAAShB,OAChB,eAAE7E,EAAc,aAAEE,GAAiB2F,EAEzC,IAAIE,EAAoC,OAAzBxI,EAAKyC,GAA2BA,EAAiB,EAAIA,EACpE+F,EAAWxI,EAAKyI,YAAY,KAAMD,GAAY,EAE9C,IAAIE,EAAS/F,IAAiBF,EAAiBE,EAAeA,EAAe,EAC7E+F,EAAS1I,EAAK8B,QAAQ,KAAM4G,GACxBA,EAAS,IAAGA,EAAS1I,EAAKlG,QAK9B,MAAO,CACL6O,MAJoB3I,EAAK+C,UAAUyF,EAAUE,GACnBzO,MAAM,MAIhCwI,iBACAE,eACA6F,WACAE,UAeJ,SAASE,EACPN,EACA7F,EACAE,EACAkG,EACAC,EACAC,GAEA,IAAIC,EAAW1O,KAAKC,IAAIsO,EAAWpG,EAAiBqG,GAChDG,EAAS3O,KAAKC,IAAIsO,EAAWlG,EAAeoG,GAE5CtG,IAAmBE,EACrBsG,EAASD,EACAvG,IAAmBoG,IAC5BG,EAAWH,GAGbP,EAASrF,kBAAkB+F,EAAUC,GAgBvC,SAASC,EAAwBC,GAC/B,MAbO,CACLC,MAAO,CACLrQ,KAHqCsQ,EAcAF,EAAOG,gBAXnCC,gBACTvQ,OAAQqQ,EAAIG,aAEdC,IAAK,CACH1Q,IAAKsQ,EAAIK,cACT1Q,OAAQqQ,EAAIM,YARlB,IAA2CN,EA+HpC,SAASO,GAAmB,SACjCtB,EAAQ,KACRtI,EAAI,IACJ6J,EAAG,aACHC,EAAY,SACZ3B,EAAQ,SACRC,EAAW,GAAE,KACbpL,EAAI,OACJ+M,EAAM,OACNZ,IAKA,IAAKU,IAAQ1B,IAAaC,EACxB,OAGF,IAGI4B,EACAC,EACAC,EACAC,EANAC,GAAqB,EACrBC,GAAsB,EACtBC,GAAmB,EAOvB,GAFAlC,EAAWA,EAASmC,WAEhBpB,EAAQ,CACV,MAAMqB,EAAiBtB,EAAwBC,GAE/Ca,EAAuBQ,EAAepB,MACtCa,EAAqBO,EAAef,IAKtC,GA5RuB,kBA4RnBI,GACEY,IACF,IACE,MAAM/M,EAAM,IAAI+M,IAAIrC,GAED,SAAf1K,EAAIgN,QAAoC,OAAfhN,EAAIgN,SAC/Bb,EAAM,iBACNE,EAAS,QAEX,MAAOrJ,IAOkB,IAA3B0H,EAAStG,QAAQ,QACnBuI,GAAsB,EACtBjC,EAAWA,EAASjE,QAAQ,MAAO,KAIjCmE,EACEA,EAAS3F,aAAe2F,EAAS7F,eAAiB2F,EAASjE,QAAQ,MAAO,IAAIrK,SAChFsQ,GAAqB,EACrBhC,EAAWA,EAASjE,QAAQ,MAAO,KAE5BgF,GACLa,EAAqBjR,MAAQkR,EAAmBlR,MAClDqR,GAAqB,EACrBhC,EAAWA,EAASjE,QAAQ,MAAO,KAIvC,MAAMwG,EAAgBvC,EAASnO,MAAM,MAEjCkP,IAAWnM,GACbkN,EAAcf,EAAOyB,WAAW3Q,MAAM,MAAM+P,EAAqBjR,KAE7D,QAAQ2O,KAAKwC,KACfI,GAAmB,IAEZhC,IAAatL,IACtBkN,EAAc5B,EAAShB,MAAMuD,OAAO,EAAGvC,EAAS7F,gBAAgBgG,YAAY,MAGxE,QAAQf,KAAKY,EAAShB,MAAMvE,UAAUmH,EAAa5B,EAAS7F,mBAC9D6H,GAAmB,IAIvB,MAAMQ,EACHxC,GAAwC,IAA5BA,EAAS7F,gBACrB0G,GAA0C,IAAhCa,EAAqBhR,QAA6C,IAA7BgR,EAAqBjR,IAEjEgS,EAAa/N,GAASsN,GAAqBQ,EAAqB,GAAP,KAK3DX,EAFAQ,EAAc7Q,OAAS,KAAOkD,GAAqB,MAAZmL,GAAiC,KAAbA,GAC7C,MAAZA,GAAiC,KAAbA,EACPgB,EA9MrB,SAA4BnJ,EAAMmI,EAAUC,EAAUe,GACpD,MAAMR,EAAQ3I,EAAK/F,MAAM,MACnBuQ,EAAiBtB,EAAwBC,GAK/C,GAHER,EAAM6B,EAAepB,MAAMrQ,IAAM,KAAOoP,GACxCQ,EAAM6B,EAAef,IAAI1Q,IAAM,KAAOoP,EAEjB,CACrB,GAAiB,OAAbA,EAAmB,CACrB,MAAM6C,EAAWrC,EAAM6B,EAAef,IAAI1Q,IAAM,GAC1CkS,EAAqB,IAAIC,MAC7BvC,EAAM6B,EAAepB,MAAMrQ,IAAM,GACjC,EACAyR,EAAef,IAAI1Q,IAAM,EACzBiS,EAASlR,QAEXqP,EAAOG,eAAerG,kBAAkBgI,GAE1C,OAAO7C,EAET,OAAOF,EAAaC,EAAUC,GA2LtB+C,CAAmBnL,EAAMmI,EAAUC,EAAUe,GAxLvD,SAAsBnJ,EAAMsI,EAAUH,EAAUC,GAK9C,OAvIF,SAA6BpI,EAAMsI,GACjC,IAAIrO,EAAQ+F,EAAK+C,UAAU,EAAGuF,EAAS7F,gBAEvCxI,EAAQA,EAAMA,MAAM,MAIpB,MAAMmR,EAAanR,EAAMA,EAAMH,OAAS,GAExC,YAAsBwH,IAAf8J,EAA2B,GAAKA,EA2HrCC,CAAoBrL,EAAMsI,KAAcH,GACxCE,EAAmBrI,EAAMsI,KAAcH,GAIvB,MAAZA,IACFG,EAAS7F,eAAiB6F,EAAS7F,gBAAkB0F,EAASrO,OAAS,GACvEwO,EAAS3F,aAAe2F,EAAS3F,cAAgBwF,EAASrO,OAAS,IAE9DsO,GAEFF,EAAaC,EAAUC,GA4KtBkD,CAAatL,EAAMsI,EAAUH,EAAUC,GAE5BuC,EACZ7R,KAAI,SAAC+J,GACJ,OAAIgH,EAAI/H,QAVQ,WAUoB,EAC3B+H,EAAI1F,QAXG,SAWsBtB,GAEb,IAArBA,EAAIf,QAAQ+H,GACP0B,OAAO1I,EAAIsB,QAAQ0F,EAAK,KAE1B0B,OAAO1B,GAAOhH,KAEtB1J,KAAK,MAED0Q,EAAI/H,QApBS,WAoBmB,EAC1B+H,EAAI1F,QArBG,UAqBsB,kBAC1CiE,EAASjE,QAAQ,OAAQ,MAAMA,QAAQ,OAAQ,UAGlCoH,OAAOR,GAAalB,EAAMzB,GAAYpL,EAAO6M,EAAM,IAGhEQ,IACFF,EAAgB,KAAIA,GAGlBC,IACFD,GAAgB,MAGdhB,EACFA,EAAOqC,oBAAoBrB,EAAcJ,GAEzC0B,YAAWnD,EAAU6B,GA1MzB,UAAoB,SAClB7B,EAAQ,IACRuB,EAAG,aACHC,EAAY,oBACZ4B,EAAmB,mBACnBtB,EAAkB,OAClBL,EAAM,OACNZ,EAAM,qBACNa,EAAoB,mBACpBC,IAEA,IAAI0B,EACJ,IAAIrD,GAAaA,EAASrF,kBAA1B,CAGA,GAAI8G,GAAUA,EAAOjQ,OAAS,EAAG,CAC/B,GAAIwO,EAAU,CAEZ,MAAMsD,EAAgBtD,EAAS7F,gBAAkBoH,EAAI/P,OAAS+P,EAAI/H,QAAQiI,IACpE8B,EAAcD,EAAgB7B,EAAOjQ,OAC3C,OAAOwO,EAASrF,kBAAkB2I,EAAeC,GAEnD,GAAI1C,EAEF,YADAA,EAAO2C,sBAAsB/B,EAAQF,GAIzC,GAAIvB,GACF,GAAIA,EAAS7F,iBAAmB6F,EAAS3F,aAErCgJ,EADED,EACIpD,EAAS7F,eAAiBoH,EAAI/P,OAE9BwO,EAAS7F,eAGb2H,IACFuB,GAAO,GAGL7B,IACF6B,GAAO7B,GAGFxB,EAASrF,kBAAkB0I,EAAKA,QAEhCxC,GAAUa,EAAqBjR,MAAQkR,EAAmBlR,KAC/D2S,GACFvC,EAAO4C,YAAyB,EAAdlC,EAAI/P,SA8J1BiS,CAAW,CACTzD,WACAuB,IAAKA,EAAI1F,QA5Ca,SA4CYiE,GAClC0B,eACA4B,oBAAqB1O,GAA4B,IAApBoL,EAAStO,OACtCsQ,qBACAL,SACAZ,SACAa,uBACAC,uBAIG,SAAS+B,GAAW,SAAE1D,EAAQ,IAAEuB,EAAG,aAAEC,EAAY,SAAE3B,EAAQ,KAAEnL,EAAI,OAAE+M,EAAM,WAAEkC,IAChF,MAAMC,EAAY7L,IAAEiI,GACpBA,EAAW4D,EAAUrO,IAAI,GACzB,MAAMmC,EAAOkM,EAAUrJ,MACjBuF,EAhYR,SAAsBpI,EAAMuC,GAC1B,OAAOvC,EAAK+C,UAAUR,EAASE,eAAgBF,EAASI,cA+XvCwJ,CAAanM,EAAMsI,IAAa2D,EACjD3D,EAAS5J,QACTkL,EAAmB,CACjBtB,WACAtI,OACA6J,MACAC,eACA3B,WACAC,WACApL,OACA+M,WAEFzB,EAAS3E,QAoIX,SAASyI,EAAmB1L,EAAG4H,GAC7B,IAAK/L,IAAI8P,yBAA0B,OACnC,GAAgB,UAAV3L,EAAE4L,IAAkB,OAC1B,GAAI5L,EAAE6L,QAAU7L,EAAE8L,SAAW9L,EAAE+L,SAAW/L,EAAEgM,SAAU,OACtD,GAAIpE,EAAS7F,iBAAmB6F,EAAS3F,aAAc,OAGvD,GAAIsF,EAAwB,OAE5B,MAAM0E,EAAgBpE,EAAmBD,GACnCsE,EAAoBD,EAAchE,MAAM,GACxCkE,EAAgBD,EAAkBE,MAAM/E,GAE9C,GAAI8E,EAAe,CACjB,MAAM,OAAEE,EAAM,OAAEC,EAAM,QAAEC,EAAO,KAAEC,GAASL,EAAcM,OAClDC,GAAiBH,EACjBI,EAAeN,EAAOjT,OAASkT,EAAOlT,OAE5C,GAAI6S,EAAclK,eAAiBkK,EAAcnE,SAAW6E,EAE1D,OAGF,GAAID,EAIF,YADA9E,EAAS7F,eAAiB6F,EAAS7F,eAAiBoK,EAAc,GAAG/S,QAIvE,IAAIwT,EAGJ,GAAIJ,EAAM,CAIRI,EAjDN,SAAwBT,EAAeU,GAAe,IAAAC,EACpD,MAAM,OAAER,EAAM,OAAED,GAAWF,EAAcM,QACjCH,OAAQS,EAAYP,KAAMQ,GAAkC,QAAxBF,EAAGD,aAAa,EAAbA,EAAeJ,cAAM,IAAAK,IAAI,IAEjEG,EAAQC,EAAU,IAAMb,EAAO9S,MAAM,KAEtC4T,EAAcH,GAAYD,IAAeT,EAAS,EAAI,EAG5D,MAAQ,GAAEA,IAFEc,SAASH,EAAQ,IAAME,KAETD,IAwCPG,CAAelB,EAHbxE,EAAmBC,EAAShB,MAAOgB,GACrBwE,MAAM/E,QAGhC,CACL,GAAI6E,EAAkBE,MAAM9E,GAAa,OAEzCsF,EAAgB,GAAEN,IAASD,IAG7BO,EAAeA,EAAanJ,QAAQ,YAAa,OAEjDzD,EAAEC,iBAEFqL,EAAW,CACTnC,IAAKyD,EACLhF,WACAH,SAAU,GACVnL,MAAM,EACN+M,OAAQ,GACRkC,WAAY,MAKX,SAAS+B,EAAiBtN,GAAG,IAAAuN,EAAAC,EAGb,QAArBD,GAAIC,EAAA7N,IAFalI,OAEDgW,aAAK,IAAAF,GAAjBA,EAAAG,KAAAF,EAAoB,iBAExB9B,EAAmB1L,EAJFvI,MAhHnB,SAAoCuI,EAAG4H,GACrC,IAAK/L,IAAI8R,4BAA6B,OACtC,GAAI3N,EAAE+L,SAAW/L,EAAE8L,QAAS,OAC5B,GAAIlE,EAAS7F,iBAAmB6F,EAAS3F,aAAc,OAEvD,MAWMkH,EAXO,CACX,IAAK,aACLyE,EAAG,WACH,IAAK,WACL,IAAK,WACL,IAAK,WACL,IAAK,WACL,IAAK,WACL,IAAK,WACL,IAAK,YAEU5N,EAAE4L,KAEfzC,IACFnJ,EAAEC,iBAEFqL,EAAW,CACTnC,MACAvB,WACAH,SAAU,GACVnL,MAAM,EACN+M,OAAQ,GACRkC,WAAY,MA0FhBsC,CAA2B7N,EALVvI,OAQZ,SAASqW,IACdvG,GAAyB,EAGpB,SAASwG,IACdxG,GAAyB,EAGpB,SAASyG,EAAwBC,GACtC,MAAMzC,EAAYyC,EAAYzR,QAAQ,YAAYtB,KAAK,YACvD,GAAKsQ,EAAUpS,OAEf,OAAQ6U,EAAYvW,KAAK,cACvB,IAAK,eA7MT,SAAqB8T,GACnB,MAAM5D,EAAW4D,EAAUrO,IAAI,IACzB,MAAE8K,EAAK,eAAElG,EAAc,aAAEE,EAAY,SAAE6F,EAAQ,OAAEE,GAAWH,EAAmBD,GAC/EsG,EAAe,GACrB,IAAIC,EAAa,EAEjBvG,EAAS5J,QACT4J,EAASrF,kBAAkBuF,EAAUE,GAErCC,EAAMnO,SAAQ,SAACsU,GACbA,EA5agB,IA4aGC,OA3aD,GA2ayBD,EAC3CD,GA5akB,EA8alBD,EAAanU,KAAKqU,MAGpB,MAAM3E,EAAeyE,EAAazV,KAAK,MAEvCsS,YAAWnD,EAAU6B,GACrBvB,EAAqBN,EAAU7F,EAAgBE,EAAc6F,EApbzC,EAobkEqG,GA2LlFG,CAAY9C,GACZ,MACF,IAAK,gBArLT,SAAsBA,GACpB,MAAM5D,EAAW4D,EAAUrO,IAAI,IACzB,MAAE8K,EAAK,eAAElG,EAAc,aAAEE,EAAY,SAAE6F,EAAQ,OAAEE,GAAWH,EAAmBD,GAC/EsG,EAAe,GACrB,IAAIK,EAAe,EACfC,GAAwB,EACxBC,EAAkB,EAEtB7G,EAAS5J,QACT4J,EAASrF,kBAAkBuF,EAAUE,GAErCC,EAAMnO,SAAQ,SAACsU,GAGb,GAFAK,EAAkB,EAEdL,EAAKhV,OAAS,EAAG,CAEnB,KAAOqV,EA5cS,GADF,MA6c4BL,EAAKK,IAC7CA,GAAmB,EAGjBA,EAAkB,IACpBL,EAAOA,EAAKM,MAAMD,GAClBF,GAAgBE,IAIU,IAA1BD,IAA6BA,EAAuBC,GACxDP,EAAanU,KAAKqU,MAGpB,MAAM3E,EAAeyE,EAAazV,KAAK,MAEnC8V,EAAe,GAAGxD,YAAWnD,EAAU6B,GAE3CvB,EACEN,EACA7F,EACAE,EACA6F,GACC0G,GACAD,GA8ICI,CAAanD,GACb,MACF,QACE,OAAOF,EAAW,CAChB1D,SAAU4D,EACVrC,IAAK8E,EAAYvW,KAAK,SACtB0R,aAAc6E,EAAYvW,KAAK,kBAC/B+P,SAAUwG,EAAYvW,KAAK,WAC3B4E,MAAO2R,EAAYvW,KAAK,aACxB2R,OAAQ4E,EAAYvW,KAAK,YACzB6T,WAAY0C,EAAYW,KAAK,0BAK9B,SAASlJ,EAAqB/K,GACnCgF,IAAE,iBAAkBhF,GACjBkC,GAAG,UAAWyQ,GACdzQ,GAAG,mBAAoBiR,GACvBjR,GAAG,iBAAkBkR,GACrBc,MAAK,WACJC,UAAUC,4BAA4BpP,IAAElI,MAAOuW,MAWnD,OARwBrO,IAAEhF,GACvBmL,IAAI,QAAS,UACbjJ,GAAG,QAAS,UAAU,WAGrB,OAAOmR,EAFarO,IAAElI,UAQrB,SAASuX,EAA2BvG,GAEzC9I,IAAE,UACCmG,IAAI,SACJjJ,GAAG,SAAS,SAACmD,GACZ,MAAM,MAAEiP,EAAK,QAAEC,EAAO,UAAEC,EAAS,SAAEC,GAAazP,IAAEK,EAAEqP,eAAe3X,OAEnEwR,EAAmB,CACjBC,IAAK8F,EACLxH,SAAUyH,EACV5S,MAAO6S,EACP9F,OAAQ+F,EACR1H,SAAUe,EAAO6G,kBACjBhQ,KAAMmJ,EAAOyB,WACbzB,WAEFA,EAAOzK,WAIN,SAASoI,EAAwBzL,GAUtC,OATAgF,IAAE,iBAAkBhF,GACjBmL,IAAI,UAAWwH,GACfxH,IAAI,mBAAoBgI,GACxBhI,IAAI,iBAAkBiI,GACtBc,MAAK,WACJC,UAAUS,8BAA8B5P,IAAElI,UAIvCkI,IAAE,SAAUhF,GAAMmL,IAAI,SAYxB,MAAM0J,EAAuBC,eAAO7H,EAAU8H,EAAsB,IACzE,MAAM,MAAEzH,EAAK,SAAEH,GAAaD,EAAmBD,GAG/C,GAAIK,EAAQ,EACV,OAAO,KAGT,MAAM0H,EAAe1H,EAAM,GAE3B,IAAK,kBAAkBjB,KAAK2I,GAAe,OAAO,KAElD,MAAMC,EAAqBhI,EAAS7F,eAAiB+F,EAC/C+H,EAAUF,EAAatN,UAAU,EAAGuN,GAAoB7H,YAAY,KACpE+H,EAAYH,EAAatN,UAAUuN,GAAoBxO,QAAQ,KAErE,GAAIyO,GAAW,GAAKC,GAAa,EAAG,CAClC,MAAMC,EAAgBJ,EAAatN,UAAUwN,EAASD,EAAqBE,EAAY,IACjF,KAAEpY,SAAe0L,IAAMC,KAAKqM,EAAqB,CAAEpQ,KAAMyQ,IAIzDC,GAHS,IAAI/W,WAEAC,gBAAgBxB,EAAKuY,KAAM,aACzBA,KAAK7S,cAAc,KAAK8S,aAAa,QAE1D,GAAIF,EAAU,CACZ,MAAM1O,EAAW0O,EAAS3N,UAAU2N,EAASjI,YAAY,KAAO,GAEhE,MAAO,CACLgI,gBACAC,WACA1O,aAKN,OAAO,O,wsBCxsBF,MAAM6O,EAA2B,2BAaxC,SAASC,EAA4BC,GACnC,MAAMC,EAAkBD,EAAU7T,QAAQ,YAAYtB,KAAK,UACrD9C,EAAM,IAAImY,IAWhB,OATAD,EAAgBzB,MAAK,WACnB,MAAMZ,EAActO,IAAElI,MAChB+Y,EAAoBvC,EAAYvW,KAAK,gBAEvC8Y,WAAmBpX,QACrBhB,EAAIqY,IAAIxC,EAAauC,MAIlBpY,EAGM,MAAM0W,EACnBvX,cAMEE,KAAKiZ,WAAa,IAAIH,IACtB9Y,KAAKkZ,aAAelZ,KAAKkZ,aAAa3K,KAAKvO,MAC3CA,KAAKmZ,iBAAmB,KACxBnZ,KAAKoZ,qBAAuB,KAE5BpZ,KAAKqZ,OAAO,CACV,CAACC,KAAkCtZ,KAAKkZ,cACxC,CAACK,KAAclC,EAAUmC,aACzB,CAACC,IAAkBzZ,KAAK0Z,YAAYnL,KAAKvO,OACzC,CAAC2Z,KAAwBtC,EAAUuC,iBACnC,CAACC,IAAwBxC,EAAUyC,sBACnC,CAACC,KAAe1C,EAAU2C,gBAE1B,CAACC,IAAsB,kBAAMC,YAAkB,sBAC/C,CAACC,IAAqB,kBAAMD,YAAkB,mCAC9C,CAACE,IAAmB,kBAAMF,YAAkB,iCAC5C,CAACG,IAA2B,kBAAMH,YAAkB,yCACpD,CAACI,IAA4B,kBAAMJ,YAAkB,0CACrD,CAACK,IAAqB,kBAAML,YAAkB,mCAC9C,CAACM,IAAmB,kBAAMN,YAAkB,iCAC5C,CAACO,IAAsB,kBAAMP,YAAkB,qCAC/C,CAACQ,IAAqB,kBAAMR,YAAkB,mCAE9C,CAACS,KAAyBtD,EAAUuD,yBAGtCC,aAAgB,SAACtS,EAAGuS,EAASC,GAAK,OAChCC,aAAQL,MAAyBvZ,SAAS2Z,SAAiB5R,KAG7D,MAAM8R,EAAcjM,SAASwJ,KAAK0C,QAAQC,SACtC,MAAOF,GACTjb,KAAKob,IAAIC,KAAyB,WAChCC,YAASL,MAIb/S,IAAE8G,UAAU5J,GAAG,QAAS,8BAA+BpF,KAAKkZ,cAExDqC,eACFC,cAmCJC,aAAaC,EAAWC,EAAO,GAAIC,EAA6B,IAAIC,KAClED,EAA2BR,IAAIM,GAE/B,IAAII,EAAW9b,KAAKiZ,WAAWvT,IAAIgW,GACnC,IAAKI,EAAU,CACb,IAAK,MAAMC,KAA6B,QAA1BC,EAAIN,EAAUO,oBAAY,IAAAD,IAAI,GAAI,KAAAA,EAC1CJ,EAA2BM,IAAIH,IAAQA,IAAQ1E,IAMnDuE,EAA2BR,IAAIW,GAE/B/b,KAAKyb,aAAaM,EAAK,GAAIH,IAG7BE,EAAW,IAAIJ,EAAU1b,QAAS2b,GAClC3b,KAAKiZ,WAAWD,IAAI0C,EAAWI,GAIjC,OADAF,EAA2BO,OAAOT,GAC3BI,EAaTV,IAAIgB,EAASC,GACXC,IAAU/N,KAAKyM,aAAQoB,GAAUC,GAWnChD,OAAOkD,GAAsB,IAAA/b,EAAA,KAC3B+b,EAAqBla,SAAQ,SAACma,GAAkB,OAAKhc,EAAK4a,OAAOoB,MAGnEtD,aAAa3Q,GAAG,IAAAhG,EAAA,KACVgG,WAAGC,gBACLD,EAAEC,iBAGAxI,KAAKmZ,kBAAoBnZ,KAAKoZ,sBAChCpZ,KAAKoZ,qBAAqBqD,WAC1Bzc,KAAKmZ,iBAAiBhR,SACtBnI,KAAKmZ,iBAAmB,KACxBnZ,KAAKoZ,qBAAuB,OAE5BpZ,KAAKmZ,iBAAmBnK,SAAS0N,cAAc,OAC/C1N,SAASwJ,KAAKrT,OAAOnF,KAAKmZ,kBAE1BnZ,KAAKoZ,qBAAuB,IAAIuD,UAAI,CAClCC,GAAI5c,KAAKmZ,iBACT0D,WAAY,CACVC,cAAe,kBAAM,6DAEvBC,OAAQ,SAACL,GACP,OAAOA,EAAc,iBAAkB,CACrCtX,GAAI,CACF4X,OAAQza,EAAK2W,oBAQzB,uBAAuB3Q,GACrBA,EAAEC,iBAEEyU,YAAaC,YADgB,qBAE/BC,YAF+B,mBAEK,QAAS,CAAE/R,KAAM,MAErD+R,YAJ+B,mBAIK,OAAQ,CAAE/R,KAAM,MAEtDgS,cAGF,sBAAsB7U,GACpBA,EAAEC,iBACF,MACM6U,EAAeJ,YAAaC,YADT,kBAEzBC,YAFyB,kBAEKE,GAAcjL,WAAY,CAAEkL,QAAS,IAAKlS,KAAM,MAC9EgS,cAGF,6BAA6B7U,GAC3BL,IAAE8G,UAAUuO,eAAe,0BAA2B,CAAChV,IAGzDmR,YAAYnR,GACLvI,KAAKwd,cACRxd,KAAKwd,YAActV,IAAE,qBAAsB,kBAE7ClI,KAAKwd,YAAYjX,QACjBgC,EAAEC,iBAGJ,mBAAmBD,GAAG,IAAAkV,EAC2B,QAA/CA,EAAAzO,SAASrJ,cAAc,gCAAwB,IAAA8X,GAA/CA,EAAiDjS,QAE7CjD,EAAEC,gBACJD,EAAEC,iBAIN,4BAA4BD,GACTyG,SAAStN,iBAAiB,sBAElCW,SAAQ,SAACyY,GAChBA,EAAQ/P,MAAM2S,QAAU,UAGtBnV,EAAEC,gBACJD,EAAEC,iBAYN,mCAAmCoQ,EAAW+E,GAC5C,MAAMC,EAA2BjF,EAA4BC,GAEvDiF,EAAiB,IAAIvB,IAAU1D,EAAU,IAI/CA,EAAU3Y,KAAKyY,EAA0BmF,GAEzCD,EAAyBvb,SAAQ,SAAC0W,EAAmBvC,GACnDqH,EAAetP,KAAKwK,GAAmB,SAACxQ,GACtCA,EAAEC,iBAEFmV,EAAQnH,SAKZ,MAAMsH,EAAeC,IAAQ,IAAIH,EAAyBI,WAEpDC,EAAuB3B,IAAU4B,UAAUC,aACjDN,EAAeM,aAAe,SAAyB5V,EAAGuS,EAASC,GACjE,OAAI+C,EAAa1c,SAAS2Z,IAInBkD,EAAqBhI,KAAKjW,KAAMuI,EAAGuS,EAASC,IAcvD,qCAAqCnC,GACnC,MAAMiF,EAAiBjF,EAAU3Y,KAAKyY,GAElCmF,GACFlF,EAA4BC,GAAWvW,SAAQ,SAAC0W,GAC9C8E,EAAeO,OAAOrF","file":"commons-pages.admin.abuse_reports.show-pages.admin.topics.edit-pages.admin.topics.new-pages.groups.i-f0d44188.70c14bf2.chunk.js","sourcesContent":["const maxColumnWidth = (rows, columnIndex) =>\n Math.max(...rows.map((row) => row[columnIndex].length));\n\nexport default class PasteMarkdownTable {\n constructor(clipboardData) {\n this.data = clipboardData;\n this.columnWidths = [];\n this.rows = [];\n this.tableFound = this.parseTable();\n }\n\n isTable() {\n return this.tableFound;\n }\n\n convertToTableMarkdown() {\n this.calculateColumnWidths();\n\n const markdownRows = this.rows.map(\n (row) =>\n // | Name | Title | Email Address |\n // |--------------|-------|----------------|\n // | Jane Atler | CEO | jane@acme.com |\n // | John Doherty | CTO | john@acme.com |\n // | Sally Smith | CFO | sally@acme.com |\n `| ${row.map((column, index) => this.formatColumn(column, index)).join(' | ')} |`,\n );\n\n // Insert a header break (e.g. -----) to the second row\n markdownRows.splice(1, 0, this.generateHeaderBreak());\n\n return markdownRows.join('\\n');\n }\n\n // Private methods below\n\n // To determine whether the cut data is a table, the following criteria\n // must be satisfied with the clipboard data:\n //\n // 1. MIME types \"text/plain\" and \"text/html\" exist\n // 2. The \"text/html\" data must have a single element\n // 3. The number of rows in the \"text/plain\" data matches that of the \"text/html\" data\n // 4. The max number of columns in \"text/plain\" matches that of the \"text/html\" data\n parseTable() {\n if (!this.data.types.includes('text/html') || !this.data.types.includes('text/plain')) {\n return false;\n }\n\n const htmlData = this.data.getData('text/html');\n this.doc = new DOMParser().parseFromString(htmlData, 'text/html');\n // Avoid formatting lines that were copied from a diff\n const tables = this.doc.querySelectorAll('table:not(.diff-wrap-lines)');\n\n // We're only looking for exactly one table. If there happens to be\n // multiple tables, it's possible an application copied data into\n // the clipboard that is not related to a simple table. It may also be\n // complicated converting multiple tables into Markdown.\n if (tables.length !== 1) {\n return false;\n }\n\n const text = this.data.getData('text/plain').trim();\n const splitRows = text.split(/[\\n\\u0085\\u2028\\u2029]|\\r\\n?/g);\n\n // Now check that the number of rows matches between HTML and text\n if (this.doc.querySelectorAll('tr').length !== splitRows.length) {\n return false;\n }\n\n this.rows = splitRows.map((row) => row.split('\\t'));\n this.normalizeRows();\n\n // Check that the max number of columns in the HTML matches the number of\n // columns in the text. GitHub, for example, copies a line number and the\n // line itself into the HTML data.\n if (!this.columnCountsMatch()) {\n return false;\n }\n\n return true;\n }\n\n // Ensure each row has the same number of columns\n normalizeRows() {\n const rowLengths = this.rows.map((row) => row.length);\n const maxLength = Math.max(...rowLengths);\n\n this.rows.forEach((row) => {\n while (row.length < maxLength) {\n row.push('');\n }\n });\n }\n\n calculateColumnWidths() {\n this.columnWidths = this.rows[0].map((_column, columnIndex) =>\n maxColumnWidth(this.rows, columnIndex),\n );\n }\n\n columnCountsMatch() {\n const textColumnCount = this.rows[0].length;\n let htmlColumnCount = 0;\n\n this.doc.querySelectorAll('table tr').forEach((row) => {\n htmlColumnCount = Math.max(row.cells.length, htmlColumnCount);\n });\n\n return textColumnCount === htmlColumnCount;\n }\n\n formatColumn(column, index) {\n const spaces = Array(this.columnWidths[index] - column.length + 1).join(' ');\n return column + spaces;\n }\n\n generateHeaderBreak() {\n // Add 3 dashes to line things up: there is additional spacing for the pipe characters\n const dashes = this.columnWidths.map((width, index) =>\n Array(this.columnWidths[index] + 3).join('-'),\n );\n return `|${dashes.join('|')}|`;\n }\n}\n","import Dropzone from 'dropzone';\nimport $ from 'jquery';\nimport { escape } from 'lodash';\nimport './behaviors/preview_markdown';\nimport { spriteIcon } from '~/lib/utils/common_utils';\nimport { getFilename } from '~/lib/utils/file_upload';\nimport { truncate } from '~/lib/utils/text_utility';\nimport { n__, __ } from '~/locale';\nimport PasteMarkdownTable from './behaviors/markdown/paste_markdown_table';\nimport axios from './lib/utils/axios_utils';\nimport csrf from './lib/utils/csrf';\n\nDropzone.autoDiscover = false;\n\n/**\n * Return the error message string from the given response.\n *\n * @param {String|Object} res\n */\nfunction getErrorMessage(res) {\n if (!res || typeof res === 'string') {\n return res;\n }\n\n return res.message;\n}\n\nexport default function dropzoneInput(form, config = { parallelUploads: 2 }) {\n const divHover = '
';\n const iconPaperclip = spriteIcon('paperclip', 'div-dropzone-icon s24');\n const $attachingFileMessage = form.find('.attaching-file-message');\n const $cancelButton = form.find('.button-cancel-uploading-files');\n const $retryLink = form.find('.retry-uploading-link');\n const $uploadProgress = form.find('.uploading-progress');\n const $uploadingErrorContainer = form.find('.uploading-error-container');\n const $uploadingErrorMessage = form.find('.uploading-error-message');\n const $uploadingProgressContainer = form.find('.uploading-progress-container');\n const uploadsPath = form.data('uploads-path') || window.uploads_path || null;\n const maxFileSize = gon.max_file_size || 10;\n const formTextarea = form.find('.js-gfm-input');\n let handlePaste;\n let pasteText;\n let addFileToForm;\n let updateAttachingMessage;\n let uploadFile;\n let hasPlainText;\n\n formTextarea.wrap('
');\n\n // Add dropzone area to the form.\n const $mdArea = formTextarea.closest('.md-area');\n const $formDropzone = form.find('.div-dropzone');\n $formDropzone.parent().addClass('div-dropzone-wrapper');\n $formDropzone.append(divHover);\n $formDropzone.find('.div-dropzone-hover').append(iconPaperclip);\n\n if (!uploadsPath) {\n $formDropzone.addClass('js-invalid-dropzone');\n return null;\n }\n\n formTextarea.on('paste', (event) => handlePaste(event));\n\n const dropzone = $formDropzone.dropzone({\n url: uploadsPath,\n dictDefaultMessage: '',\n clickable: form.get(0).querySelector('[data-button-type=\"attach-file\"]') ?? true,\n paramName: 'file',\n maxFilesize: maxFileSize,\n uploadMultiple: false,\n headers: csrf.headers,\n previewContainer: false,\n ...config,\n dragover: () => {\n $mdArea.addClass('is-dropzone-hover');\n form.find('.div-dropzone-hover').css('opacity', 0.7);\n },\n dragleave: () => {\n $mdArea.removeClass('is-dropzone-hover');\n form.find('.div-dropzone-hover').css('opacity', 0);\n },\n drop: () => {\n $mdArea.removeClass('is-dropzone-hover');\n form.find('.div-dropzone-hover').css('opacity', 0);\n formTextarea.focus();\n },\n success(header, response) {\n const processingFileCount = this.getQueuedFiles().length + this.getUploadingFiles().length;\n const shouldPad = processingFileCount >= 1;\n\n addFileToForm(response.link.url, header.size);\n pasteText(response.link.markdown, shouldPad);\n },\n error: (file, errorMessage = __('Attaching the file failed.'), xhr) => {\n // If 'error' event is fired by dropzone, the second parameter is error message.\n // If the 'errorMessage' parameter is empty, the default error message is set.\n // If the 'error' event is fired by backend (xhr) error response, the third parameter is\n // xhr object (xhr.responseText is error message).\n // On error we hide the 'Attach' and 'Cancel' buttons\n // and show an error.\n const message = getErrorMessage(errorMessage || xhr.responseText);\n\n $uploadingErrorContainer.removeClass('hide');\n $uploadingErrorMessage.html(message);\n $cancelButton.addClass('hide');\n },\n totaluploadprogress(totalUploadProgress) {\n updateAttachingMessage(this.files, $attachingFileMessage);\n $uploadProgress.text(`${Math.round(totalUploadProgress)}%`);\n },\n sending: () => {\n // DOM elements already exist.\n // Instead of dynamically generating them,\n // we just either hide or show them.\n $uploadingErrorContainer.addClass('hide');\n $uploadingProgressContainer.removeClass('hide');\n $cancelButton.removeClass('hide');\n },\n removedfile: () => {\n $cancelButton.addClass('hide');\n $uploadingProgressContainer.addClass('hide');\n $uploadingErrorContainer.addClass('hide');\n },\n queuecomplete: () => {\n $('.dz-preview').remove();\n $('.markdown-area').trigger('input');\n\n $uploadingProgressContainer.addClass('hide');\n $cancelButton.addClass('hide');\n },\n });\n\n const child = $(dropzone[0]).children('textarea');\n\n // removeAllFiles(true) stops uploading files (if any)\n // and remove them from dropzone files queue.\n $cancelButton.on('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n Dropzone.forElement($formDropzone.get(0)).removeAllFiles(true);\n });\n\n // If 'error' event is fired, we store a failed files,\n // clear dropzone files queue, change status of failed files to undefined,\n // and add that files to the dropzone files queue again.\n // addFile() adds file to dropzone files queue and upload it.\n $retryLink.on('click', (e) => {\n const dropzoneInstance = Dropzone.forElement(\n e.target.closest('.js-main-target-form').querySelector('.div-dropzone'),\n );\n const failedFiles = dropzoneInstance.files;\n\n e.preventDefault();\n\n // 'true' parameter of removeAllFiles() cancels\n // uploading of files that are being uploaded at the moment.\n dropzoneInstance.removeAllFiles(true);\n\n failedFiles.map((failedFile) => {\n const file = failedFile;\n\n if (file.status === Dropzone.ERROR) {\n file.status = undefined;\n file.accepted = undefined;\n }\n\n return dropzoneInstance.addFile(file);\n });\n });\n\n handlePaste = (event) => {\n const pasteEvent = event.originalEvent;\n const { clipboardData } = pasteEvent;\n if (clipboardData && clipboardData.items) {\n const converter = new PasteMarkdownTable(clipboardData);\n // Apple Numbers copies a table as an image, HTML, and text, so\n // we need to check for the presence of a table first.\n if (converter.isTable()) {\n event.preventDefault();\n const text = converter.convertToTableMarkdown();\n pasteText(text);\n } else if (!hasPlainText(pasteEvent)) {\n const fileList = [...clipboardData.files];\n fileList.forEach((file) => {\n if (file.type.indexOf('image') !== -1) {\n event.preventDefault();\n const MAX_FILE_NAME_LENGTH = 246;\n\n const filename = getFilename(file) || 'image.png';\n const truncateFilename = truncate(filename, MAX_FILE_NAME_LENGTH);\n const text = `{{${truncateFilename}}}`;\n pasteText(text);\n\n uploadFile(file, truncateFilename);\n }\n });\n }\n }\n };\n\n hasPlainText = (data) => {\n const clipboardDataList = [...data.clipboardData.items];\n return clipboardDataList.some((item) => item.type === 'text/plain');\n };\n\n pasteText = (text, shouldPad) => {\n let formattedText = text;\n if (shouldPad) {\n formattedText += '\\n\\n';\n }\n const textarea = child.get(0);\n const caretStart = textarea.selectionStart;\n const caretEnd = textarea.selectionEnd;\n const textEnd = $(child).val().length;\n const beforeSelection = $(child).val().substring(0, caretStart);\n const afterSelection = $(child).val().substring(caretEnd, textEnd);\n $(child).val(beforeSelection + formattedText + afterSelection);\n textarea.setSelectionRange(caretStart + formattedText.length, caretEnd + formattedText.length);\n textarea.style.height = `${textarea.scrollHeight}px`;\n formTextarea.get(0).dispatchEvent(new Event('input'));\n return formTextarea.trigger('input');\n };\n\n addFileToForm = (path) => {\n $(form).append(``);\n };\n\n const showSpinner = () => $uploadingProgressContainer.removeClass('hide');\n\n const closeSpinner = () => $uploadingProgressContainer.addClass('hide');\n\n const showError = (message) => {\n $uploadingErrorContainer.removeClass('hide');\n $uploadingErrorMessage.html(message);\n };\n\n const insertToTextArea = (filename, url) => {\n const $child = $(child);\n const textarea = $child.get(0);\n const caretStart = textarea.selectionStart;\n const caretEnd = textarea.selectionEnd;\n const formattedText = `{{${filename}}}`;\n $child.val((index, val) => val.replace(formattedText, url));\n textarea.setSelectionRange(\n caretStart - formattedText.length + url.length,\n caretEnd - formattedText.length + url.length,\n );\n $child.trigger('change');\n };\n\n uploadFile = (item, filename) => {\n const formData = new FormData();\n formData.append('file', item, filename);\n\n showSpinner();\n\n axios\n .post(uploadsPath, formData)\n .then(({ data }) => {\n const md = data.link.markdown;\n\n insertToTextArea(filename, md);\n closeSpinner();\n })\n .catch((e) => {\n showError(e.response.data.message);\n closeSpinner();\n });\n };\n\n updateAttachingMessage = (files, messageContainer) => {\n const filesCount = files.filter(\n (file) => file.status === 'uploading' || file.status === 'queued',\n ).length;\n const attachingMessage = n__('Attaching a file', 'Attaching %d files', filesCount);\n\n messageContainer.text(`${attachingMessage} -`);\n };\n\n function handleAttachFile(e) {\n e.preventDefault();\n $(this).closest('.gfm-form').find('.div-dropzone').click();\n formTextarea.focus();\n }\n\n form.find('.markdown-selector').click(handleAttachFile);\n\n const $attachFileButton = form.find('.js-attach-file-button');\n if ($attachFileButton.length) {\n $attachFileButton.get(0).addEventListener('click', handleAttachFile);\n }\n\n return $formDropzone.get(0) ? Dropzone.forElement($formDropzone.get(0)) : null;\n}\n","import autosize from 'autosize';\nimport $ from 'jquery';\nimport { isEmpty } from 'lodash';\nimport GfmAutoComplete, { defaultAutocompleteConfig } from 'ee_else_ce/gfm_auto_complete';\nimport { disableButtonIfEmptyField } from '~/lib/utils/common_utils';\nimport dropzoneInput from './dropzone_input';\nimport { addMarkdownListeners, removeMarkdownListeners } from './lib/utils/text_markdown';\n\nexport default class GLForm {\n /**\n * Create a GLForm\n *\n * @param {jQuery} form Root element of the GLForm\n * @param {Object} enableGFM Which autocomplete features should be enabled?\n * @param {Boolean} forceNew If true, treat the element as a **new** form even if `gfm-form` class already exists.\n * @param {Object} gfmDataSources The paths of the autocomplete data sources to use for GfmAutoComplete\n * By default, the backend embeds these in the global object gl.GfmAutocomplete.dataSources.\n * Use this param to override them.\n */\n constructor(form, enableGFM = {}, forceNew = false, gfmDataSources = {}) {\n this.form = form;\n this.textarea = this.form.find('textarea.js-gfm-input');\n this.enableGFM = { ...defaultAutocompleteConfig, ...enableGFM };\n\n // Disable autocomplete for keywords which do not have dataSources available\n let dataSources = (gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources) || {};\n\n if (!isEmpty(gfmDataSources)) {\n dataSources = gfmDataSources;\n }\n\n Object.keys(this.enableGFM).forEach((item) => {\n if (item !== 'emojis' && !dataSources[item]) {\n this.enableGFM[item] = false;\n }\n });\n\n // Before we start, we should clean up any previous data for this form\n this.destroy();\n // Set up the form\n this.setupForm(dataSources, forceNew);\n this.form.data('glForm', this);\n }\n\n destroy() {\n // Clean form listeners\n this.clearEventListeners();\n if (this.autoComplete) {\n this.autoComplete.destroy();\n }\n if (this.formDropzone) {\n this.formDropzone.destroy();\n }\n\n this.form.data('glForm', null);\n }\n\n setupForm(dataSources, forceNew = false) {\n const isNewForm = this.form.is(':not(.gfm-form)') || forceNew;\n this.form.removeClass('js-new-note-form');\n if (isNewForm) {\n this.form.find('.div-dropzone').remove();\n this.form.addClass('gfm-form');\n // remove notify commit author checkbox for non-commit notes\n disableButtonIfEmptyField(\n this.form.find('.js-note-text'),\n this.form.find('.js-comment-button, .js-note-new-discussion'),\n );\n this.autoComplete = new GfmAutoComplete(dataSources);\n this.autoComplete.setup(this.form.find('.js-gfm-input'), this.enableGFM);\n this.formDropzone = dropzoneInput(this.form, { parallelUploads: 1 });\n\n if (this.form.is(':not(.js-no-autosize)')) {\n autosize(this.textarea);\n }\n }\n // form and textarea event listeners\n this.addEventListeners();\n addMarkdownListeners(this.form);\n this.form.show();\n if (this.isAutosizeable) this.setupAutosize();\n if (this.textarea.data('autofocus') === true) this.textarea.focus();\n }\n\n setupAutosize() {\n // eslint-disable-next-line @gitlab/no-global-event-off\n this.textarea.off('autosize:resized').on('autosize:resized', this.setHeightData.bind(this));\n\n // eslint-disable-next-line @gitlab/no-global-event-off\n this.textarea.off('mouseup.autosize').on('mouseup.autosize', this.destroyAutosize.bind(this));\n\n setTimeout(() => {\n autosize(this.textarea);\n this.textarea.css('resize', 'vertical');\n }, 0);\n }\n\n setHeightData() {\n this.textarea.data('height', this.textarea.outerHeight());\n }\n\n destroyAutosize() {\n const outerHeight = this.textarea.outerHeight();\n\n if (this.textarea.data('height') === outerHeight) return;\n\n autosize.destroy(this.textarea);\n\n this.textarea.data('height', outerHeight);\n this.textarea.outerHeight(outerHeight);\n this.textarea.css('max-height', window.outerHeight);\n }\n\n clearEventListeners() {\n // eslint-disable-next-line @gitlab/no-global-event-off\n this.textarea.off('focus');\n // eslint-disable-next-line @gitlab/no-global-event-off\n this.textarea.off('blur');\n removeMarkdownListeners(this.form);\n }\n\n addEventListeners() {\n this.textarea.on('focus', function focusTextArea() {\n $(this).closest('.md-area').addClass('is-focused');\n });\n this.textarea.on('blur', function blurTextArea() {\n $(this).closest('.md-area').removeClass('is-focused');\n });\n }\n\n get supportsQuickActions() {\n return Boolean(this.textarea.data('supports-quick-actions'));\n }\n}\n","export default (buttonSelector, fileSelector) => {\n const btn = document.querySelector(buttonSelector);\n const fileInput = document.querySelector(fileSelector);\n\n if (!btn || !fileInput) return;\n\n const form = btn.closest('form');\n\n btn.addEventListener('click', () => {\n fileInput.click();\n });\n\n fileInput.addEventListener('change', () => {\n form.querySelector('.js-filename').textContent = fileInput.value.replace(/^.*[\\\\\\/]/, ''); // eslint-disable-line no-useless-escape\n });\n};\n\nexport const getFilename = (file) => {\n let fileName;\n if (file) {\n fileName = file.name;\n }\n\n return fileName;\n};\n\nexport const validateImageName = (file) => {\n const fileName = file.name ? file.name : 'image.png';\n const legalImageRegex = /^[\\w.\\-+]+\\.(png|jpg|jpeg|gif|bmp|tiff|ico|webp)$/;\n return legalImageRegex.test(fileName) ? fileName : 'image.png';\n};\n\nexport const validateFileFromAllowList = (fileName, allowList) => {\n const parts = fileName.split('.');\n const ext = `.${parts[parts.length - 1]}`;\n\n return allowList.includes(ext);\n};\n","/* eslint-disable func-names, no-param-reassign, operator-assignment, consistent-return */\nimport $ from 'jquery';\nimport Shortcuts from '~/behaviors/shortcuts/shortcuts';\nimport { insertText } from '~/lib/utils/common_utils';\nimport axios from '~/lib/utils/axios_utils';\n\nconst LINK_TAG_PATTERN = '[{text}](url)';\nconst INDENT_CHAR = ' ';\nconst INDENT_LENGTH = 2;\n\n// at the start of a line, find any amount of whitespace followed by\n// a bullet point character (*+-) and an optional checkbox ([ ] [x])\n// OR a number with a . after it and an optional checkbox ([ ] [x])\n// followed by one or more whitespace characters\nconst LIST_LINE_HEAD_PATTERN = /^(?\\s*)(?((?[*+-])|(?\\d+\\.))( \\[([xX~\\s])\\])?\\s)(?.)?/;\n\n// detect a horizontal rule that might be mistaken for a list item (not full pattern for an
)\nconst HR_PATTERN = /^((\\s{0,3}-+\\s*-+\\s*-+\\s*[\\s-]*)|(\\s{0,3}\\*+\\s*\\*+\\s*\\*+\\s*[\\s*]*))$/;\n\nlet compositioningNoteText = false;\n\nfunction selectedText(text, textarea) {\n return text.substring(textarea.selectionStart, textarea.selectionEnd);\n}\n\nfunction addBlockTags(blockTag, selected) {\n return `${blockTag}\\n${selected}\\n${blockTag}`;\n}\n\n/**\n * Returns the line of text that is before the first line\n * of the current selection\n *\n * @param {String} text - the text of the targeted text area\n * @param {Object} textArea - the targeted text area\n * @returns {String}\n */\nfunction lineBeforeSelection(text, textArea) {\n let split = text.substring(0, textArea.selectionStart);\n\n split = split.split('\\n');\n\n // Last item, at -1, is the line where the start of selection is.\n // Line before selection is therefore at -2\n const lineBefore = split[split.length - 2];\n\n return lineBefore === undefined ? '' : lineBefore;\n}\n\n/**\n * Returns the line of text that is after the last line\n * of the current selection\n *\n * @param {String} text - the text of the targeted text area\n * @param {Object} textArea - the targeted text area\n * @returns {String}\n */\nfunction lineAfterSelection(text, textArea) {\n let split = text.substring(textArea.selectionEnd);\n\n // remove possible leading newline to get at the real line\n split = split.replace(/^\\n/, '');\n split = split.split('\\n');\n\n return split[0];\n}\n\n/**\n * Returns the text lines that encompass the current selection\n *\n * @param {Object} textArea - the targeted text area\n * @returns {Object}\n */\nfunction linesFromSelection(textArea) {\n const text = textArea.value;\n const { selectionStart, selectionEnd } = textArea;\n\n let startPos = text[selectionStart] === '\\n' ? selectionStart - 1 : selectionStart;\n startPos = text.lastIndexOf('\\n', startPos) + 1;\n\n let endPos = selectionEnd === selectionStart ? selectionEnd : selectionEnd - 1;\n endPos = text.indexOf('\\n', endPos);\n if (endPos < 0) endPos = text.length;\n\n const selectedRange = text.substring(startPos, endPos);\n const lines = selectedRange.split('\\n');\n\n return {\n lines,\n selectionStart,\n selectionEnd,\n startPos,\n endPos,\n };\n}\n\n/**\n * Set the selection of a textarea such that it maintains the\n * previous selection before the lines were indented/outdented\n *\n * @param {Object} textArea - the targeted text area\n * @param {Number} selectionStart - start position of original selection\n * @param {Number} selectionEnd - end position of original selection\n * @param {Number} lineStart - start pos of first line\n * @param {Number} firstLineChange - number of characters changed on first line\n * @param {Number} totalChanged - total number of characters changed\n */\nfunction setNewSelectionRange(\n textArea,\n selectionStart,\n selectionEnd,\n lineStart,\n firstLineChange,\n totalChanged,\n) {\n let newStart = Math.max(lineStart, selectionStart + firstLineChange);\n let newEnd = Math.max(lineStart, selectionEnd + totalChanged);\n\n if (selectionStart === selectionEnd) {\n newEnd = newStart;\n } else if (selectionStart === lineStart) {\n newStart = lineStart;\n }\n\n textArea.setSelectionRange(newStart, newEnd);\n}\n\nfunction convertMonacoSelectionToAceFormat(sel) {\n return {\n start: {\n row: sel.startLineNumber,\n column: sel.startColumn,\n },\n end: {\n row: sel.endLineNumber,\n column: sel.endColumn,\n },\n };\n}\n\nfunction getEditorSelectionRange(editor) {\n return convertMonacoSelectionToAceFormat(editor.getSelection());\n}\n\nfunction editorBlockTagText(text, blockTag, selected, editor) {\n const lines = text.split('\\n');\n const selectionRange = getEditorSelectionRange(editor);\n const shouldRemoveBlock =\n lines[selectionRange.start.row - 1] === blockTag &&\n lines[selectionRange.end.row + 1] === blockTag;\n\n if (shouldRemoveBlock) {\n if (blockTag !== null) {\n const lastLine = lines[selectionRange.end.row + 1];\n const rangeWithBlockTags = new Range(\n lines[selectionRange.start.row - 1],\n 0,\n selectionRange.end.row + 1,\n lastLine.length,\n );\n editor.getSelection().setSelectionRange(rangeWithBlockTags);\n }\n return selected;\n }\n return addBlockTags(blockTag, selected);\n}\n\nfunction blockTagText(text, textArea, blockTag, selected) {\n const shouldRemoveBlock =\n lineBeforeSelection(text, textArea) === blockTag &&\n lineAfterSelection(text, textArea) === blockTag;\n\n if (shouldRemoveBlock) {\n // To remove the block tag we have to select the line before & after\n if (blockTag != null) {\n textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1);\n textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1);\n }\n return selected;\n }\n return addBlockTags(blockTag, selected);\n}\n\nfunction moveCursor({\n textArea,\n tag,\n cursorOffset,\n positionBetweenTags,\n removedLastNewLine,\n select,\n editor,\n editorSelectionStart,\n editorSelectionEnd,\n}) {\n let pos;\n if (textArea && !textArea.setSelectionRange) {\n return;\n }\n if (select && select.length > 0) {\n if (textArea) {\n // calculate the part of the text to be selected\n const startPosition = textArea.selectionStart - (tag.length - tag.indexOf(select));\n const endPosition = startPosition + select.length;\n return textArea.setSelectionRange(startPosition, endPosition);\n }\n if (editor) {\n editor.selectWithinSelection(select, tag);\n return;\n }\n }\n if (textArea) {\n if (textArea.selectionStart === textArea.selectionEnd) {\n if (positionBetweenTags) {\n pos = textArea.selectionStart - tag.length;\n } else {\n pos = textArea.selectionStart;\n }\n\n if (removedLastNewLine) {\n pos -= 1;\n }\n\n if (cursorOffset) {\n pos -= cursorOffset;\n }\n\n return textArea.setSelectionRange(pos, pos);\n }\n } else if (editor && editorSelectionStart.row === editorSelectionEnd.row) {\n if (positionBetweenTags) {\n editor.moveCursor(tag.length * -1);\n }\n }\n}\n\n/**\n * Inserts the given MarkdownText into the given textArea or editor\n *\n * WARNING: This is a bit of legacy code that has some complicated logic.\n * There are a lot of hidden contexts to consider here. Please proceed with caution.\n *\n * We've tried to document the parameter responsibilities as best as possible.\n * Please look for actual usage in the code to verify any assumptions.\n *\n * @param {Object} options - Named parameters\n * @param {HTMLTextAreaElement} options.textArea - The relevant text area\n * @param {String} options.text - The current text of the text area\n * @param {String} options.tag - The markdown tag we want to enter (Example: `- [ ] ` for lists)\n * @param {Number} options.cursorOffset - Applied to the position after we insert the text (moves backward)\n * @param {String} options.blockTag - The markdown tag to use if a block is detected (Example ` ``` ` vs. ` ` `)\n * @param {Boolean} options.wrap - Flag for whether the tag is a wrapping tag (Example `**text**` vs `* text`)\n * @param {String} options.select - The text to select after inserting (Example `url` of `({text})[url]`)\n * @param {Object} options.editor - The instance of the SourceEditor which we are inserting MarkdownText into. This should be mutually exclusive with textArea.\n */\nexport function insertMarkdownText({\n textArea,\n text,\n tag,\n cursorOffset,\n blockTag,\n selected = '',\n wrap,\n select,\n editor,\n}) {\n // If we aren't really inserting anything, let's just noop.\n // Let's check for `selected` too because there might be hidden logic that actually\n // is expected to run for this case.\n if (!tag && !blockTag && !selected) {\n return;\n }\n\n let removedLastNewLine = false;\n let removedFirstNewLine = false;\n let currentLineEmpty = false;\n let editorSelectionStart;\n let editorSelectionEnd;\n let lastNewLine;\n let textToInsert;\n selected = selected.toString();\n\n if (editor) {\n const selectionRange = getEditorSelectionRange(editor);\n\n editorSelectionStart = selectionRange.start;\n editorSelectionEnd = selectionRange.end;\n }\n\n // check for link pattern and selected text is an URL\n // if so fill in the url part instead of the text part of the pattern.\n if (tag === LINK_TAG_PATTERN) {\n if (URL) {\n try {\n const url = new URL(selected);\n\n if (url.origin !== 'null' || url.origin === null) {\n tag = '[text]({text})';\n select = 'text';\n }\n } catch (e) {\n // ignore - no valid url\n }\n }\n }\n\n // Remove the first newline\n if (selected.indexOf('\\n') === 0) {\n removedFirstNewLine = true;\n selected = selected.replace(/\\n+/, '');\n }\n\n // Remove the last newline\n if (textArea) {\n if (textArea.selectionEnd - textArea.selectionStart > selected.replace(/\\n$/, '').length) {\n removedLastNewLine = true;\n selected = selected.replace(/\\n$/, '');\n }\n } else if (editor) {\n if (editorSelectionStart.row !== editorSelectionEnd.row) {\n removedLastNewLine = true;\n selected = selected.replace(/\\n$/, '');\n }\n }\n\n const selectedSplit = selected.split('\\n');\n\n if (editor && !wrap) {\n lastNewLine = editor.getValue().split('\\n')[editorSelectionStart.row];\n\n if (/^\\s*$/.test(lastNewLine)) {\n currentLineEmpty = true;\n }\n } else if (textArea && !wrap) {\n lastNewLine = textArea.value.substr(0, textArea.selectionStart).lastIndexOf('\\n');\n\n // Check whether the current line is empty or consists only of spaces(=handle as empty)\n if (/^\\s*$/.test(textArea.value.substring(lastNewLine, textArea.selectionStart))) {\n currentLineEmpty = true;\n }\n }\n\n const isBeginning =\n (textArea && textArea.selectionStart === 0) ||\n (editor && editorSelectionStart.column === 0 && editorSelectionStart.row === 0);\n\n const startChar = !wrap && !currentLineEmpty && !isBeginning ? '\\n' : '';\n const textPlaceholder = '{text}';\n\n if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) {\n if (blockTag != null && blockTag !== '') {\n textToInsert = editor\n ? editorBlockTagText(text, blockTag, selected, editor)\n : blockTagText(text, textArea, blockTag, selected);\n } else {\n textToInsert = selectedSplit\n .map((val) => {\n if (tag.indexOf(textPlaceholder) > -1) {\n return tag.replace(textPlaceholder, val);\n }\n if (val.indexOf(tag) === 0) {\n return String(val.replace(tag, ''));\n }\n return String(tag) + val;\n })\n .join('\\n');\n }\n } else if (tag.indexOf(textPlaceholder) > -1) {\n textToInsert = tag.replace(textPlaceholder, () =>\n selected.replace(/\\\\n/g, '\\n').replace(/%br/g, '\\\\n'),\n );\n } else {\n textToInsert = String(startChar) + tag + selected + (wrap ? tag : '');\n }\n\n if (removedFirstNewLine) {\n textToInsert = `\\n${textToInsert}`;\n }\n\n if (removedLastNewLine) {\n textToInsert += '\\n';\n }\n\n if (editor) {\n editor.replaceSelectedText(textToInsert, select);\n } else {\n insertText(textArea, textToInsert);\n }\n\n moveCursor({\n textArea,\n tag: tag.replace(textPlaceholder, selected),\n cursorOffset,\n positionBetweenTags: wrap && selected.length === 0,\n removedLastNewLine,\n select,\n editor,\n editorSelectionStart,\n editorSelectionEnd,\n });\n}\n\nexport function updateText({ textArea, tag, cursorOffset, blockTag, wrap, select, tagContent }) {\n const $textArea = $(textArea);\n textArea = $textArea.get(0);\n const text = $textArea.val();\n const selected = selectedText(text, textArea) || tagContent;\n textArea.focus();\n insertMarkdownText({\n textArea,\n text,\n tag,\n cursorOffset,\n blockTag,\n selected,\n wrap,\n select,\n });\n textArea.click();\n}\n\n/**\n * Indents selected lines to the right by 2 spaces\n *\n * @param {Object} textArea - jQuery object with the targeted text area\n */\nfunction indentLines($textArea) {\n const textArea = $textArea.get(0);\n const { lines, selectionStart, selectionEnd, startPos, endPos } = linesFromSelection(textArea);\n const shiftedLines = [];\n let totalAdded = 0;\n\n textArea.focus();\n textArea.setSelectionRange(startPos, endPos);\n\n lines.forEach((line) => {\n line = INDENT_CHAR.repeat(INDENT_LENGTH) + line;\n totalAdded += INDENT_LENGTH;\n\n shiftedLines.push(line);\n });\n\n const textToInsert = shiftedLines.join('\\n');\n\n insertText(textArea, textToInsert);\n setNewSelectionRange(textArea, selectionStart, selectionEnd, startPos, INDENT_LENGTH, totalAdded);\n}\n\n/**\n * Outdents selected lines to the left by 2 spaces\n *\n * @param {Object} textArea - the targeted text area\n */\nfunction outdentLines($textArea) {\n const textArea = $textArea.get(0);\n const { lines, selectionStart, selectionEnd, startPos, endPos } = linesFromSelection(textArea);\n const shiftedLines = [];\n let totalRemoved = 0;\n let removedFromFirstline = -1;\n let removedFromLine = 0;\n\n textArea.focus();\n textArea.setSelectionRange(startPos, endPos);\n\n lines.forEach((line) => {\n removedFromLine = 0;\n\n if (line.length > 0) {\n // need to count how many spaces are actually removed, so can't use `replace`\n while (removedFromLine < INDENT_LENGTH && line[removedFromLine] === INDENT_CHAR) {\n removedFromLine += 1;\n }\n\n if (removedFromLine > 0) {\n line = line.slice(removedFromLine);\n totalRemoved += removedFromLine;\n }\n }\n\n if (removedFromFirstline === -1) removedFromFirstline = removedFromLine;\n shiftedLines.push(line);\n });\n\n const textToInsert = shiftedLines.join('\\n');\n\n if (totalRemoved > 0) insertText(textArea, textToInsert);\n\n setNewSelectionRange(\n textArea,\n selectionStart,\n selectionEnd,\n startPos,\n -removedFromFirstline,\n -totalRemoved,\n );\n}\n\n/* eslint-disable @gitlab/require-i18n-strings */\nfunction handleSurroundSelectedText(e, textArea) {\n if (!gon.markdown_surround_selection) return;\n if (e.metaKey || e.ctrlKey) return;\n if (textArea.selectionStart === textArea.selectionEnd) return;\n\n const keys = {\n '*': '**{text}**', // wraps with bold character\n _: '_{text}_', // wraps with italic character\n '`': '`{text}`', // wraps with inline character\n \"'\": \"'{text}'\", // single quotes\n '\"': '\"{text}\"', // double quotes\n '[': '[{text}]', // brackets\n '{': '{{text}}', // braces\n '(': '({text})', // parentheses\n '<': '<{text}>', // angle brackets\n };\n const tag = keys[e.key];\n\n if (tag) {\n e.preventDefault();\n\n updateText({\n tag,\n textArea,\n blockTag: '',\n wrap: true,\n select: '',\n tagContent: '',\n });\n }\n}\n/* eslint-enable @gitlab/require-i18n-strings */\n\n/**\n * Returns the content for a new line following a list item.\n *\n * @param {Object} listLineMatch - regex match of the current line\n * @param {Object?} nextLineMatch - regex match of the next line\n * @returns string with the new list item\n */\nfunction continueOlText(listLineMatch, nextLineMatch) {\n const { indent, leader } = listLineMatch.groups;\n const { indent: nextIndent, isOl: nextIsOl } = nextLineMatch?.groups ?? {};\n\n const [numStr, postfix = ''] = leader.split('.');\n\n const incrementBy = nextIsOl && nextIndent === indent ? 0 : 1;\n const num = parseInt(numStr, 10) + incrementBy;\n\n return `${indent}${num}.${postfix}`;\n}\n\nfunction handleContinueList(e, textArea) {\n if (!gon.markdown_automatic_lists) return;\n if (!(e.key === 'Enter')) return;\n if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;\n if (textArea.selectionStart !== textArea.selectionEnd) return;\n\n // prevent unintended line breaks inserted using Japanese IME on MacOS\n if (compositioningNoteText) return;\n\n const selectedLines = linesFromSelection(textArea);\n const firstSelectedLine = selectedLines.lines[0];\n const listLineMatch = firstSelectedLine.match(LIST_LINE_HEAD_PATTERN);\n\n if (listLineMatch) {\n const { leader, indent, content, isOl } = listLineMatch.groups;\n const emptyListItem = !content;\n const prefixLength = leader.length + indent.length;\n\n if (selectedLines.selectionStart - selectedLines.startPos < prefixLength) {\n // cursor in the indent/leader area, allow the natural line feed to be added\n return;\n }\n\n if (emptyListItem) {\n // erase empty list item - select the text and allow the\n // natural line feed to erase the text\n textArea.selectionStart = textArea.selectionStart - listLineMatch[0].length;\n return;\n }\n\n let itemToInsert;\n\n // Behaviors specific to either `ol` or `ul`\n if (isOl) {\n const nextLine = lineAfterSelection(textArea.value, textArea);\n const nextLineMatch = nextLine.match(LIST_LINE_HEAD_PATTERN);\n\n itemToInsert = continueOlText(listLineMatch, nextLineMatch);\n } else {\n if (firstSelectedLine.match(HR_PATTERN)) return;\n\n itemToInsert = `${indent}${leader}`;\n }\n\n itemToInsert = itemToInsert.replace(/\\[[x~]\\]/i, '[ ]');\n\n e.preventDefault();\n\n updateText({\n tag: itemToInsert,\n textArea,\n blockTag: '',\n wrap: false,\n select: '',\n tagContent: '',\n });\n }\n}\n\nexport function keypressNoteText(e) {\n const textArea = this;\n\n if ($(textArea).atwho?.('isSelecting')) return;\n\n handleContinueList(e, textArea);\n handleSurroundSelectedText(e, textArea);\n}\n\nexport function compositionStartNoteText() {\n compositioningNoteText = true;\n}\n\nexport function compositionEndNoteText() {\n compositioningNoteText = false;\n}\n\nexport function updateTextForToolbarBtn($toolbarBtn) {\n const $textArea = $toolbarBtn.closest('.md-area').find('textarea');\n if (!$textArea.length) return;\n\n switch ($toolbarBtn.data('mdCommand')) {\n case 'indentLines':\n indentLines($textArea);\n break;\n case 'outdentLines':\n outdentLines($textArea);\n break;\n default:\n return updateText({\n textArea: $textArea,\n tag: $toolbarBtn.data('mdTag'),\n cursorOffset: $toolbarBtn.data('mdCursorOffset'),\n blockTag: $toolbarBtn.data('mdBlock'),\n wrap: !$toolbarBtn.data('mdPrepend'),\n select: $toolbarBtn.data('mdSelect'),\n tagContent: $toolbarBtn.attr('data-md-tag-content'),\n });\n }\n}\n\nexport function addMarkdownListeners(form) {\n $('.markdown-area', form)\n .on('keydown', keypressNoteText)\n .on('compositionstart', compositionStartNoteText)\n .on('compositionend', compositionEndNoteText)\n .each(function attachTextareaShortcutHandlers() {\n Shortcuts.initMarkdownEditorShortcuts($(this), updateTextForToolbarBtn);\n });\n\n const $allToolbarBtns = $(form)\n .off('click', '.js-md')\n .on('click', '.js-md', function () {\n const $toolbarBtn = $(this);\n\n return updateTextForToolbarBtn($toolbarBtn);\n });\n\n return $allToolbarBtns;\n}\n\nexport function addEditorMarkdownListeners(editor) {\n // eslint-disable-next-line @gitlab/no-global-event-off\n $('.js-md')\n .off('click')\n .on('click', (e) => {\n const { mdTag, mdBlock, mdPrepend, mdSelect } = $(e.currentTarget).data();\n\n insertMarkdownText({\n tag: mdTag,\n blockTag: mdBlock,\n wrap: !mdPrepend,\n select: mdSelect,\n selected: editor.getSelectedText(),\n text: editor.getValue(),\n editor,\n });\n editor.focus();\n });\n}\n\nexport function removeMarkdownListeners(form) {\n $('.markdown-area', form)\n .off('keydown', keypressNoteText)\n .off('compositionstart', compositionStartNoteText)\n .off('compositionend', compositionEndNoteText)\n .each(function removeTextareaShortcutHandlers() {\n Shortcuts.removeMarkdownEditorShortcuts($(this));\n });\n\n // eslint-disable-next-line @gitlab/no-global-event-off\n return $('.js-md', form).off('click');\n}\n\n/**\n * If the textarea cursor is positioned in a Markdown image declaration,\n * it uses the Markdown API to resolve the image’s absolute URL.\n * @param {Object} textarea Textarea DOM element\n * @param {String} markdownPreviewPath Markdown API path\n * @returns {Object} an object containing the image’s absolute URL, filename,\n * and the markdown declaration. If the textarea cursor is not positioned\n * in an image, it returns null.\n */\nexport const resolveSelectedImage = async (textArea, markdownPreviewPath = '') => {\n const { lines, startPos } = linesFromSelection(textArea);\n\n // image declarations can’t span more than one line in Markdown\n if (lines > 0) {\n return null;\n }\n\n const selectedLine = lines[0];\n\n if (!/!\\[.+?\\]\\(.+?\\)/.test(selectedLine)) return null;\n\n const lineSelectionStart = textArea.selectionStart - startPos;\n const preExlm = selectedLine.substring(0, lineSelectionStart).lastIndexOf('!');\n const postClose = selectedLine.substring(lineSelectionStart).indexOf(')');\n\n if (preExlm >= 0 && postClose >= 0) {\n const imageMarkdown = selectedLine.substring(preExlm, lineSelectionStart + postClose + 1);\n const { data } = await axios.post(markdownPreviewPath, { text: imageMarkdown });\n const parser = new DOMParser();\n\n const dom = parser.parseFromString(data.body, 'text/html');\n const imageURL = dom.body.querySelector('a').getAttribute('href');\n\n if (imageURL) {\n const filename = imageURL.substring(imageURL.lastIndexOf('/') + 1);\n\n return {\n imageMarkdown,\n imageURL,\n filename,\n };\n }\n }\n\n return null;\n};\n","import $ from 'jquery';\nimport { flatten } from 'lodash';\nimport Vue from 'vue';\nimport { Mousetrap, addStopCallback } from '~/lib/mousetrap';\nimport { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';\n\nimport findAndFollowLink from '~/lib/utils/navigation_utility';\nimport { refreshCurrentPage, visitUrl } from '~/lib/utils/url_utility';\nimport {\n keysFor,\n TOGGLE_KEYBOARD_SHORTCUTS_DIALOG,\n START_SEARCH,\n FOCUS_FILTER_BAR,\n TOGGLE_PERFORMANCE_BAR,\n HIDE_APPEARING_CONTENT,\n TOGGLE_CANARY,\n TOGGLE_MARKDOWN_PREVIEW,\n GO_TO_YOUR_TODO_LIST,\n GO_TO_ACTIVITY_FEED,\n GO_TO_YOUR_ISSUES,\n GO_TO_YOUR_MERGE_REQUESTS,\n GO_TO_YOUR_PROJECTS,\n GO_TO_YOUR_GROUPS,\n GO_TO_MILESTONE_LIST,\n GO_TO_YOUR_SNIPPETS,\n GO_TO_PROJECT_FIND_FILE,\n GO_TO_YOUR_REVIEW_REQUESTS,\n} from './keybindings';\nimport { disableShortcuts, shouldDisableShortcuts } from './shortcuts_toggle';\n\n/**\n * The key used to save and fetch the local Mousetrap instance\n * attached to a `